summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2024-03-18 22:07:36 +0100
committerAlbert Cervin <albert@acervin.com>2024-03-18 22:12:01 +0100
commit1558a1b36b15eb9bde28e05beea43b619e6257c6 (patch)
treecf17929449567278cd8487ecf2aff648122c5685
parenteabf7f9a958026c073faecf7504cbd8bb484a6c1 (diff)
downloaddged-1558a1b36b15eb9bde28e05beea43b619e6257c6.tar.gz
dged-1558a1b36b15eb9bde28e05beea43b619e6257c6.tar.xz
dged-1558a1b36b15eb9bde28e05beea43b619e6257c6.zip
More work on languages/syntax
Implement another predicate and add javascript.
-rw-r--r--Makefile1
-rw-r--r--dged.nix50
-rw-r--r--src/dged/lang.c2
-rw-r--r--src/dged/s8.c18
-rw-r--r--src/dged/s8.h2
-rw-r--r--src/dged/syntax.c119
-rw-r--r--src/main/main.c18
7 files changed, 175 insertions, 35 deletions
diff --git a/Makefile b/Makefile
index 43b2be9..009fdb8 100644
--- a/Makefile
+++ b/Makefile
@@ -115,6 +115,7 @@ format:
clean:
rm -f $(FILES)
rm -rf $(.CURDIR)/docs
+ rm -rf $(.OBJDIR)/grammars
install: dged
install -d $(prefix)/bin
diff --git a/dged.nix b/dged.nix
index a529004..39b32e1 100644
--- a/dged.nix
+++ b/dged.nix
@@ -33,26 +33,70 @@ stdenv.mkDerivation {
'';
TREESITTER_GRAMMARS = with tree-sitter-grammars;
- linkFarm "tree-sitter-grammars" {
+ linkFarm "tree-sitter-grammars" rec {
"bash" = tree-sitter-bash;
"c" = tree-sitter-c;
+ "cpp" = tree-sitter-cpp.overrideAttrs (_: {
+ # TODO: better, this works kinda ok but maybe should be more flexible
+ postInstall = ''
+ echo "" >> "$out"/queries/highlights.scm
+ echo ";; Inserted from C" >> "$out"/queries/highlights.scm
+ cat "${tree-sitter-c}"/queries/highlights.scm >> "$out"/queries/highlights.scm
+ '';
+ });
"rust" = tree-sitter-rust;
"nix" = tree-sitter-nix;
"python" = tree-sitter-python;
"make" = tree-sitter-make;
+ "markdown" = tree-sitter-markdown;
+ "javascript" = tree-sitter.buildGrammar {
+ language = "javascript";
+ version = "0.20.4";
+ src = fetchFromGitHub {
+ owner = "tree-sitter";
+ repo = "tree-sitter-javascript";
+ rev = "v0.20.4";
+ hash = "sha256-HhqYqU1CwPxXMHp21unRekFDzpGVedlgh/4bsplhe9c=";
+ };
+ };
+ "typescript" = tree-sitter.buildGrammar {
+ language = "typescript";
+ version = "0.20.6";
+ location = "typescript";
+ src = fetchFromGitHub {
+ owner = "tree-sitter";
+ repo = "tree-sitter-typescript";
+ rev = "v0.20.6";
+ hash = "sha256-uGuwE1eTVEkuosMfTeY2akHB+bJ5npWEwUv+23nhY9M=";
+ };
+
+ postInstall = ''
+ cd ..
+ cp -r queries $out
+ '';
+ };
"qmljs" = tree-sitter.buildGrammar {
language = "qmljs";
version = "0.1.2";
src = fetchFromGitHub {
owner = "yuja";
repo = "tree-sitter-qmljs";
- rev = "master";
+ rev = "9fa49ff3315987f715ce5666ff979a7742fa8a98";
hash = "sha256-q20gLVLs0LpqRpgo/qNRDfExbWXhICWZjM1ux4+AT6M=";
};
- # remove broken symlinks
+
+ # remove and fix broken symlinks
postInstall = ''
unlink "$out/queries/highlights-javascript.scm"
unlink "$out/queries/highlights-typescript.scm"
+
+ echo "" >> "$out"/queries/highlights.scm
+ echo ";; Inserted from javascript" >> "$out"/queries/highlights.scm
+ cat "${javascript}"/queries/highlights.scm >> "$out"/queries/highlights.scm
+
+ echo "" >> "$out"/queries/highlights.scm
+ echo ";; Inserted from typescript" >> "$out"/queries/highlights.scm
+ cat "${typescript}"/queries/highlights.scm >> "$out"/queries/highlights.scm
'';
};
"gitcommit" = tree-sitter.buildGrammar {
diff --git a/src/dged/lang.c b/src/dged/lang.c
index d2d7b34..070b96e 100644
--- a/src/dged/lang.c
+++ b/src/dged/lang.c
@@ -46,6 +46,8 @@ void languages_init(bool register_default) {
define_lang("Nix", "nix", "^.*\\.nix$", 2, false);
define_lang("Make", "make", "^.*(Makefile|\\.mk)$", 4, true);
define_lang("Python", "python", "^.*\\.py$", 4, false);
+ define_lang("Markdown", "markdown", "^.*\\.md$", 4, false);
+ define_lang("Javascript", "javascript", "^.*\\.js$", 4, false);
define_lang("Git Commit Message", "gitcommit", "^.*COMMIT_EDITMSG$", 4,
false);
}
diff --git a/src/dged/s8.c b/src/dged/s8.c
index 0566fde..c4544b9 100644
--- a/src/dged/s8.c
+++ b/src/dged/s8.c
@@ -23,3 +23,21 @@ char *s8tocstr(struct s8 s) {
cstr[s.l] = '\0';
return cstr;
}
+
+bool s8startswith(struct s8 s, struct s8 prefix) {
+ if (prefix.l > s.l) {
+ return false;
+ }
+
+ return memcmp(s.s, prefix.s, prefix.l) == 0;
+}
+
+struct s8 s8dup(struct s8 s) {
+ struct s8 new = {0};
+ new.l = s.l;
+
+ new.s = (char *)malloc(s.l);
+ memcpy(new.s, s.s, s.l);
+
+ return new;
+}
diff --git a/src/dged/s8.h b/src/dged/s8.h
index 955a642..76bcc34 100644
--- a/src/dged/s8.h
+++ b/src/dged/s8.h
@@ -14,5 +14,7 @@ struct s8 {
bool s8eq(struct s8 s1, struct s8 s2);
int s8cmp(struct s8 s1, struct s8 s2);
char *s8tocstr(struct s8 s);
+bool s8startswith(struct s8 s, struct s8 prefix);
+struct s8 s8dup(struct s8 s);
#endif
diff --git a/src/dged/syntax.c b/src/dged/syntax.c
index 1544d33..3ee750c 100644
--- a/src/dged/syntax.c
+++ b/src/dged/syntax.c
@@ -121,6 +121,25 @@ static const char *lang_folder(struct buffer *buffer, const char *path) {
return fld;
}
+static bool eval_eq(struct s8 capname, uint32_t argc, struct s8 argv[],
+ struct s8 value, void *data) {
+ const struct s8 *cmp_to = (const struct s8 *)data;
+ if (data == NULL) {
+ return false;
+ }
+
+ return s8eq(value, *cmp_to);
+}
+
+static void cleanup_eq(void *data) {
+ struct s8 *s = (struct s8 *)data;
+ if (s != NULL) {
+ free(s->s);
+ s->l = 0;
+ free(s);
+ }
+}
+
static bool eval_match(struct s8 capname, uint32_t argc, struct s8 argv[],
struct s8 value, void *data) {
regex_t *regex = (regex_t *)data;
@@ -185,6 +204,15 @@ static void create_predicates(struct highlight *h, uint32_t pattern_index) {
}
free(val);
+ } else if (s8eq(args[0], s8("eq?"))) {
+ struct s8 *val = calloc(1, sizeof(struct s8));
+ *val = s8dup(args[1]);
+ VEC_APPEND(&h->predicates, struct predicate * pred);
+ pred->pattern_idx = pattern_index;
+ pred->eval = eval_eq;
+ pred->cleanup = cleanup_eq;
+ pred->argc = 1;
+ pred->data = val;
}
argc = 0;
@@ -217,8 +245,6 @@ static TSQuery *setup_queries(const char *lang_root, TSTree *tree) {
TSQuery *q = ts_query_new(ts_tree_language(tree), (char *)data, len,
&error_offset, &error);
- munmap(data, len);
-
if (error != TSQueryErrorNone) {
const char *msg = "unknown error";
switch (error) {
@@ -235,10 +261,27 @@ static TSQuery *setup_queries(const char *lang_root, TSTree *tree) {
msg = "capture";
break;
}
- message("ts query error at byte offset %d: %s", error_offset, msg);
+
+ // calculate line
+ const char *chars = (const char *)data;
+ uint64_t byteoff = 0;
+ uint32_t lineno = 1;
+ uint32_t colno = 0;
+ while (byteoff < error_offset) {
+ if (chars[byteoff] == '\n') {
+ ++lineno;
+ colno = 0;
+ }
+ ++colno;
+ ++byteoff;
+ }
+ message("ts query error at (%d, %d): %s, %.*s", lineno, colno, msg);
+
+ munmap(data, len);
return NULL;
}
+ munmap(data, len);
return q;
}
@@ -266,6 +309,9 @@ static bool eval_predicates(struct highlight *h, struct text *text,
return true;
}
+#define match_cname(cname, capture) \
+ (s8eq(cname, s8(capture)) || s8startswith(cname, s8(capture ".")))
+
static void update_parser(struct buffer *buffer, void *userdata,
struct location origin, uint32_t width,
uint32_t height) {
@@ -308,50 +354,41 @@ static void update_parser(struct buffer *buffer, void *userdata,
bool highlight = false;
uint32_t color = 0;
- if (s8eq(cname, s8("keyword"))) {
+ if (match_cname(cname, "keyword")) {
highlight = true;
color = Color_Blue;
- } else if (s8eq(cname, s8("operator"))) {
+ } else if (match_cname(cname, "operator")) {
highlight = true;
color = Color_Magenta;
- } else if (s8eq(cname, s8("delimiter"))) {
+ } else if (match_cname(cname, "delimiter")) {
+ highlight = false;
+ } else if (s8eq(cname, s8("text"))) {
highlight = false;
- } else if (s8eq(cname, s8("string")) ||
- s8eq(cname, s8("string.special")) ||
- s8eq(cname, s8("string.special.path")) ||
- s8eq(cname, s8("text.title")) || s8eq(cname, s8("text.uri")) ||
- s8eq(cname, s8("string.special.uri"))) {
+ } else if (match_cname(cname, "string") || match_cname(cname, "text")) {
highlight = true;
color = Color_Green;
- } else if (s8eq(cname, s8("constant"))) {
+ } else if (match_cname(cname, "constant")) {
highlight = true;
color = Color_Yellow;
- } else if (s8eq(cname, s8("attribute"))) {
+ } else if (match_cname(cname, "attribute")) {
highlight = true;
color = Color_Yellow;
- } else if (s8eq(cname, s8("number"))) {
+ } else if (match_cname(cname, "number")) {
highlight = true;
color = Color_Yellow;
- } else if (s8eq(cname, s8("function")) ||
- s8eq(cname, s8("function.macro")) ||
- s8eq(cname, s8("function.method")) ||
- s8eq(cname, s8("function.builtin")) ||
- s8eq(cname, s8("function.signal")) ||
- s8eq(cname, s8("function.special"))) {
+ } else if (match_cname(cname, "function")) {
highlight = true;
color = Color_Yellow;
- } else if (s8eq(cname, s8("property"))) {
+ } else if (match_cname(cname, "property")) {
highlight = false;
- } else if (s8eq(cname, s8("label"))) {
+ } else if (match_cname(cname, "label")) {
highlight = false;
- } else if (s8eq(cname, s8("type")) || s8eq(cname, s8("type.builtin"))) {
+ } else if (match_cname(cname, "type")) {
highlight = true;
color = Color_Cyan;
- } else if (s8eq(cname, s8("variable")) ||
- s8eq(cname, s8("variable.builtin")) ||
- s8eq(cname, s8("variable.parameter"))) {
+ } else if (match_cname(cname, "variable")) {
highlight = false;
- } else if (s8eq(cname, s8("comment"))) {
+ } else if (match_cname(cname, "comment")) {
highlight = true;
color = Color_BrightBlack;
}
@@ -524,6 +561,12 @@ static void create_parser(struct buffer *buffer, void *userdata) {
hl->tree = ts_parser_parse(hl->parser, NULL, i);
hl->query = setup_queries(lang_root, hl->tree);
+ if (hl->query == NULL) {
+ ts_parser_delete(hl->parser);
+ free((void *)lang_root);
+ return;
+ }
+
VEC_INIT(&hl->predicates, 8);
uint32_t npatterns = ts_query_pattern_count(hl->query);
for (uint32_t pi = 0; pi < npatterns; ++pi) {
@@ -549,14 +592,26 @@ void syntax_init(uint32_t grammar_path_len, const char *grammar_path[]) {
treesitter_path[i] = strdup(grammar_path[i]);
}
- // TODO: check that it exists
+ // special-case some of the built-in languages
+ // that have grammar names different from the default
struct language l = lang_from_id("gitcommit");
- lang_setting_set_default(&l, "grammar",
- (struct setting_value){.type = Setting_String,
- .string_value = "gitcommit"});
+ if (!lang_is_fundamental(&l)) {
+ lang_setting_set_default(
+ &l, "grammar",
+ (struct setting_value){.type = Setting_String,
+ .string_value = "gitcommit"});
+ lang_destroy(&l);
+ }
+
+ l = lang_from_id("cxx");
+ if (!lang_is_fundamental(&l)) {
+ lang_setting_set_default(
+ &l, "grammar",
+ (struct setting_value){.type = Setting_String, .string_value = "cpp"});
+ lang_destroy(&l);
+ }
buffer_add_create_hook(create_parser, NULL);
- lang_destroy(&l);
}
void syntax_teardown() {
diff --git a/src/main/main.c b/src/main/main.c
index d0d118b..b96edd4 100644
--- a/src/main/main.c
+++ b/src/main/main.c
@@ -214,6 +214,11 @@ int main(int argc, char *argv[]) {
#ifdef SYNTAX_ENABLE
char *treesitter_path_env = getenv("TREESITTER_GRAMMARS");
+ struct setting *path_setting = settings_get("editor.grammars-path");
+ char *settings_path = NULL;
+ if (path_setting != NULL && path_setting->value.type == Setting_String) {
+ settings_path = path_setting->value.string_value;
+ }
const char *builtin_path = join_path(xstr(DATADIR), "grammars");
const char *treesitter_path[256] = {0};
@@ -229,6 +234,16 @@ int main(int argc, char *argv[]) {
}
}
+ if (settings_path != NULL) {
+ settings_path = strdup(settings_path);
+ char *result = strtok(settings_path, ":");
+ while (result != NULL && treesitter_path_len < 256) {
+ treesitter_path[treesitter_path_len] = result;
+ ++treesitter_path_len;
+ result = strtok(NULL, ":");
+ }
+ }
+
if (treesitter_path_len < 256) {
treesitter_path[treesitter_path_len] = builtin_path;
++treesitter_path_len;
@@ -239,6 +254,9 @@ int main(int argc, char *argv[]) {
if (treesitter_path_env != NULL) {
free((void *)treesitter_path_env);
}
+ if (settings_path != NULL) {
+ free((void *)settings_path);
+ }
free((void *)builtin_path);
#endif