summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-07-21 23:46:56 -0400
committerpommicket <pommicket@gmail.com>2022-07-21 23:46:56 -0400
commit47a65f608f485af32d2df12be489146ad67839e1 (patch)
tree998051aba1da5da4a75e51bfee9a9a5d5b00b517
parent08da42c48bf40f24faa91c00b777ae15ac8f706b (diff)
minor fixes, syntax highlighting for java & js
-rw-r--r--README.md5
-rw-r--r--buffer.c9
-rw-r--r--keywords.h59
-rwxr-xr-xkeywords.py63
-rw-r--r--syntax.c255
-rw-r--r--ted.cfg2
-rw-r--r--ted.h13
-rw-r--r--test.java13
-rw-r--r--test.js12
9 files changed, 421 insertions, 10 deletions
diff --git a/README.md b/README.md
index 8bdb1d4..da61dd5 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ in other editors.
- Multiple tabs, each with a different file
- Split screen
- Auto-indent
-- Syntax highlighting for C, C++, HTML, LaTeX, Markdown, Python, and Rust.
+- Syntax highlighting for C, C++, HTML, Java, JavaScript, LaTeX, Markdown, Python, and Rust.
- Find and replace (with regular expressions!)
- Run build command, go to errors
- Run any shell command
@@ -145,7 +145,8 @@ Then, open windows\_installer\\ted\\ted.sln, and build.
<tr><td>1.0</td> <td>Bugfixes, small additional features, installers</td> <td>2021 Apr 20</td></tr>
<tr><td>1.0r1</td> <td>Windows-specific bugfixes, update to new version of PCRE2</td> <td>2022 Jan 1</td></tr>
<tr><td>1.0r2</td> <td>Various bugfixes involving closing tabs and windows</td> <td>2022 Mar 26</td></tr>
-<tr><td>1.0r3</td> <td>Better Tex syntax highlighting, move to cursor on backspace/delete</td> <td>2022 Jul 7</td></tr>
+<tr><td>1.0r3</td> <td>Better TeX syntax highlighting, move to cursor on backspace/delete</td> <td>2022 Jul 7</td></tr>
+<tr><td>1.1</td> <td>Minor fixes, syntax highlighting for JavaScript and Java</td> <td>2022 Jul 22</td></tr>
</table>
## License
diff --git a/buffer.c b/buffer.c
index 4fa05ef..50a75fe 100644
--- a/buffer.c
+++ b/buffer.c
@@ -2183,6 +2183,13 @@ bool buffer_save(TextBuffer *buffer) {
bool buffer_save_as(TextBuffer *buffer, char const *new_filename) {
char *prev_filename = buffer->filename;
if ((buffer->filename = buffer_strdup(buffer, new_filename))) {
+ buffer->view_only = false;
+
+ // ensure whole file is syntax highlighted when saving with a different
+ // file extension
+ buffer->frame_earliest_line_modified = 0;
+ buffer->frame_latest_line_modified = buffer->nlines - 1;
+
if (buffer_save(buffer)) {
free(prev_filename);
return true;
@@ -2428,6 +2435,8 @@ void buffer_render(TextBuffer *buffer, Rect r) {
if (buffer->frame_latest_line_modified >= buffer->frame_earliest_line_modified
&& syntax_highlighting) {
// update syntax cache
+ if (buffer->frame_latest_line_modified >= buffer->nlines)
+ buffer->frame_latest_line_modified = buffer->nlines - 1;
Line *earliest = &buffer->lines[buffer->frame_earliest_line_modified];
Line *latest = &buffer->lines[buffer->frame_latest_line_modified];
Line *buffer_last_line = &buffer->lines[buffer->nlines - 1];
diff --git a/keywords.h b/keywords.h
index c880b77..723f8f6 100644
--- a/keywords.h
+++ b/keywords.h
@@ -131,6 +131,65 @@ static Keyword const *const syntax_all_keywords_rust[] = {
['A'] = syntax_keywords_rust_A, ['B'] = syntax_keywords_rust_B, ['C'] = syntax_keywords_rust_C, ['D'] = syntax_keywords_rust_D, ['E'] = syntax_keywords_rust_E, ['F'] = syntax_keywords_rust_F, ['I'] = syntax_keywords_rust_I, ['N'] = syntax_keywords_rust_N, ['O'] = syntax_keywords_rust_O, ['P'] = syntax_keywords_rust_P, ['R'] = syntax_keywords_rust_R, ['S'] = syntax_keywords_rust_S, ['T'] = syntax_keywords_rust_T, ['U'] = syntax_keywords_rust_U, ['V'] = syntax_keywords_rust_V, ['a'] = syntax_keywords_rust_a, ['b'] = syntax_keywords_rust_b, ['c'] = syntax_keywords_rust_c, ['d'] = syntax_keywords_rust_d, ['e'] = syntax_keywords_rust_e, ['f'] = syntax_keywords_rust_f, ['g'] = syntax_keywords_rust_g, ['i'] = syntax_keywords_rust_i, ['l'] = syntax_keywords_rust_l, ['m'] = syntax_keywords_rust_m, ['o'] = syntax_keywords_rust_o, ['p'] = syntax_keywords_rust_p, ['r'] = syntax_keywords_rust_r, ['s'] = syntax_keywords_rust_s, ['t'] = syntax_keywords_rust_t, ['u'] = syntax_keywords_rust_u, ['v'] = syntax_keywords_rust_v, ['w'] = syntax_keywords_rust_w, ['y'] = syntax_keywords_rust_y
};
+static Keyword const syntax_keywords_javascript_A[8] = {{"AggregateError", SYNTAX_BUILTIN},{"Array", SYNTAX_BUILTIN},{"ArrayBuffer", SYNTAX_BUILTIN},{"AsyncFunction", SYNTAX_BUILTIN},{"AsyncGenerator", SYNTAX_BUILTIN},{"AsyncGeneratorFunction", SYNTAX_BUILTIN},{"Atomics", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_B[5] = {{"BigInt", SYNTAX_BUILTIN},{"BigInt64Array", SYNTAX_BUILTIN},{"BigUint64Array", SYNTAX_BUILTIN},{"Boolean", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_D[3] = {{"DataView", SYNTAX_BUILTIN},{"Date", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_E[3] = {{"Error", SYNTAX_BUILTIN},{"EvalError", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_F[5] = {{"FinalizationRegistry", SYNTAX_BUILTIN},{"Float32Array", SYNTAX_BUILTIN},{"Float64Array", SYNTAX_BUILTIN},{"Function", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_G[3] = {{"Generator", SYNTAX_BUILTIN},{"GeneratorFunction", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_I[7] = {{"Infinity", SYNTAX_BUILTIN},{"Int16Array", SYNTAX_BUILTIN},{"Int32Array", SYNTAX_BUILTIN},{"Int8Array", SYNTAX_BUILTIN},{"InternalError", SYNTAX_BUILTIN},{"Intl", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_J[2] = {{"JSON", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_M[3] = {{"Map", SYNTAX_BUILTIN},{"Math", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_N[3] = {{"NaN", SYNTAX_BUILTIN},{"Number", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_O[2] = {{"Object", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_P[3] = {{"Promise", SYNTAX_BUILTIN},{"Proxy", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_R[5] = {{"RangeError", SYNTAX_BUILTIN},{"ReferenceError", SYNTAX_BUILTIN},{"Reflect", SYNTAX_BUILTIN},{"RegExp", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_S[6] = {{"Set", SYNTAX_BUILTIN},{"SharedArrayBuffer", SYNTAX_BUILTIN},{"String", SYNTAX_BUILTIN},{"Symbol", SYNTAX_BUILTIN},{"SyntaxError", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_T[3] = {{"TypeError", SYNTAX_BUILTIN},{"TypedArray", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_U[6] = {{"URIError", SYNTAX_BUILTIN},{"Uint16Array", SYNTAX_BUILTIN},{"Uint32Array", SYNTAX_BUILTIN},{"Uint8Array", SYNTAX_BUILTIN},{"Uint8ClampedArray", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_W[5] = {{"WeakMap", SYNTAX_BUILTIN},{"WeakRef", SYNTAX_BUILTIN},{"WeakSet", SYNTAX_BUILTIN},{"WebAssembly", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_a[2] = {{"await", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_b[2] = {{"break", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_c[6] = {{"case", SYNTAX_KEYWORD},{"catch", SYNTAX_KEYWORD},{"class", SYNTAX_KEYWORD},{"const", SYNTAX_KEYWORD},{"continue", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_d[7] = {{"debugger", SYNTAX_KEYWORD},{"default", SYNTAX_KEYWORD},{"delete", SYNTAX_KEYWORD},{"do", SYNTAX_KEYWORD},{"decodeURI", SYNTAX_BUILTIN},{"decodeURIComponent", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_e[7] = {{"else", SYNTAX_KEYWORD},{"export", SYNTAX_KEYWORD},{"extends", SYNTAX_KEYWORD},{"encodeURI", SYNTAX_BUILTIN},{"encodeURIComponent", SYNTAX_BUILTIN},{"eval", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_f[5] = {{"finally", SYNTAX_KEYWORD},{"for", SYNTAX_KEYWORD},{"function", SYNTAX_KEYWORD},{"false", SYNTAX_CONSTANT}};
+static Keyword const syntax_keywords_javascript_g[2] = {{"globalThis", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_i[7] = {{"if", SYNTAX_KEYWORD},{"import", SYNTAX_KEYWORD},{"in", SYNTAX_KEYWORD},{"instanceof", SYNTAX_KEYWORD},{"isFinite", SYNTAX_BUILTIN},{"isNaN", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_l[2] = {{"let", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_n[3] = {{"new", SYNTAX_KEYWORD},{"null", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_p[3] = {{"parseFloat", SYNTAX_BUILTIN},{"parseInt", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_r[2] = {{"return", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_s[3] = {{"super", SYNTAX_KEYWORD},{"switch", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_t[6] = {{"this", SYNTAX_KEYWORD},{"throw", SYNTAX_KEYWORD},{"try", SYNTAX_KEYWORD},{"typeof", SYNTAX_KEYWORD},{"true", SYNTAX_CONSTANT}};
+static Keyword const syntax_keywords_javascript_u[2] = {{"undefined", SYNTAX_BUILTIN}};
+static Keyword const syntax_keywords_javascript_v[3] = {{"var", SYNTAX_KEYWORD},{"void", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_w[3] = {{"while", SYNTAX_KEYWORD},{"with", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_javascript_y[2] = {{"yield", SYNTAX_KEYWORD}};
+static Keyword const *const syntax_all_keywords_javascript[] = {
+ ['A'] = syntax_keywords_javascript_A, ['B'] = syntax_keywords_javascript_B, ['D'] = syntax_keywords_javascript_D, ['E'] = syntax_keywords_javascript_E, ['F'] = syntax_keywords_javascript_F, ['G'] = syntax_keywords_javascript_G, ['I'] = syntax_keywords_javascript_I, ['J'] = syntax_keywords_javascript_J, ['M'] = syntax_keywords_javascript_M, ['N'] = syntax_keywords_javascript_N, ['O'] = syntax_keywords_javascript_O, ['P'] = syntax_keywords_javascript_P, ['R'] = syntax_keywords_javascript_R, ['S'] = syntax_keywords_javascript_S, ['T'] = syntax_keywords_javascript_T, ['U'] = syntax_keywords_javascript_U, ['W'] = syntax_keywords_javascript_W, ['a'] = syntax_keywords_javascript_a, ['b'] = syntax_keywords_javascript_b, ['c'] = syntax_keywords_javascript_c, ['d'] = syntax_keywords_javascript_d, ['e'] = syntax_keywords_javascript_e, ['f'] = syntax_keywords_javascript_f, ['g'] = syntax_keywords_javascript_g, ['i'] = syntax_keywords_javascript_i, ['l'] = syntax_keywords_javascript_l, ['n'] = syntax_keywords_javascript_n, ['p'] = syntax_keywords_javascript_p, ['r'] = syntax_keywords_javascript_r, ['s'] = syntax_keywords_javascript_s, ['t'] = syntax_keywords_javascript_t, ['u'] = syntax_keywords_javascript_u, ['v'] = syntax_keywords_javascript_v, ['w'] = syntax_keywords_javascript_w, ['y'] = syntax_keywords_javascript_y
+};
+
+static Keyword const syntax_keywords_java_a[3] = {{"abstract", SYNTAX_KEYWORD},{"assert", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_b[4] = {{"boolean", SYNTAX_KEYWORD},{"break", SYNTAX_KEYWORD},{"byte", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_c[7] = {{"case", SYNTAX_KEYWORD},{"catch", SYNTAX_KEYWORD},{"char", SYNTAX_KEYWORD},{"class", SYNTAX_KEYWORD},{"const", SYNTAX_KEYWORD},{"continue", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_d[4] = {{"default", SYNTAX_KEYWORD},{"do", SYNTAX_KEYWORD},{"double", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_e[4] = {{"else", SYNTAX_KEYWORD},{"enum", SYNTAX_KEYWORD},{"extends", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_f[6] = {{"final", SYNTAX_KEYWORD},{"finally", SYNTAX_KEYWORD},{"float", SYNTAX_KEYWORD},{"for", SYNTAX_KEYWORD},{"false", SYNTAX_CONSTANT}};
+static Keyword const syntax_keywords_java_g[2] = {{"goto", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_i[7] = {{"if", SYNTAX_KEYWORD},{"implements", SYNTAX_KEYWORD},{"import", SYNTAX_KEYWORD},{"instanceof", SYNTAX_KEYWORD},{"int", SYNTAX_KEYWORD},{"interface", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_l[2] = {{"long", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_n[4] = {{"native", SYNTAX_KEYWORD},{"new", SYNTAX_KEYWORD},{"null", SYNTAX_CONSTANT}};
+static Keyword const syntax_keywords_java_p[5] = {{"package", SYNTAX_KEYWORD},{"private", SYNTAX_KEYWORD},{"protected", SYNTAX_KEYWORD},{"public", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_r[2] = {{"return", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_s[7] = {{"short", SYNTAX_KEYWORD},{"static", SYNTAX_KEYWORD},{"strictfp", SYNTAX_KEYWORD},{"super", SYNTAX_KEYWORD},{"switch", SYNTAX_KEYWORD},{"synchronized", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_t[7] = {{"this", SYNTAX_KEYWORD},{"throw", SYNTAX_KEYWORD},{"throws", SYNTAX_KEYWORD},{"transient", SYNTAX_KEYWORD},{"try", SYNTAX_KEYWORD},{"true", SYNTAX_CONSTANT}};
+static Keyword const syntax_keywords_java_v[4] = {{"var", SYNTAX_KEYWORD},{"void", SYNTAX_KEYWORD},{"volatile", SYNTAX_KEYWORD}};
+static Keyword const syntax_keywords_java_w[2] = {{"while", SYNTAX_KEYWORD}};
+static Keyword const *const syntax_all_keywords_java[] = {
+ ['a'] = syntax_keywords_java_a, ['b'] = syntax_keywords_java_b, ['c'] = syntax_keywords_java_c, ['d'] = syntax_keywords_java_d, ['e'] = syntax_keywords_java_e, ['f'] = syntax_keywords_java_f, ['g'] = syntax_keywords_java_g, ['i'] = syntax_keywords_java_i, ['l'] = syntax_keywords_java_l, ['n'] = syntax_keywords_java_n, ['p'] = syntax_keywords_java_p, ['r'] = syntax_keywords_java_r, ['s'] = syntax_keywords_java_s, ['t'] = syntax_keywords_java_t, ['v'] = syntax_keywords_java_v, ['w'] = syntax_keywords_java_w
+};
+
static Keyword const syntax_keywords_python_A[4] = {{"ArithmeticError", SYNTAX_BUILTIN},{"AssertionError", SYNTAX_BUILTIN},{"AttributeError", SYNTAX_BUILTIN}};
static Keyword const syntax_keywords_python_B[6] = {{"BaseException", SYNTAX_BUILTIN},{"BlockingIOError", SYNTAX_BUILTIN},{"BrokenPipeError", SYNTAX_BUILTIN},{"BufferError", SYNTAX_BUILTIN},{"BytesWarning", SYNTAX_BUILTIN}};
static Keyword const syntax_keywords_python_C[6] = {{"ChildProcessError", SYNTAX_BUILTIN},{"ConnectionAbortedError", SYNTAX_BUILTIN},{"ConnectionError", SYNTAX_BUILTIN},{"ConnectionRefusedError", SYNTAX_BUILTIN},{"ConnectionResetError", SYNTAX_BUILTIN}};
diff --git a/keywords.py b/keywords.py
index 2413dd9..b7f7432 100755
--- a/keywords.py
+++ b/keywords.py
@@ -27,6 +27,13 @@ def output_keywords(file, keywords, language):
file.write('\t'+', '.join(["['{}'] = syntax_keywords_{}_{}".format(c, language, c) for c in sorted(keywords.keys())]) + '\n')
file.write('};\n\n')
+def cant_overlap(*args):
+ for i in range(len(args)):
+ for j in range(i):
+ intersection = set(args[i]).intersection(args[j])
+ if intersection:
+ raise ValueError("Argument {} intersects with {}: {}".format(i, j, intersection))
+
constants_c = ['CHAR_BIT', 'CHAR_MAX', 'CHAR_MIN', 'DBL_DIG', 'DBL_EPSILON', 'DBL_HAS_SUBNORM', 'DBL_MANT_DIG', 'DBL_MAX',
'DBL_MAX_10_EXP', 'DBL_MAX_EXP', 'DBL_MIN', 'DBL_MIN_EXP', 'DBL_TRUE_MIN', 'DECIMAL_DIG', 'EXIT_FAILURE', 'EXIT_SUCCESS',
'FLT_DECIMAL_DIG', 'FLT_DIG', 'FLT_EVAL_METHOD', 'FLT_HAS_SUBNORM', 'FLT_MANT_DIG', 'FLT_MAX', 'FLT_MAX_10_EXP', 'FLT_MAX_EXP',
@@ -151,12 +158,7 @@ keywords_cpp = [
'xor', 'xor_eq',
'bool', 'wchar_t',
]
-def cant_overlap(*args):
- for i in range(len(args)):
- for j in range(i):
- intersection = set(args[i]).intersection(args[j])
- if intersection:
- raise ValueError("Argument {} intersects with {}: {}".format(i, j, intersection))
+
cant_overlap(keywords_c, keywords_cpp)
keywords_rust = [
@@ -253,6 +255,51 @@ builtins_html = []
for attr in attributes_html:
builtins_html.append(attr + '=')
+
+keywords_javascript = [
+ 'break', 'case', 'catch', 'class', 'const',
+ 'continue', 'debugger', 'default', 'delete',
+ 'do', 'else', 'export', 'extends', 'finally',
+ 'for', 'function', 'if', 'import', 'in',
+ 'instanceof', 'new', 'return', 'super',
+ 'switch', 'this', 'throw', 'try', 'typeof',
+ 'var', 'void', 'while', 'with', 'yield',
+ 'let', 'await'
+]
+
+constants_javascript = [
+ 'true', 'false'
+]
+
+builtins_javascript = [
+ 'AggregateError','Array','ArrayBuffer','AsyncFunction','AsyncGenerator','AsyncGeneratorFunction',
+ 'Atomics','BigInt','BigInt64Array','BigUint64Array','Boolean','DataView','Date','decodeURI',
+ 'decodeURIComponent','encodeURI','encodeURIComponent','Error','eval','EvalError','FinalizationRegistry',
+ 'Float32Array','Float64Array','Function','Generator','GeneratorFunction','globalThis','Infinity',
+ 'Int16Array','Int32Array','Int8Array','InternalError','Intl','isFinite','isNaN','JSON','Map','Math',
+ 'NaN','Number','Object','parseFloat','parseInt','Promise','Proxy','RangeError','ReferenceError',
+ 'Reflect','RegExp','Set','SharedArrayBuffer','String','Symbol','SyntaxError','TypedArray',
+ 'TypeError','Uint16Array','Uint32Array','Uint8Array','Uint8ClampedArray','undefined',
+ 'URIError','WeakMap','WeakRef','WeakSet','WebAssembly', 'null'
+]
+
+keywords_java = [
+ 'abstract', 'continue', 'for', 'new', 'switch',
+ 'assert', 'default', 'goto', 'package', 'synchronized',
+ 'boolean', 'do', 'if', 'private', 'this',
+ 'break', 'double', 'implements', 'protected', 'throw',
+ 'byte', 'else', 'import', 'public', 'throws',
+ 'case', 'enum', 'instanceof', 'return', 'transient',
+ 'catch', 'extends', 'int', 'short', 'try',
+ 'char', 'final', 'interface', 'static', 'var',
+ 'class', 'finally', 'long', 'strictfp', 'void',
+ 'const', 'float', 'native', 'super', 'volatile', 'while'
+]
+
+constants_java = [
+ 'true', 'false', 'null'
+]
+
file = open('keywords.h', 'w')
file.write('''// keywords for all languages ted supports
// This file was auto-generated by keywords.py
@@ -268,6 +315,7 @@ def label(kwds, l):
cant_overlap(keywords_c, constants_c, builtins_c)
cant_overlap(keywords_rust, builtins_rust, constants_rust)
cant_overlap(keywords_python, builtins_python)
+cant_overlap(keywords_javascript, builtins_javascript, constants_javascript)
c_things = label(keywords_c, SYNTAX_KEYWORD) + label(constants_c, SYNTAX_CONSTANT) + label(builtins_c, SYNTAX_BUILTIN)
output_keywords(file, c_things, 'c')
cpp_things = c_things + label(keywords_cpp, SYNTAX_KEYWORD)
@@ -275,6 +323,9 @@ cpp_things.remove((SYNTAX_BUILTIN, 'bool'))
cpp_things.remove((SYNTAX_BUILTIN, 'wchar_t'))
output_keywords(file, cpp_things, 'cpp')
output_keywords(file, label(keywords_rust, SYNTAX_KEYWORD) + label(builtins_rust, SYNTAX_BUILTIN) + label(constants_rust, SYNTAX_CONSTANT), 'rust')
+output_keywords(file, label(keywords_javascript, SYNTAX_KEYWORD) + label(builtins_javascript, SYNTAX_BUILTIN) +
+ label(constants_javascript, SYNTAX_CONSTANT), 'javascript')
+output_keywords(file, label(keywords_java, SYNTAX_KEYWORD) + label(constants_java, SYNTAX_CONSTANT), 'java')
output_keywords(file, label(keywords_python, SYNTAX_KEYWORD) + label(builtins_python, SYNTAX_BUILTIN), 'python')
output_keywords(file, label(builtins_html, SYNTAX_BUILTIN), 'html')
output_keywords(file, label(constants_config, SYNTAX_CONSTANT), 'config')
diff --git a/syntax.c b/syntax.c
index b3504bc..99aae45 100644
--- a/syntax.c
+++ b/syntax.c
@@ -20,6 +20,8 @@ char const *language_comment_start(Language l) {
return "/* ";
case LANG_RUST:
case LANG_CPP:
+ case LANG_JAVASCRIPT:
+ case LANG_JAVA:
return "// ";
case LANG_CONFIG:
case LANG_PYTHON:
@@ -497,12 +499,12 @@ static void syntax_highlight_python(SyntaxState *state, char32_t const *line, u3
case '\'':
case '"': {
bool dbl_quoted = c == '"';
- bool is_triple = i < line_len - 2 &&
+ bool is_triple = i+2 < line_len &&
line[i+1] == c && line[i+2] == c;
if (in_string) {
if (!string_is_multiline || is_triple) {
- // end of string
if (string_is_dbl_quoted == dbl_quoted && backslashes % 2 == 0) {
+ // end of string
in_string = false;
if (char_types) {
char_types[i] = SYNTAX_STRING;
@@ -1046,6 +1048,249 @@ static void syntax_highlight_config(SyntaxState *state, char32_t const *line, u3
}
}
+static void syntax_highlight_javascript(SyntaxState *state, char32_t const *line, u32 line_len, SyntaxCharType *char_types) {
+ (void)state;
+ bool string_is_template = (*state & SYNTAX_STATE_JAVASCRIPT_TEMPLATE_STRING) != 0;
+ bool in_multiline_comment = (*state & SYNTAX_STATE_JAVASCRIPT_MULTILINE_COMMENT) != 0;
+ bool string_is_dbl_quoted = false;
+ bool in_number = false;
+ bool in_string = string_is_template;
+ uint backslashes = 0;
+
+ for (u32 i = 0; i < line_len; ++i) {
+ char32_t c = line[i];
+ bool dealt_with = false;
+ switch (c) {
+ case '/':
+ if (!in_string) {
+ if (i > 0) {
+ if (line[i-1] == '*') {
+ // end of multi line comment
+ in_multiline_comment = false;
+ if (char_types) char_types[i] = SYNTAX_COMMENT;
+ dealt_with = true;
+ }
+ }
+ if (!dealt_with && i+1 < line_len) {
+ if (line[i+1] == '/') {
+ // single line comment
+ if (char_types) memset(&char_types[i], SYNTAX_COMMENT, line_len - i);
+ i = line_len - 1;
+ dealt_with = true;
+ } else if (line[i+1] == '*') {
+ // multi line comment
+ in_multiline_comment = true;
+ if (char_types) char_types[i] = SYNTAX_COMMENT;
+ dealt_with = true;
+ }
+ }
+ }
+ break;
+ case '\'':
+ case '"':
+ case '`': {
+ if (!in_multiline_comment) {
+ bool dbl_quoted = c == '"';
+ bool template = c == '`';
+ if (in_string) {
+ if (string_is_dbl_quoted == dbl_quoted && string_is_template == template && backslashes % 2 == 0) {
+ // end of string
+ in_string = false;
+ if (char_types) char_types[i] = SYNTAX_STRING;
+ dealt_with = true;
+ }
+ } else {
+ // start of string
+ string_is_dbl_quoted = dbl_quoted;
+ string_is_template = template;
+ in_string = true;
+ }
+ }
+ } break;
+ case ANY_DIGIT:
+ if (char_types && !in_string && !in_number && !in_multiline_comment) {
+ in_number = true;
+ if (i) {
+ if (line[i - 1] == '.') {
+ // support .6, for example
+ char_types[i - 1] = SYNTAX_CONSTANT;
+ } else if (is32_ident(line[i - 1])) {
+ // actually, this isn't a number. it's something like a*6* or u3*2*.
+ in_number = false;
+ }
+ }
+ }
+ break;
+ case '\\':
+ ++backslashes;
+ break;
+ default:
+ if ((i && is32_ident(line[i - 1])) || !is32_ident(c))
+ break; // can't be a keyword on its own.
+
+ if (char_types && !in_string && !in_number && !in_multiline_comment) {
+ u32 keyword_len = syntax_keyword_len(LANG_JAVASCRIPT, line, i, line_len);
+ Keyword const *keyword = syntax_keyword_lookup(syntax_all_keywords_javascript, arr_count(syntax_all_keywords_javascript),
+ &line[i], keyword_len);
+ if (keyword) {
+ SyntaxCharType type = keyword->type;
+ for (size_t j = 0; j < keyword_len; ++j) {
+ char_types[i++] = type;
+ }
+ --i; // we'll increment i from the for loop
+ dealt_with = true;
+ break;
+ }
+ }
+ break;
+ }
+ if (c != '\\') backslashes = 0;
+ if (in_number && !syntax_number_continues(line, line_len, i))
+ in_number = false;
+
+ if (char_types && !dealt_with) {
+ SyntaxCharType type = SYNTAX_NORMAL;
+ if (in_multiline_comment)
+ type = SYNTAX_COMMENT;
+ else if (in_string)
+ type = SYNTAX_STRING;
+ else if (in_number)
+ type = SYNTAX_CONSTANT;
+ char_types[i] = type;
+ }
+ }
+ *state = 0;
+ if (in_string && string_is_template)
+ *state |= SYNTAX_STATE_JAVASCRIPT_TEMPLATE_STRING;
+ if (in_multiline_comment)
+ *state |= SYNTAX_STATE_JAVASCRIPT_MULTILINE_COMMENT;
+}
+
+static void syntax_highlight_java(SyntaxState *state_ptr, char32_t const *line, u32 line_len, SyntaxCharType *char_types) {
+ SyntaxState state = *state_ptr;
+ bool in_string = false;
+ bool in_multiline_comment = (state & SYNTAX_STATE_CPP_MULTI_LINE_COMMENT) != 0;
+ bool in_char = false;
+ bool in_number = false;
+
+ int backslashes = 0;
+ for (u32 i = 0; i < line_len; ++i) {
+
+ // are there 1/2 characters left in the line?
+ bool has_1_char = i + 1 < line_len;
+
+ bool dealt_with = false;
+
+ char32_t c = line[i];
+
+ switch (c) {
+ case '\\':
+ ++backslashes;
+ break;
+ case '/':
+ if (!in_multiline_comment && !in_string && !in_char && has_1_char) {
+ if (line[i + 1] == '/') {
+ if (char_types) memset(&char_types[i], SYNTAX_COMMENT, line_len - i);
+ i = line_len - 1;
+ dealt_with = true;
+ } else if (line[i + 1] == '*') {
+ in_multiline_comment = true; // /*
+ }
+ } else if (in_multiline_comment) {
+ if (i > 0 && line[i - 1] == '*') {
+ // */
+ in_multiline_comment = false;
+ if (char_types) {
+ dealt_with = true;
+ char_types[i] = SYNTAX_COMMENT;
+ }
+ }
+ }
+ break;
+ case '"':
+ if (in_string && backslashes % 2 == 0) {
+ in_string = false;
+ if (char_types) {
+ dealt_with = true;
+ char_types[i] = SYNTAX_STRING;
+ }
+ } else if (!in_multiline_comment && !in_char) {
+ in_string = true;
+ }
+ break;
+ case '\'':
+ if (in_char && backslashes % 2 == 0) {
+ in_char = false;
+ if (char_types) {
+ dealt_with = true;
+ char_types[i] = SYNTAX_CHARACTER;
+ }
+ } else if (!in_multiline_comment && !in_string) {
+ in_char = true;
+ }
+ break;
+ case ANY_DIGIT:
+ // a number!
+ if (char_types && !in_multiline_comment && !in_string && !in_number && !in_char) {
+ in_number = true;
+ if (i) {
+ if (line[i - 1] == '.') {
+ // support .6, for example
+ char_types[i - 1] = SYNTAX_CONSTANT;
+ } else if (is32_ident(line[i - 1])) {
+ // actually, this isn't a number. it's something like a*6* or u3*2*.
+ in_number = false;
+ }
+ }
+ }
+ break;
+ default: {
+ if ((i && is32_ident(line[i - 1])) || !is32_ident(c))
+ break; // can't be a keyword on its own.
+
+ // keywords don't matter for advancing the state
+ if (char_types && !in_multiline_comment && !in_number && !in_string && !in_char) {
+ u32 keyword_len = syntax_keyword_len(LANG_JAVA, line, i, line_len);
+ Keyword const *keyword = syntax_keyword_lookup(syntax_all_keywords_java, arr_count(syntax_all_keywords_java),
+ &line[i], keyword_len);
+
+
+ if (keyword) {
+ SyntaxCharType type = keyword->type;
+ for (size_t j = 0; j < keyword_len; ++j) {
+ char_types[i++] = type;
+ }
+ --i; // we'll increment i from the for loop
+ dealt_with = true;
+ break;
+ }
+ }
+ } break;
+ }
+ if (c != '\\') backslashes = 0;
+ if (in_number && !syntax_number_continues(line, line_len, i)) {
+ in_number = false;
+ }
+
+ if (char_types && !dealt_with) {
+ SyntaxCharType type = SYNTAX_NORMAL;
+ if (in_multiline_comment)
+ type = SYNTAX_COMMENT;
+ else if (in_string)
+ type = SYNTAX_STRING;
+ else if (in_char)
+ type = SYNTAX_CHARACTER;
+ else if (in_number)
+ type = SYNTAX_CONSTANT;
+
+ char_types[i] = type;
+ }
+ }
+ *state_ptr = (SyntaxState)(
+ (in_multiline_comment * SYNTAX_STATE_JAVA_MULTILINE_COMMENT)
+ );
+}
+
// This is the main syntax highlighting function. It will determine which colors to use for each character.
// Rather than returning colors, it returns a character type (e.g. comment) which can be converted to a color.
// To highlight multiple lines, start out with a zeroed SyntaxState, and pass a pointer to it each time.
@@ -1080,6 +1325,12 @@ void syntax_highlight(SyntaxState *state, Language lang, char32_t const *line, u
case LANG_CONFIG:
syntax_highlight_config(state, line, line_len, char_types);
break;
+ case LANG_JAVASCRIPT:
+ syntax_highlight_javascript(state, line, line_len, char_types);
+ break;
+ case LANG_JAVA:
+ syntax_highlight_java(state, line, line_len, char_types);
+ break;
case LANG_COUNT: assert(0); break;
}
}
diff --git a/ted.cfg b/ted.cfg
index 87b1c95..27b33e5 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -227,3 +227,5 @@ Tex = .tex
Markdown = .md
HTML = .html, .php, .xml, .xhtml
Config = .cfg
+Javascript = .js
+Java = .java
diff --git a/ted.h b/ted.h
index 941508f..2400aa0 100644
--- a/ted.h
+++ b/ted.h
@@ -41,6 +41,15 @@ enum {
SYNTAX_STATE_HTML_COMMENT = 0x01u
};
+enum {
+ SYNTAX_STATE_JAVASCRIPT_TEMPLATE_STRING = 0x01u,
+ SYNTAX_STATE_JAVASCRIPT_MULTILINE_COMMENT = 0x02u,
+};
+
+enum {
+ SYNTAX_STATE_JAVA_MULTILINE_COMMENT = 0x01u
+};
+
typedef u8 SyntaxState;
// If you are adding new languages, DO NOT change the constant values
@@ -55,6 +64,8 @@ ENUM_U16 {
LANG_MARKDOWN = 6,
LANG_HTML = 7,
LANG_CONFIG = 8, // .cfg files, e.g. ted.cfg
+ LANG_JAVASCRIPT = 9,
+ LANG_JAVA = 10,
LANG_COUNT
} ENUM_U16_END(Language);
@@ -73,6 +84,8 @@ static LanguageName const language_names[] = {
{LANG_MARKDOWN, "Markdown"},
{LANG_HTML, "HTML"},
{LANG_CONFIG, "Config"},
+ {LANG_JAVASCRIPT, "Javascript"},
+ {LANG_JAVA, "Java"},
};
static_assert_if_possible(arr_count(language_names) == LANG_COUNT)
diff --git a/test.java b/test.java
new file mode 100644
index 0000000..7183aed
--- /dev/null
+++ b/test.java
@@ -0,0 +1,13 @@
+class Test {
+ public static void main(String[] args) {
+ /* hello!
+ everyone
+ this
+ is
+ a test*/
+ String x = "hello, world!\"";
+ System.out.println(x +
+ "yes\n\\"+
+ x);
+ }
+}
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..ad95614
--- /dev/null
+++ b/test.js
@@ -0,0 +1,12 @@
+const c = `template
+strings
+yay
+`;
+let y = 34 * parseInt('hello\\\'\\"') + "'\\";
+/*
+comm
+ent
+
+*/a//yes
+/*
+*//no