summaryrefslogtreecommitdiff
path: root/syntax.c
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-01-31 19:09:50 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-01-31 19:09:50 -0500
commit68b3e3928e1bd05ebbb56810ae8b7a68ff5f12b0 (patch)
tree72832015fedc7f8230b345e36aa9b0b5efa7cf46 /syntax.c
parent58444144fae39d38c155d868cf3aebb8e4ef8dba (diff)
started syntax higlighting (still need to add state to each line)
Diffstat (limited to 'syntax.c')
-rw-r--r--syntax.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/syntax.c b/syntax.c
new file mode 100644
index 0000000..50e87d9
--- /dev/null
+++ b/syntax.c
@@ -0,0 +1,121 @@
+typedef struct {
+ bool multi_line_comment:1; // are we in a multi-line comment? (delineated by /* */)
+ bool continued_single_line_comment:1; // if you add a \ to the end of a single-line comment, it is continued to the next line.
+ bool continued_preprocessor:1; // similar to above
+ bool continued_string:1;
+} SyntaxStateC;
+
+typedef union {
+ SyntaxStateC c;
+} SyntaxState;
+
+ENUM_U16 {
+ LANG_C
+} ENUM_U16_END(Language);
+
+ENUM_U8 {
+ SYNTAX_NORMAL,
+ SYNTAX_KEYWORD,
+ SYNTAX_COMMENT,
+ SYNTAX_PREPROCESSOR,
+ SYNTAX_STRING,
+ SYNTAX_CHARACTER,
+ SYNTAX_NUMBER
+} ENUM_U8_END(SyntaxCharType);
+
+// NOTE: returns the color setting, not the color
+ColorSetting syntax_char_type_to_color(SyntaxCharType t) {
+ switch (t) {
+ case SYNTAX_NORMAL: return COLOR_TEXT;
+ case SYNTAX_KEYWORD: return COLOR_KEYWORD;
+ case SYNTAX_COMMENT: return COLOR_COMMENT;
+ case SYNTAX_PREPROCESSOR: return COLOR_PREPROCESSOR;
+ case SYNTAX_STRING: return COLOR_STRING;
+ case SYNTAX_CHARACTER: return COLOR_CHARACTER;
+ case SYNTAX_NUMBER: return COLOR_NUMBER;
+ }
+}
+
+static void syntax_highlight_c(SyntaxStateC *state, char32_t *line, u32 line_len, SyntaxCharType *char_types) {
+ (void)state;
+ bool in_preprocessor = state->continued_preprocessor;
+ bool in_string = state->continued_string;
+ bool in_single_line_comment = state->continued_single_line_comment; // this kind of comment :)
+ bool in_multi_line_comment = state->multi_line_comment;
+ int backslashes = 0;
+ for (u32 i = 0; i < line_len; ++i) {
+ SyntaxCharType type = SYNTAX_NORMAL;
+ // necessary for the final " of a string to be highlighted
+ bool in_string_now = in_string;
+ bool in_multi_line_comment_now = in_multi_line_comment;
+
+ // are there 1/2 characters left in the line?
+ bool has_1_char = i + 1 < line_len;
+
+ switch (line[i]) {
+ case '#':
+ if (!in_single_line_comment && !in_multi_line_comment)
+ in_preprocessor = true;
+ break;
+ case '\\':
+ ++backslashes;
+ break;
+ case '/':
+ if (!in_multi_line_comment && !in_single_line_comment && !in_string && has_1_char) {
+ if (line[i + 1] == '/')
+ in_single_line_comment = true; // //
+ else if (line[i + 1] == '*')
+ in_multi_line_comment = in_multi_line_comment_now = true; // /*
+ } else if (in_multi_line_comment) {
+ if (i && line[i - 1] == '*') {
+ // */
+ in_multi_line_comment = false;
+ }
+ }
+ break;
+ case '"':
+ if (in_string && backslashes % 2 == 0)
+ in_string = false;
+ else if (!in_multi_line_comment && !in_single_line_comment)
+ in_string = in_string_now = true;
+ break;
+ case '<': // preprocessor string, e.g. <stdio.h>
+ if (in_preprocessor)
+ in_string = in_string_now = true;
+ break;
+ case '>':
+ if (in_preprocessor && in_string)
+ in_string = false;
+ break;
+ }
+ if (line[i] != '\\') backslashes = 0;
+
+ if (in_single_line_comment || in_multi_line_comment_now)
+ type = SYNTAX_COMMENT;
+ else if (in_string_now)
+ type = SYNTAX_STRING;
+ else if (in_preprocessor)
+ type = SYNTAX_PREPROCESSOR;
+
+ if (char_types) {
+ char_types[i] = type;
+ }
+ }
+ state->continued_single_line_comment = backslashes && in_single_line_comment;
+ state->continued_preprocessor = backslashes && in_preprocessor;
+ state->continued_string = backslashes && in_string;
+
+ state->multi_line_comment = in_multi_line_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.
+// You can set char_types to NULL if you just want to advance the state, and don't care about the character types.
+void syntax_highlight(SyntaxState *state, Language lang, char32_t *line, u32 line_len, SyntaxCharType *char_types) {
+ switch (lang) {
+ case LANG_C:
+ syntax_highlight_c(&state->c, line, line_len, char_types);
+ break;
+ }
+}