public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
* [PATCH olang v1] docs: add code highlight post processor
@ 2024-11-08  4:24 Carlos Maniero
  2024-11-08  4:24 ` [olang/patches/.build.yml] build success builds.sr.ht
  2024-11-13  1:40 ` [PATCH olang v1] docs: add code highlight post processor Johnny Richard
  0 siblings, 2 replies; 3+ messages in thread
From: Carlos Maniero @ 2024-11-08  4:24 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

This a very simple token based code highlighter that is not able to
evaluate syntax.

How it works:

The @sethl inserts a html comment at generated html. The generated html
file is than post processed by the script which highlights the code.

The alternative is to use the texi2any *HIGHLIGHT_SYNTAX* [1] experimental
feature, which would require the inclusion of other dependency to the
project.

[1]: https://www.gnu.org/software/texinfo/manual/texinfo/html_node/Syntax-Highlighting.html

Signed-off-by: Carlos Maniero <carlos@maniero.me>
---
 docs/info/Makefile             |   1 +
 docs/info/_ext.texi            |  15 +++++
 docs/info/c-ffi.texi           |  17 +++++-
 docs/info/codehl.py            | 104 +++++++++++++++++++++++++++++++++
 docs/info/getting-started.texi |  32 +++++++++-
 docs/info/specification.texi   |   3 +
 docs/style.css                 |  92 ++++++++++++++++++++++++++---
 7 files changed, 250 insertions(+), 14 deletions(-)
 create mode 100644 docs/info/_ext.texi
 create mode 100644 docs/info/codehl.py

diff --git a/docs/info/Makefile b/docs/info/Makefile
index b2d29a4..12cb790 100644
--- a/docs/info/Makefile
+++ b/docs/info/Makefile
@@ -6,6 +6,7 @@ all: html
 
 html: olang.texi introduction.texi installation.texi getting-started.texi specification.texi contribution-guide.texi
 	$(MAKEINFO) --set-customization-variable AFTER_BODY_OPEN="$(HTML_HEADER)" --css-include=../style.css -o html --html olang.texi
+	find html -name '*.html' | xargs python3 codehl.py
 
 .PHONY: clean
 clean:
diff --git a/docs/info/_ext.texi b/docs/info/_ext.texi
new file mode 100644
index 0000000..2a0d6e7
--- /dev/null
+++ b/docs/info/_ext.texi
@@ -0,0 +1,15 @@
+@ifclear olc_info_ext
+@macro sethl{lang}
+@html
+<!--syntax:\lang\-->
+@end html
+@end macro
+
+@macro sethl-{lang}
+@html
+<!--syntax:\lang\ no-numbers-->
+@end html
+@end macro
+@end ifclear
+
+@set olc_info_ext
diff --git a/docs/info/c-ffi.texi b/docs/info/c-ffi.texi
index 719fcd5..12ba9d0 100644
--- a/docs/info/c-ffi.texi
+++ b/docs/info/c-ffi.texi
@@ -1,3 +1,5 @@
+@include _ext.texi
+
 @node C FFI
 @chapter C FFI
 
@@ -13,6 +15,7 @@ To call external code you can use the @code{extern} statement.
 
 @subsection extern
 
+@sethl olang
 @verbatim
 # file: answer.ol
 
@@ -28,6 +31,7 @@ fn main(): u8 {
 That way instead of defining the @code{u32print} function. It must be provided
 at the linkage step.
 
+@sethl c
 @verbatim
 // file: u32print.c
 
@@ -40,10 +44,11 @@ int u32print(int number) {
 
 @subsection Compiling without linking
 
-If you try to compile the answer.ol file you will receive the follow error:
+If you try to compile the answer.ol file by using the
+@code{olc answer.ol -o answer.o} command you will receive the follow error:
 
+@sethl- output
 @verbatim
-olc answer.ol -o answer.o
 /usr/bin/ld: answer.o.o: in function `main':
 (.text+0x10): undefined reference to `u32print'
 collect2: error: ld returned 1 exit status
@@ -52,6 +57,7 @@ collect2: error: ld returned 1 exit status
 That's because @code{O} tries to link by default. To assemble the code without
 linking it, you can use the @code{-c} option.
 
+@sethl- bash
 @verbatim
 olc answer.ol -c -o answer.o
 @end verbatim
@@ -59,12 +65,14 @@ olc answer.ol -c -o answer.o
 After that you can do the same with the C file that contains the function that
 you are looking to call.
 
+@sethl- bash
 @verbatim
 gcc u32print.c -c -o u32print.o
 @end verbatim
 
 And then you can link both object files into an executable:
 
+@sethl- bash
 @verbatim
 gcc answer.o u32print.o -o answer
 @end verbatim
@@ -73,6 +81,7 @@ gcc answer.o u32print.o -o answer
 
 All that is required is to set the function prototype.
 
+@sethl olang
 @verbatim
 # file: sum.ol
 
@@ -81,8 +90,9 @@ fn sum(a: u32, b: u32): u32 {
 }
 @end verbatim
 
+@sethl c
 @verbatim
-# file: csum.c
+// file: csum.c
 
 #include <stdio.h>
 
@@ -96,6 +106,7 @@ int main() {
 
 Compiling:
 
+@sethl- bash
 @verbatim
 olc sum.ol -c -o sum.o
 gcc sum.o csum.c -o csum
diff --git a/docs/info/codehl.py b/docs/info/codehl.py
new file mode 100644
index 0000000..0749138
--- /dev/null
+++ b/docs/info/codehl.py
@@ -0,0 +1,104 @@
+# Copyright (C) 2024 Carlos Maniero<carlos@maniero.me>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+import sys
+import re
+
+re_hl_block = r'<!--syntax:(?P<lang>\w+)( (?P<class>.*?))?-->.*?<pre class="verbatim">(?P<code>.*?)<\/pre>'
+
+lexers = {
+    'default': [
+        (r'^(?P<value> +)', None),
+        (r'^(?P<value>\d+)', 'num'),
+        (r'^(?P<value>\w+)', 'ident'),
+        (r'^(?P<value>\(|\)|{|})', 'brac'),
+        (r'^(?P<value>&\w+;|\^|\~|!|@|\#|\$|%|&|\*|-|\+|\.|=|,|:|;|\||\\|/|\?)', 'symbol'),
+        (r'^(?P<value>.+)', None),
+    ],
+    'olang': [
+        (r'^(?P<value>#.*)', 'comment'),
+        (r'^(?P<value>\w+) *?\(', 'fn-name'),
+        (r'^(?P<value>fn|if|else|return|while|var|const|extern)', 'key'),
+        (r'^\b(?P<value>u8|u16|u32|u64)\b', 'type'),
+    ],
+    'c': [
+        (r'^(?P<value>#.*)', 'macro'),
+        (r'^(?P<value>&quot;.*?&quot;)', 'str'),
+        (r'^(?P<value>//.*)', 'comment'),
+        (r'^(?P<value>\w+) *?\(', 'fn-name'),
+        (r'^(?P<value>fn|if|else|return|while|var|const|extern)', 'key'),
+        (r'^\b(?P<value>int|long|float)\b', 'type'),
+    ],
+    'bash': [
+        (r'^(?P<value>-+.+? ?)', 'opt'),
+        (r'^(?P<value>[A-z0\d\.-/]+)', 'ident'),
+    ],
+    'output': [
+        (r'(?P<value>.*)', None),
+    ],
+    'ebnf': [
+        (r'^(?P<value>.+?::=)', 'fn-name'),
+        (r'^(?P<value>\|)', 'fn-name'),
+        (r'^(?P<value>\?|\*)', 'key'),
+        (r'^(?P<value>\(\*.*?\*\))', 'comment'),
+        (r'^(?P<value>\'.*?\')', 'str'),
+    ]
+}
+
+def format_code_line(line, lang):
+    new_line = ''
+
+    lexer = lexers.get(lang, []) + lexers['default']
+
+    while line != '':
+        for (regex, name) in lexer:
+            match = re.match(regex, line)
+            if match:
+                value = match.group('value')
+                line = line[len(value):]
+                if name:
+                    new_line += f'<span class="code-{name}">{value}</span>'
+                else:
+                    new_line += value
+                break
+
+
+    return f'<span class="code-line">{new_line}</span>'
+
+def format_pre(match):
+    lang = match.group('lang')
+    css_class = match.group('class')
+    css_classes = f'code-hl lang-{lang} {css_class or ""}'.strip()
+    raw_lines = match.group('code').split('\n')
+
+    while raw_lines[-1].strip() == '':
+        raw_lines = raw_lines[:-1]
+
+    code = "\n".join([format_code_line(line, lang) for line in raw_lines])
+
+    return f'<pre class="{css_classes}">{code}</pre>'
+
+def codehl(code):
+    return re.sub(re_hl_block, format_pre, code, flags=re.DOTALL)
+
+if __name__ == '__main__':
+    for file_name in sys.argv[1:]:
+        print(f"HL\t{file_name}")
+
+        with open(file_name, 'r+') as file:
+            content = codehl(file.read())
+
+            file.seek(0)
+            file.write(content)
+            file.truncate()
diff --git a/docs/info/getting-started.texi b/docs/info/getting-started.texi
index 77b9298..75c00f0 100644
--- a/docs/info/getting-started.texi
+++ b/docs/info/getting-started.texi
@@ -1,3 +1,5 @@
+@include _ext.texi
+
 @node Getting Started
 @chapter Getting Started
 
@@ -15,6 +17,7 @@ much the same with some small quirks. Let's dive in!
 An O programming language program starts with a @code{main} function. This
 function must return the program exit code.
 
+@sethl olang
 @verbatim
 fn main(): u8 {
   return 0
@@ -23,9 +26,10 @@ fn main(): u8 {
 
 To compile the program you can use @code{olc}.
 
+@sethl- bash
 @verbatim
-$ olc my_prog.ol -o my_prog
-$ ./my_prog
+olc my_prog.ol -o my_prog
+./my_prog
 @end verbatim
 
 @section Functions
@@ -34,6 +38,7 @@ Unlike C, O language does not require function prototypes. This means you can
 call a function before it's defined, making your code more flexible and easier
 to read in many cases.
 
+@sethl olang
 @verbatim
 fn main(): u8 {
   return fib(8)
@@ -56,12 +61,14 @@ fn fib(n: u32): u32 {
 
 Comments starts with a @code{#}.
 
+@sethl- olang
 @verbatim
 # Hi I'm a comment and I'll be ignored by the compiler.
 @end verbatim
 
 @section Variables
 
+@sethl- olang
 @verbatim
 var answer: u32 = 42
 @end verbatim
@@ -72,6 +79,7 @@ Any non zero expr is true.
 
 @subsection If-Else
 
+@sethl olang
 @verbatim
 if expr {
   # statement
@@ -84,6 +92,7 @@ if expr {
 
 While loop
 
+@sethl olang
 @verbatim
 while expr {
   # statement
@@ -92,6 +101,7 @@ while expr {
 
 @subsection While loop
 
+@sethl olang
 @verbatim
 while expr {
   # statement
@@ -128,6 +138,7 @@ Unsigned 64 bits.
 
 @item Equals
 
+@sethl- olang
 @verbatim
 expr1 == expr2
 @end verbatim
@@ -136,6 +147,7 @@ Results zero (false) or one (true).
 
 @item Less
 
+@sethl- olang
 @verbatim
 expr1 < expr2
 @end verbatim
@@ -144,6 +156,7 @@ Results zero (false) or one (true).
 
 @item Less Equal
 
+@sethl- olang
 @verbatim
 expr1 <= expr2
 @end verbatim
@@ -152,6 +165,7 @@ Results zero (false) or one (true).
 
 @item Greater
 
+@sethl- olang
 @verbatim
 expr1 > expr2
 @end verbatim
@@ -160,6 +174,7 @@ Results zero (false) or one (true).
 
 @item Greater Equal
 
+@sethl- olang
 @verbatim
 expr1 >= expr2
 @end verbatim
@@ -168,6 +183,7 @@ Results zero (false) or one (true).
 
 @item Or
 
+@sethl- olang
 @verbatim
 expr1 || expr2
 @end verbatim
@@ -176,6 +192,7 @@ Results zero (false) if both are true or one (true) if any is true.
 
 @item And
 
+@sethl- olang
 @verbatim
 expr1 && expr2
 @end verbatim
@@ -190,24 +207,28 @@ Results zero (false) if any is false or one (true) if both are true.
 
 @item Shift left
 
+@sethl- olang
 @verbatim
 n << bits
 @end verbatim
 
 @item Shift left
 
+@sethl- olang
 @verbatim
 n >> bits
 @end verbatim
 
 @item And
 
+@sethl- olang
 @verbatim
 n & bits
 @end verbatim
 
 @item Or
 
+@sethl- olang
 @verbatim
 n | bits
 @end verbatim
@@ -220,30 +241,35 @@ n | bits
 
 @item Addition
 
+@sethl- olang
 @verbatim
 expr1 + expr2
 @end verbatim
 
 @item Subtraction
 
+@sethl- olang
 @verbatim
 expr1 - expr2
 @end verbatim
 
 @item Multiplication
 
+@sethl- olang
 @verbatim
 expr1 * expr2
 @end verbatim
 
 @item Division
 
+@sethl- olang
 @verbatim
 expr1 / expr2
 @end verbatim
 
 @item Remaining
 
+@sethl- olang
 @verbatim
 expr1 % expr2
 @end verbatim
@@ -258,6 +284,7 @@ Dealing with memory address.
 
 Get the address of a variable.
 
+@sethl olang
 @verbatim
 var my_var: u32 = 0
 
@@ -268,6 +295,7 @@ var my_pointer: u32* = &my_var
 
 Accessing the value of the address a pointer points to.
 
+@sethl olang
 @verbatim
 var my_var: u32 = 0
 
diff --git a/docs/info/specification.texi b/docs/info/specification.texi
index 707d932..47dad9a 100644
--- a/docs/info/specification.texi
+++ b/docs/info/specification.texi
@@ -1,3 +1,5 @@
+@include _ext.texi
+
 @node Language Specification
 @chapter Specification
 
@@ -19,4 +21,5 @@ This is the O Programming Language EBNF grammar specification[^1]
 NOTE: This grammar spec is a DRAFT and it covers only a small portion of the
 language.
 
+@sethl ebnf
 @verbatiminclude olang.ebnf
diff --git a/docs/style.css b/docs/style.css
index 9ee71e3..0a50254 100644
--- a/docs/style.css
+++ b/docs/style.css
@@ -44,10 +44,6 @@ dd {
   margin-left: 4ch;
 }
 
-pre {
-  margin-bottom: 1rem;
-}
-
 p {
   padding-bottom: 1ch;
 }
@@ -109,12 +105,90 @@ footer {
 }
 
 pre {
-  background: gray;
-  color: black;
-  padding: 2ch;
-  font-weight: bold;
-  max-width: 100%;
+  margin-bottom: 1ch;
+  max-width: calc(100vw - 7ch);
+  width: calc(100vw - 7ch);
   overflow: auto;
+  position: relative;
+  counter-reset: line;
+  background: black;
+  color: white;
+  border-left: 1ch solid grey;
+  padding: 2ch 1ch;
+}
+
+dd pre {
+  max-width: calc(100vw - 11ch);
+  width: calc(100vw - 11ch);
+}
+
+pre:before, pre:after {
+  content: "";
+  background: grey;
+  position: absolute;
+  left: 0ch;
+  width: 1ch;
+  height: 1ch;
+}
+
+pre:before {
+  top: 0ch;
+}
+pre:after {
+  bottom: 0ch;
+}
+
+.code-line {
+  counter-increment: line;
+}
+
+.code-line:before {
+  content: "" counter(line, decimal-leading-zero) " ";
+  color: grey;
+}
+
+.no-numbers .code-line:before {
+  content: ""
+}
+
+.code-key {
+  color: yellow;
+}
+
+.code-fn-name {
+  color: aqua;
+}
+
+.code-symbol,.code-brac {
+  color: silver;
+}
+
+.code-num {
+  color: orange;
+}
+
+.code-type {
+  color: lime;
+}
+
+.code-comment {
+  color: grey;
+}
+
+.code-macro {
+  color: orange;
+}
+
+.code-str {
+  color: lime;
+}
+
+.lang-output {
+  color: grey;
+}
+
+.lang-bash .code-opt {
+  color: silver;
 }
 
 .logo-name {
-- 
2.46.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-11-12 23:41 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-08  4:24 [PATCH olang v1] docs: add code highlight post processor Carlos Maniero
2024-11-08  4:24 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-11-13  1:40 ` [PATCH olang v1] docs: add code highlight post processor Johnny Richard

Code repositories for project(s) associated with this public inbox

	https://git.johnnyrichard.com/olang.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox