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; + + +--- + + +let x = 1 + 2 / 3.5e10; +let y = 0n * 0xff8n ** x; +x <= y === false; + \ 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(); + + +--- + + +export function main() { + const message = 'Hello, world!'; + console.log(message); +} + +main(); + \ 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); + + +--- + + +class RegexWrapper { + constructor(r) { + this.r = r; + } +} + +const rw = new RegexWrapper(/hello [regex]?/); +console.log(rw instanceof RegexWrapper); + \ 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; + + +--- + +#! shebang! +// This is some kind of comment +console.log("Hi"); +/* +Another comment +that spans several lines +*/ +let x = /* this on is inline! */ 10; + \ 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. + + +--- + + +let unknown = @; +let ustring = 'This string does not finish +let uregex = /uh oh +let badNumber = 0xabcdefg; +/* +This comment spans the rest of the program. + \ 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. +", + ) +}