diff --git a/birdie_snapshots/highlight_arithmetic_ansi.accepted b/birdie_snapshots/highlight_arithmetic_ansi.accepted
new file mode 100644
index 0000000..fc9dab2
--- /dev/null
+++ b/birdie_snapshots/highlight_arithmetic_ansi.accepted
@@ -0,0 +1,17 @@
+---
+version: 1.2.6
+title: highlight_arithmetic_ansi
+---
+
+let x = 1 + 2 / 3.5e10;
+let y = 0n * 0xff8n ** x;
+x <= y === false;
+
+
+---
+
+[0m
+[0m[33mlet[39m[0m [0m[0mx[0m[0m [0m[35m=[39m[0m [0m[32m1[39m[0m [0m[35m+[39m[0m [0m[32m2[39m[0m [0m[35m/[39m[0m [0m[32m3.5e10[39m[0m;[0m[0m
+[0m[33mlet[39m[0m [0m[0my[0m[0m [0m[35m=[39m[0m [0m[32m0n[39m[0m [0m[35m*[39m[0m [0m[32m0xff8n[39m[0m [0m[35m**[39m[0m [0m[0mx[0m[0m;[0m[0m
+[0m[0mx[0m[0m [0m[35m<=[39m[0m [0m[0my[0m[0m [0m[35m===[39m[0m [0m[33mfalse[39m[0m;[0m[0m
+[0m
\ No newline at end of file
diff --git a/birdie_snapshots/highlight_arithmetic_html.accepted b/birdie_snapshots/highlight_arithmetic_html.accepted
new file mode 100644
index 0000000..27588da
--- /dev/null
+++ b/birdie_snapshots/highlight_arithmetic_html.accepted
@@ -0,0 +1,16 @@
+---
+version: 1.2.6
+title: highlight_arithmetic_html
+---
+
+let x = 1 + 2 / 3.5e10;
+let y = 0n * 0xff8n ** x;
+x <= y === false;
+
+
+---
+
+
+let x = 1 + 2 / 3.5e10;
+let y = 0n * 0xff8n ** x;
+x <= y === false;
diff --git a/birdie_snapshots/highlight_basic_program_ansi.accepted b/birdie_snapshots/highlight_basic_program_ansi.accepted
new file mode 100644
index 0000000..14db5e4
--- /dev/null
+++ b/birdie_snapshots/highlight_basic_program_ansi.accepted
@@ -0,0 +1,23 @@
+---
+version: 1.2.6
+title: highlight_basic_program_ansi
+---
+
+export function main() {
+ const message = 'Hello, world!';
+ console.log(message);
+}
+
+main();
+
+
+---
+
+[0m
+[0m[33mexport[39m[0m [0m[33mfunction[39m[0m [0m[34mmain[39m[0m([0m[0m)[0m[0m [0m[0m{[0m[0m
+[0m[0m [0m[33mconst[39m[0m [0m[0mmessage[0m[0m [0m[35m=[39m[0m [0m[32m'Hello, world!'[39m[0m;[0m[0m
+[0m[0m [0m[0mconsole[0m[0m.[0m[34mlog[39m[0m([0m[0mmessage[0m[0m)[0m[0m;[0m[0m
+[0m[0m}[0m[0m
+[0m[0m
+[0m[34mmain[39m[0m([0m[0m)[0m[0m;[0m[0m
+[0m
\ No newline at end of file
diff --git a/birdie_snapshots/highlight_basic_program_html.accepted b/birdie_snapshots/highlight_basic_program_html.accepted
new file mode 100644
index 0000000..0eb99a1
--- /dev/null
+++ b/birdie_snapshots/highlight_basic_program_html.accepted
@@ -0,0 +1,22 @@
+---
+version: 1.2.6
+title: highlight_basic_program_html
+---
+
+export function main() {
+ const message = 'Hello, world!';
+ console.log(message);
+}
+
+main();
+
+
+---
+
+
+export function main() {
+ const message = 'Hello, world!';
+ console.log(message);
+}
+
+main();
diff --git a/birdie_snapshots/highlight_class_ansi.accepted b/birdie_snapshots/highlight_class_ansi.accepted
new file mode 100644
index 0000000..fdcee74
--- /dev/null
+++ b/birdie_snapshots/highlight_class_ansi.accepted
@@ -0,0 +1,27 @@
+---
+version: 1.2.6
+title: highlight_class_ansi
+---
+
+class RegexWrapper {
+ constructor(r) {
+ this.r = r;
+ }
+}
+
+const rw = new RegexWrapper(/hello [regex]?/);
+console.log(rw instanceof RegexWrapper);
+
+
+---
+
+[0m
+[0m[33mclass[39m[0m [0m[36mRegexWrapper[39m[0m [0m[0m{[0m[0m
+[0m[0m [0m[34mconstructor[39m[0m([0m[0mr[0m[0m)[0m[0m [0m[0m{[0m[0m
+[0m[0m [0m[33mthis[39m[0m.[0m[0mr[0m[0m [0m[35m=[39m[0m [0m[0mr[0m[0m;[0m[0m
+[0m[0m [0m[0m}[0m[0m
+[0m[0m}[0m[0m
+[0m[0m
+[0m[33mconst[39m[0m [0m[0mrw[0m[0m [0m[35m=[39m[0m [0m[33mnew[39m[0m [0m[36mRegexWrapper[39m[0m([0m[32m/hello [regex]?/[39m[0m)[0m[0m;[0m[0m
+[0m[0mconsole[0m[0m.[0m[34mlog[39m[0m([0m[0mrw[0m[0m [0m[33minstanceof[39m[0m [0m[36mRegexWrapper[39m[0m)[0m[0m;[0m[0m
+[0m
\ No newline at end of file
diff --git a/birdie_snapshots/highlight_comments_ansi.accepted b/birdie_snapshots/highlight_comments_ansi.accepted
new file mode 100644
index 0000000..824f2ee
--- /dev/null
+++ b/birdie_snapshots/highlight_comments_ansi.accepted
@@ -0,0 +1,25 @@
+---
+version: 1.2.6
+title: highlight_comments_ansi
+---
+#! shebang!
+// This is some kind of comment
+console.log("Hi");
+/*
+Another comment
+that spans several lines
+*/
+let x = /* this on is inline! */ 10;
+
+
+---
+
+[3m[90m#! shebang![39m[23m[0m
+[0m[3m[90m// This is some kind of comment[39m[23m[0m
+[0m[0mconsole[0m[0m.[0m[34mlog[39m[0m([0m[32m"Hi"[39m[0m)[0m[0m;[0m[0m
+[0m[3m[90m/*
+Another comment
+that spans several lines
+*/[39m[23m[0m
+[0m[33mlet[39m[0m [0m[0mx[0m[0m [0m[35m=[39m[0m [0m[3m[90m/* this on is inline! */[39m[23m[0m [0m[32m10[39m[0m;[0m[0m
+[0m
\ No newline at end of file
diff --git a/birdie_snapshots/highlight_errors_ansi.accepted b/birdie_snapshots/highlight_errors_ansi.accepted
new file mode 100644
index 0000000..582e918
--- /dev/null
+++ b/birdie_snapshots/highlight_errors_ansi.accepted
@@ -0,0 +1,23 @@
+---
+version: 1.2.6
+title: highlight_errors_ansi
+---
+
+let unknown = @;
+let ustring = 'This string does not finish
+let uregex = /uh oh
+let badNumber = 0xabcdefg;
+/*
+This comment spans the rest of the program.
+
+
+---
+
+[0m
+[0m[33mlet[39m[0m [0m[0munknown[0m[0m [0m[35m=[39m[0m [0m[0m@[0m[0m;[0m[0m
+[0m[33mlet[39m[0m [0m[0mustring[0m[0m [0m[35m=[39m[0m [0m[32m'This string does not finish[39m[0m
+[0m[33mlet[39m[0m [0m[0muregex[0m[0m [0m[35m=[39m[0m [0m[32m/uh oh[39m[0m
+[0m[33mlet[39m[0m [0m[0mbadNumber[0m[0m [0m[35m=[39m[0m [0m[32m0xabcdef[39m[0mg[0m[0m;[0m[0m
+[0m[3m[90m/*
+This comment spans the rest of the program.
+[39m[23m
\ No newline at end of file
diff --git a/gleam.toml b/gleam.toml
index 2dc2145..d12d93e 100644
--- a/gleam.toml
+++ b/gleam.toml
@@ -20,3 +20,4 @@ houdini = ">= 1.1.0 and < 2.0.0"
[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
simplifile = ">= 2.2.1 and < 3.0.0"
+birdie = ">= 1.2.6 and < 2.0.0"
diff --git a/manifest.toml b/manifest.toml
index ddaaab2..ed314b5 100644
--- a/manifest.toml
+++ b/manifest.toml
@@ -2,18 +2,29 @@
# You typically do not need to edit this file
packages = [
+ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
+ { name = "birdie", version = "1.2.6", build_tools = ["gleam"], requirements = ["argv", "edit_distance", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "term_size", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "1363F4C7E7433A4A8350CC682BCDDBA5BBC6F66C94EFC63BC43025F796C4F6D0" },
+ { name = "edit_distance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "edit_distance", source = "hex", outer_checksum = "A1E485C69A70210223E46E63985FA1008B8B2DDA9848B7897469171B29020C05" },
{ name = "filepath", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "65F51013BCF78A603AFFD7992EF1CC6ECA96C74038EB48887F656DE44DBC1902" },
+ { name = "glance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "106111453AE9BA959184302B7DADF2E8CF322B27A7CB68EE78F3EE43FEACCE2C" },
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
+ { name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
{ name = "gleam_stdlib", version = "0.58.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "091F2D2C4A3A4E2047986C47E2C2C9D728A4E068ABB31FDA17B0D347E6248467" },
{ name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" },
+ { name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
{ name = "houdini", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "houdini", source = "hex", outer_checksum = "5BA517E5179F132F0471CB314F27FE210A10407387DA1EA4F6FD084F74469FC2" },
+ { name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
+ { name = "rank", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "rank", source = "hex", outer_checksum = "5660E361F0E49CBB714CC57CC4C89C63415D8986F05B2DA0C719D5642FAD91C9" },
{ name = "simplifile", version = "2.2.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C88E0EE2D509F6D86EB55161D631657675AA7684DAB83822F7E59EB93D9A60E3" },
+ { name = "term_size", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "term_size", source = "hex", outer_checksum = "D00BD2BC8FB3EBB7E6AE076F3F1FF2AC9D5ED1805F004D0896C784D06C6645F1" },
+ { name = "trie_again", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "trie_again", source = "hex", outer_checksum = "5B19176F52B1BD98831B57FDC97BD1F88C8A403D6D8C63471407E78598E27184" },
]
[requirements]
+birdie = { version = ">= 1.2.6 and < 2.0.0" }
gleam_community_ansi = { version = ">= 1.4.3 and < 2.0.0" }
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
diff --git a/src/just.gleam b/src/just.gleam
index 2495f19..6c90bf3 100644
--- a/src/just.gleam
+++ b/src/just.gleam
@@ -396,7 +396,7 @@ fn lex_multiline_comment(lexer: Lexer, lexed: String) -> #(Lexer, Token) {
Error(_) ->
maybe_token(
error(lexer, UnterminatedComment),
- token.MultiLineComment(lexed),
+ token.UnterminatedComment(lexed),
!lexer.ignore_comments,
)
Ok(#(char, source)) ->
diff --git a/src/just/highlight.gleam b/src/just/highlight.gleam
index 5ac5322..1623a45 100644
--- a/src/just/highlight.gleam
+++ b/src/just/highlight.gleam
@@ -40,8 +40,8 @@ pub type Token {
///
/// If you wish to use other colours or another format, use `to_tokens`.
///
-pub fn to_ansi(code: String) -> String {
- to_tokens(code)
+pub fn ansi(code: String) -> String {
+ tokens(code)
|> list.fold("", fn(code, token) {
code
<> case token {
@@ -96,8 +96,8 @@ pub fn to_ansi(code: String) -> String {
///
/// If you wish to use another format see `to_ansi` or `to_tokens`.
///
-pub fn to_html(code: String) -> String {
- to_tokens(code)
+pub fn html(code: String) -> String {
+ tokens(code)
|> list.fold("", fn(acc, token) {
case token {
Whitespace(s) -> acc <> s
@@ -132,7 +132,7 @@ pub fn to_html(code: String) -> String {
///
/// To convert code into syntax tokens, see `just.tokenise`.
///
-pub fn to_tokens(code: String) -> List(Token) {
+pub fn tokens(code: String) -> List(Token) {
let lexer = just.new(code)
let #(tokens, _errors) = just.tokenise(lexer)
do_to_tokens(tokens, [])
@@ -340,14 +340,14 @@ fn do_to_tokens(in: List(t.Token), out: List(Token)) -> List(Token) {
[t.DoublePipeEqual, ..in] -> do_to_tokens(in, [Operator("||="), ..out])
[t.DoubleQuestionEqual, ..in] -> do_to_tokens(in, [Operator("??="), ..out])
- [t.Unknown(value), ..] -> do_to_tokens(in, [Other(value), ..out])
- [t.UnterminatedComment(value), ..] ->
+ [t.Unknown(value), ..in] -> do_to_tokens(in, [Other(value), ..out])
+ [t.UnterminatedComment(value), ..in] ->
do_to_tokens(in, [Comment("/*" <> value), ..out])
- [t.UnterminatedRegularExpression(value), ..] ->
+ [t.UnterminatedRegularExpression(value), ..in] ->
do_to_tokens(in, [Regexp("/" <> value), ..out])
- [t.UnterminatedString(quote:, contents:), ..] ->
+ [t.UnterminatedString(quote:, contents:), ..in] ->
do_to_tokens(in, [String(quote <> contents), ..out])
- [t.UnterminatedTemplate(contents), ..] ->
+ [t.UnterminatedTemplate(contents), ..in] ->
do_to_tokens(in, [String(contents), ..out])
}
}
diff --git a/test/just/highlight_test.gleam b/test/just/highlight_test.gleam
new file mode 100644
index 0000000..70a3b29
--- /dev/null
+++ b/test/just/highlight_test.gleam
@@ -0,0 +1,111 @@
+import birdie
+import just/highlight
+
+fn assert_ansi_highlight(title: String, src: String) -> Nil {
+ birdie.snap(
+ src <> "\n\n---\n\n" <> highlight.ansi(src),
+ "highlight_" <> title <> "_ansi",
+ )
+}
+
+fn assert_html_highlight(title: String, src: String) -> Nil {
+ birdie.snap(
+ src <> "\n\n---\n\n" <> highlight.html(src),
+ "highlight_" <> title <> "_html",
+ )
+}
+
+pub fn basic_program_test() {
+ assert_ansi_highlight(
+ "basic_program",
+ "
+export function main() {
+ const message = 'Hello, world!';
+ console.log(message);
+}
+
+main();
+",
+ )
+}
+
+pub fn basic_program_html_test() {
+ assert_html_highlight(
+ "basic_program",
+ "
+export function main() {
+ const message = 'Hello, world!';
+ console.log(message);
+}
+
+main();
+",
+ )
+}
+
+pub fn arithmetic_test() {
+ assert_ansi_highlight(
+ "arithmetic",
+ "
+let x = 1 + 2 / 3.5e10;
+let y = 0n * 0xff8n ** x;
+x <= y === false;
+",
+ )
+}
+
+pub fn arithmetic_html_test() {
+ assert_html_highlight(
+ "arithmetic",
+ "
+let x = 1 + 2 / 3.5e10;
+let y = 0n * 0xff8n ** x;
+x <= y === false;
+",
+ )
+}
+
+pub fn comments_test() {
+ assert_ansi_highlight(
+ "comments",
+ "#! shebang!
+// This is some kind of comment
+console.log(\"Hi\");
+/*
+Another comment
+that spans several lines
+*/
+let x = /* this on is inline! */ 10;
+",
+ )
+}
+
+pub fn class_test() {
+ assert_ansi_highlight(
+ "class",
+ "
+class RegexWrapper {
+ constructor(r) {
+ this.r = r;
+ }
+}
+
+const rw = new RegexWrapper(/hello [regex]?/);
+console.log(rw instanceof RegexWrapper);
+",
+ )
+}
+
+pub fn errors_test() {
+ assert_ansi_highlight(
+ "errors",
+ "
+let unknown = @;
+let ustring = 'This string does not finish
+let uregex = /uh oh
+let badNumber = 0xabcdefg;
+/*
+This comment spans the rest of the program.
+",
+ )
+}