summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c32
-rw-r--r--config.c31
-rw-r--r--main.c1
-rw-r--r--syntax.c11
-rw-r--r--ted.cfg3
-rw-r--r--ted.h15
6 files changed, 87 insertions, 6 deletions
diff --git a/buffer.c b/buffer.c
index 2b9957c..fa16c20 100644
--- a/buffer.c
+++ b/buffer.c
@@ -177,6 +177,33 @@ static inline Settings const *buffer_settings(TextBuffer *buffer) {
return &buffer->ted->settings;
}
+// what programming language is this?
+Language buffer_language(TextBuffer *buffer) {
+ Settings const *settings = buffer_settings(buffer);
+ char const *filename = buffer->filename;
+ if (!filename)
+ return LANG_NONE;
+ size_t filename_len = strlen(filename);
+
+ for (u16 l = 0; l < LANG_COUNT; ++l) {
+ char const *extensions = settings->language_extensions[l];
+ if (extensions) {
+ // extensions is a string with commas separating each extension.
+ size_t len = 0;
+ for (char const *p = extensions; *p; p += len) {
+ if (*p == ',') ++p; // move past comma
+ len = strcspn(p, ",");
+ if (filename_len >= len && strncmp(&filename[filename_len - len], p, len) == 0) {
+ // found a match!
+ return (Language)l;
+ }
+ }
+ }
+ }
+ // no extensions matched
+ return LANG_NONE;
+}
+
// NOTE: this string will be invalidated when the line is edited!!!
// only use it briefly!!
static String32 buffer_get_line(TextBuffer *buffer, u32 line_number) {
@@ -1976,11 +2003,12 @@ void buffer_render(TextBuffer *buffer, Rect r) {
text_state.y -= (float)(buffer->scroll_y - start_line) * char_height;
SyntaxState syntax_state = {0};
+ Language language = buffer_language(buffer);
// dynamic array of character types, to be filled by syntax_highlight
SyntaxCharType *char_types = NULL;
for (u32 line_idx = 0; line_idx < start_line; ++line_idx) {
Line *line = &lines[line_idx];
- syntax_highlight(&syntax_state, buffer->language, line->str, line->len, NULL);
+ syntax_highlight(&syntax_state, language, line->str, line->len, NULL);
}
for (u32 line_idx = start_line; line_idx < nlines; ++line_idx) {
@@ -1988,7 +2016,7 @@ void buffer_render(TextBuffer *buffer, Rect r) {
if (arr_len(char_types) < line->len) {
arr_set_len(char_types, line->len);
}
- syntax_highlight(&syntax_state, buffer->language, line->str, line->len, char_types);
+ syntax_highlight(&syntax_state, language, line->str, line->len, char_types);
for (u32 i = 0; i < line->len; ++i) {
char32_t c = line->str[i];
SyntaxCharType type = char_types[i];
diff --git a/config.c b/config.c
index 2ebc094..bf3b284 100644
--- a/config.c
+++ b/config.c
@@ -11,7 +11,8 @@ typedef enum {
SECTION_NONE,
SECTION_CORE,
SECTION_KEYBOARD,
- SECTION_COLORS
+ SECTION_COLORS,
+ SECTION_EXTENSIONS
} Section;
// all worth it for the -Wformat warnings
@@ -227,6 +228,8 @@ void config_read(Ted *ted, char const *filename) {
section = SECTION_COLORS;
} else if (streq(section_name, "core")) {
section = SECTION_CORE;
+ } else if (streq(section_name, "extensions")) {
+ section = SECTION_EXTENSIONS;
} else {
config_err(cfg, "Unrecognized section: [%s].", section_name);
}
@@ -294,6 +297,25 @@ void config_read(Ted *ted, char const *filename) {
config_err(cfg, "Expected ':' for key action. This line should look something like: %s = :command.", key);
}
} break;
+ case SECTION_EXTENSIONS: {
+ Language lang = language_from_str(key);
+ if (lang == LANG_NONE) {
+ config_err(cfg, "Invalid programming language: %s.", key);
+ } else {
+ char *new_str = malloc(strlen(value) + 1);
+ if (!new_str) {
+ config_err(cfg, "Out of memory.");
+ } else {
+ char *dst = new_str;
+ // get rid of whitespace in extension list
+ for (char const *src = value; *src; ++src)
+ if (!isspace(*src))
+ *dst++ = *src;
+ *dst = 0;
+ settings->language_extensions[lang] = new_str;
+ }
+ }
+ } break;
case SECTION_CORE: {
char const *endptr;
long long const integer = strtoll(value, (char **)&endptr, 10);
@@ -380,3 +402,10 @@ void config_read(Ted *ted, char const *filename) {
ted_seterr(ted, "Couldn't open file %s.", filename);
}
}
+
+static void settings_free(Settings *settings) {
+ for (u16 i = 0; i < LANG_COUNT; ++i) {
+ free(settings->language_extensions[i]);
+ settings->language_extensions[i] = NULL;
+ }
+}
diff --git a/main.c b/main.c
index 0932609..bcad077 100644
--- a/main.c
+++ b/main.c
@@ -591,6 +591,7 @@ int main(int argc, char **argv) {
buffer_free(&ted->line_buffer);
text_font_free(ted->font);
text_font_free(ted->font_bold);
+ settings_free(&ted->settings);
free(ted);
#if _WIN32
for (int i = 0; i < argc; ++i)
diff --git a/syntax.c b/syntax.c
index eff776c..a4378b1 100644
--- a/syntax.c
+++ b/syntax.c
@@ -1,3 +1,12 @@
+// returns the language this string is referring to, or LANG_NONE if it's invalid.
+Language language_from_str(char const *str) {
+ for (int i = 0; i < LANG_COUNT; ++i) {
+ if (streq(language_names[i].name, str))
+ return language_names[i].lang;
+ }
+ return LANG_NONE;
+}
+
// NOTE: returns the color setting, not the color
ColorSetting syntax_char_type_to_color(SyntaxCharType t) {
switch (t) {
@@ -210,7 +219,7 @@ static void syntax_highlight_c(SyntaxStateC *state, char32_t *line, u32 line_len
// 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_TEXT:
+ case LANG_NONE:
memset(char_types, 0, line_len * sizeof *char_types);
break;
case LANG_C:
diff --git a/ted.cfg b/ted.cfg
index 7e2877f..f76c6bd 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -137,3 +137,6 @@ string = #f77
character = #a7f
comment = #999
constant = #8ff
+
+[extensions]
+C = .c, .h
diff --git a/ted.h b/ted.h
index 2fcc541..59247fb 100644
--- a/ted.h
+++ b/ted.h
@@ -16,11 +16,21 @@ typedef union {
} SyntaxState;
ENUM_U16 {
- LANG_TEXT,
+ LANG_NONE,
LANG_C,
LANG_COUNT
} ENUM_U16_END(Language);
+typedef struct {
+ Language lang;
+ char const *name;
+} LanguageName;
+
+static LanguageName const language_names[] = {
+ {LANG_NONE, "None"},
+ {LANG_C, "C"},
+};
+
ENUM_U8 {
SYNTAX_NORMAL,
SYNTAX_KEYWORD,
@@ -45,6 +55,8 @@ typedef struct {
u8 border_thickness;
u8 padding;
u8 scrolloff;
+ // [i] = comma-separated string of file extensions for language i, or NULL for none
+ char *language_extensions[LANG_COUNT];
} Settings;
#define SCANCODE_COUNT 0x120 // SDL scancodes should be less than this value.
@@ -91,7 +103,6 @@ typedef struct {
double scroll_x, scroll_y; // number of characters scrolled in the x/y direction
BufferPos cursor_pos;
BufferPos selection_pos; // if selection is true, the text between selection_pos and cursor_pos is selected.
- Language language;
bool is_line_buffer; // "line buffers" are buffers which can only have one line of text (used for inputs)
bool selection;
bool store_undo_events; // set to false to disable undo events