diff --git a/assets/highlighting-tests/toml.toml b/assets/highlighting-tests/toml.toml new file mode 100644 index 00000000000..c46dd49b535 --- /dev/null +++ b/assets/highlighting-tests/toml.toml @@ -0,0 +1,45 @@ +title = "TOML Example" # inline comment +enabled = true +disabled = false + +[owner] +name = "Tom Preston-Werner" +"quoted key" = "value" +dob = 1979-05-27T07:32:00-08:00 +bare-key = 'literal string' +winpath = 'C:\Users\me\' +dotted.nested.key = 42 + +[database] +ports = [8000, 8001, 8002] +data = [["delta", "phi"], [3.14]] +temp_targets = { cpu = 79.5, case = 72.0 } +hex = 0xDEAD_BEEF +octal = 0o755 +binary = 0b1101_0010 +negative = -17 +positive = +99 +scientific = 6.626e-34 +infinity = inf +plus_infinity = +inf +not_a_number = -nan + +[servers.alpha] +ip = "10.0.0.1" +local_date = 1979-05-27 +local_time = 07:32:00.999999 + +multiline = """ +a multi-line basic string \ +with an escape and a "quote" inside +""" + +regex = '''\d{4}-\d{2}-\d{2}''' + +[[products]] +name = "Hammer" +sku = 777777777 + +[[products]] +name = "Nail" +color = "gray" diff --git a/crates/lsh/definitions/toml.lsh b/crates/lsh/definitions/toml.lsh new file mode 100644 index 00000000000..ba21c13766e --- /dev/null +++ b/crates/lsh/definitions/toml.lsh @@ -0,0 +1,89 @@ +#[display_name = "TOML"] +#[path = "**/*.toml"] +#[path = "**/Cargo.lock"] +pub fn toml() { + yield other; + + // Optional leading whitespace. + if /[ \t]+/ { + yield other; + } + + // Table headers: [table], [a.b.c] and [[array.of.tables]]. + if /\[\[[^\]]*\]\]/ { + yield meta.header; + } else if /\[[^\]]*\]/ { + yield meta.header; + } + + yield other; + + until /$/ { + yield other; + + if /#.*/ { + yield comment; + } else if /"""/ { + // Multi-line basic string. + loop { + yield string; + if /\\./ { + } else if /"""/ { + yield string; + break; + } + await input; + } + } else if /'''/ { + // Multi-line literal string (no escapes). + loop { + yield string; + if /'''/ { + yield string; + break; + } + await input; + } + } + // Quoted key: "key" = ... or 'key' = ... (also matches inside inline tables). + else if /("[^"]*"|'[^']*')[ \t]*=/ { + yield $1 as variable; + } + // Bare or dotted key: key = ..., a.b.c = ... (also matches inside inline tables). + else if /([A-Za-z0-9_.-]+)[ \t]*=/ { + yield $1 as variable; + } else if /"/ { + double_quote_string(); + } else if /'/ { + // Literal string: no escape sequences, so a trailing backslash + // (e.g. a Windows path like 'C:\dir\') still ends the string. + until /$/ { + yield string; + if /'/ { + yield string; + break; + } + } + } else if /(?:true|false)\>/ { + yield constant.language; + } else if /\+?-?(?:inf|nan)\>/ { + yield constant.language; + } else if /\d{4}-\d{2}-\d{2}(?:[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})?)?/ { + // Offset date-time, local date-time and local date. + yield constant.numeric; + } else if /\d{2}:\d{2}:\d{2}(?:\.\d+)?/ { + // Local time. + yield constant.numeric; + } else if /\+?-?(?:0x[0-9a-fA-F][0-9a-fA-F_]*|0o[0-7][0-7_]*|0b[01][01_]*|\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)/ { + if /\w+/ { + // Not a number after all. + } else { + yield constant.numeric; + } + } else if /\w+/ { + // Gobble word chars to align the next iteration on a word boundary. + } + + yield other; + } +}