From: Carlos Maniero <carlos@maniero.me>
To: ~johnnyrichard/olang-devel@lists.sr.ht
Cc: Carlos Maniero <carlos@maniero.me>
Subject: [PATCH olang v1] docs: add code highlight post processor
Date: Fri, 08 Nov 2024 04:24:16 +0000 (UTC) [thread overview]
Message-ID: <20241108042411.105478-1-carlos@maniero.me> (raw)
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>".*?")', '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
next reply other threads:[~2024-11-08 4:24 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-08 4:24 Carlos Maniero [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241108042411.105478-1-carlos@maniero.me \
--to=carlos@maniero.me \
--cc=~johnnyrichard/olang-devel@lists.sr.ht \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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