diff --git a/.gitmodules b/.gitmodules index 0aa2eba..8f192f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -54,18 +54,87 @@ path = libs/tree-sitter-bash url = https://github.com/tree-sitter/tree-sitter-bash.git ignore = dirty -[submodule "libs/tree-sitter-markdown"] - path = libs/tree-sitter-markdown - url = https://github.com/tree-sitter-grammars/tree-sitter-markdown [submodule "libs/tree-sitter-make"] path = libs/tree-sitter-make url = https://github.com/tree-sitter-grammars/tree-sitter-make + ignore = dirty [submodule "libs/tree-sitter-lua"] path = libs/tree-sitter-lua url = https://github.com/tree-sitter-grammars/tree-sitter-lua + ignore = dirty [submodule "libs/tree-sitter-fish"] path = libs/tree-sitter-fish url = https://github.com/ram02z/tree-sitter-fish + ignore = dirty [submodule "libs/tree-sitter-rust"] path = libs/tree-sitter-rust url = https://github.com/tree-sitter/tree-sitter-rust.git + ignore = dirty +[submodule "libs/tree-sitter-nginx"] + path = libs/tree-sitter-nginx + url = https://gitlab.com/joncoole/tree-sitter-nginx + ignore = dirty +[submodule "libs/tree-sitter-yaml"] + path = libs/tree-sitter-yaml + url = https://github.com/tree-sitter-grammars/tree-sitter-yaml.git + ignore = dirty +[submodule "libs/tree-sitter-gdscript"] + path = libs/tree-sitter-gdscript + url = https://github.com/PrestonKnopp/tree-sitter-gdscript + ignore = dirty +[submodule "libs/tree-sitter-ini"] + path = libs/tree-sitter-ini + url = https://github.com/justinmk/tree-sitter-ini + ignore = dirty +[submodule "libs/tree-sitter-php"] + path = libs/tree-sitter-php + url = https://github.com/tree-sitter/tree-sitter-php + ignore = dirty +[submodule "libs/tree-sitter-query"] + path = libs/tree-sitter-query + url = https://github.com/tree-sitter-grammars/tree-sitter-query + ignore = dirty +[submodule "libs/tree-sitter-cabal"] + path = libs/tree-sitter-cabal + url = https://gitlab.com/magus/tree-sitter-cabal + ignore = dirty +[submodule "libs/tree-sitter-go-mod"] + path = libs/tree-sitter-go-mod + url = https://github.com/camdencheek/tree-sitter-go-mod + ignore = dirty +[submodule "libs/tree-sitter-gitattributes"] + path = libs/tree-sitter-gitattributes + url = https://github.com/tree-sitter-grammars/tree-sitter-gitattributes + ignore = dirty +[submodule "libs/tree-sitter-gitignore"] + path = libs/tree-sitter-gitignore + url = https://github.com/shunsambongi/tree-sitter-gitignore + ignore = dirty +[submodule "libs/tree-sitter-diff"] + path = libs/tree-sitter-diff + url = https://github.com/tree-sitter-grammars/tree-sitter-diff + ignore = dirty +[submodule "libs/tree-sitter-regex"] + path = libs/tree-sitter-regex + url = https://github.com/tree-sitter/tree-sitter-regex + ignore = dirty +[submodule "libs/tree-sitter-embedded-template"] + path = libs/tree-sitter-embedded-template + url = https://github.com/tree-sitter/tree-sitter-embedded-template + ignore = dirty +[submodule "libs/tree-sitter-sql"] + path = libs/tree-sitter-sql + url = https://github.com/DerekStride/tree-sitter-sql.git + ignore = dirty +[submodule "libs/libs/tree-sitter-yaml"] + path = libs/libs/tree-sitter-yaml + url = https://github.com/tree-sitter-grammars/tree-sitter-yaml.git + ignore = dirty +[submodule "libs/tree-sitter-toml"] + path = libs/tree-sitter-toml + url = https://github.com/tree-sitter-grammars/tree-sitter-toml.git + ignore = dirty +[submodule "libs/tree-sitter-markdown"] + path = libs/tree-sitter-markdown + url = https://github.com/tree-sitter-grammars/tree-sitter-markdown.git + ignore = dirty diff --git a/Makefile b/Makefile index d934fcb..430875a 100644 --- a/Makefile +++ b/Makefile @@ -31,15 +31,35 @@ UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_ UNICODE_OBJ_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC)) TREE_SITTER_LIBS := $(wildcard libs/tree-sitter-*/libtree-sitter*.a) + +PHP_LIB := libs/tree-sitter-php/php/libtree-sitter-php.a + FISH_OBJ_PARSER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/parser.o FISH_OBJ_SCANNER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/scanner.o +NGINX_OBJ_PARSER := libs/tree-sitter-nginx/build/Release/obj.target/tree_sitter_nginx_binding/src/parser.o + +CABAL_OBJ_PARSER := libs/tree-sitter-cabal/build/Release/obj.target/tree_sitter_cabal_binding/src/parser.o +CABAL_OBJ_SCANNER := libs/tree-sitter-cabal/src/scanner.o + +GITIGNORE_OBJ_PARSER := libs/tree-sitter-gitignore/build/Release/obj.target/tree_sitter_ignore_binding/src/parser.o + +MD_OBJ_PARSER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown/src/parser.o +MD_OBJ_SCANNER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown/src/scanner.o + LIBS := \ libs/libgrapheme/libgrapheme.a \ libs/tree-sitter/libtree-sitter.a \ $(TREE_SITTER_LIBS) \ + $(PHP_LIB) \ + $(NGINX_OBJ_PARSER) \ + $(GITIGNORE_OBJ_PARSER) \ $(FISH_OBJ_PARSER) \ + $(CABAL_OBJ_PARSER) \ + $(CABAL_OBJ_SCANNER) \ $(FISH_OBJ_SCANNER) \ + $(MD_OBJ_PARSER) \ + $(MD_OBJ_SCANNER) \ -lpcre2-8 -lmagic SRC := $(wildcard $(SRC_DIR)/*.cc) diff --git a/README.md b/README.md index 25a799f..1318c0b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ A TUI IDE. # TODO +- [ ] Get all tree-sitter grammars needed and write down their scm files. - [ ] Add support for LSP & autocomplete / snippets. - First research - `textDocument/documentHighlight` - for highlighting stuff (probably tree-sitter is enough) diff --git a/include/editor.h b/include/editor.h index 5404190..550c79b 100644 --- a/include/editor.h +++ b/include/editor.h @@ -223,7 +223,8 @@ void apply_edit(std::vector &spans, uint32_t x, int64_t y); void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows); void apply_hook_deletion(Editor *editor, uint32_t removal_start, uint32_t removal_end); -Editor *new_editor(const char *filename, Coord position, Coord size); +Editor *new_editor(const char *filename_arg, Coord position, Coord size); +void save_file(Editor *editor); void free_editor(Editor *editor); void render_editor(Editor *editor); void fold(Editor *editor, uint32_t start_line, uint32_t end_line); diff --git a/include/maps.h b/include/maps.h index b666a8a..0f2968f 100644 --- a/include/maps.h +++ b/include/maps.h @@ -4,7 +4,22 @@ #include "./lsp.h" #include "./pch.h" #include "./ts_def.h" -#include + +static const std::unordered_map kLsps = { + {1, + {"clangd", + { + "clangd", + "--background-index", + "--clang-tidy", + "--completion-style=detailed", + "--header-insertion=never", + "--pch-storage=memory", + "--limit-results=50", + "--log=error", + nullptr, + }}}, +}; static const std::unordered_map kLanguages = { {"bash", {"bash", LANG(bash)}}, @@ -22,29 +37,67 @@ static const std::unordered_map kLanguages = { {"make", {"make", LANG(make)}}, {"python", {"python", LANG(python)}}, {"ruby", {"ruby", LANG(ruby)}}, -}; - -static const std::unordered_map kLsps = { - {1, - {"clangd", - { - "clangd", - "--background-index", - "--clang-tidy", - "--completion-style=detailed", - "--header-insertion=iwyu", - "--log=error", - nullptr, - }}}, + {"diff", {"diff", LANG(diff)}}, + {"embedded_template", {"embedded_template", LANG(embedded_template)}}, + {"gdscript", {"gdscript", LANG(gdscript)}}, + {"gitattributes", {"gitattributes", LANG(gitattributes)}}, + {"gitignore", {"gitignore", LANG(gitignore)}}, + {"gomod", {"gomod", LANG(gomod)}}, + {"ini", {"ini", LANG(ini)}}, + {"markdown", {"markdown", LANG(markdown)}}, + {"nginx", {"nginx", LANG(nginx)}}, + {"php", {"php", LANG(php)}}, + {"query", {"query", LANG(query)}}, + {"regex", {"regex", LANG(regex)}}, + {"sql", {"sql", LANG(sql)}}, + {"toml", {"toml", LANG(toml)}}, + {"yaml", {"yaml", LANG(yaml)}}, + {"cabal", {"cabal", LANG(cabal)}}, }; static const std::unordered_map kExtToLang = { - {"sh", "bash"}, {"bash", "bash"}, {"c", "c"}, {"cpp", "cpp"}, - {"cxx", "cpp"}, {"cc", "cpp"}, {"hpp", "h"}, {"hh", "h"}, - {"hxx", "h"}, {"h", "h"}, {"css", "css"}, {"fish", "fish"}, - {"go", "go"}, {"hs", "haskell"}, {"html", "html"}, {"htm", "html"}, - {"js", "javascript"}, {"json", "json"}, {"lua", "lua"}, {"mk", "make"}, - {"makefile", "make"}, {"py", "python"}, {"rb", "ruby"}, + {"sh", "bash"}, + {"bash", "bash"}, + {"c", "c"}, + {"cpp", "cpp"}, + {"cxx", "cpp"}, + {"cc", "cpp"}, + {"hpp", "h"}, + {"hh", "h"}, + {"hxx", "h"}, + {"h", "h"}, + {"css", "css"}, + {"fish", "fish"}, + {"go", "go"}, + {"hs", "haskell"}, + {"html", "html"}, + {"htm", "html"}, + {"js", "javascript"}, + {"json", "json"}, + {"lua", "lua"}, + {"mk", "make"}, + {"makefile", "make"}, + {"py", "python"}, + {"rb", "ruby"}, + {"diff", "diff"}, + {"erb", "embedded_template"}, + {"etlua", "embedded_template"}, + {"gd", "gdscript"}, + {"gitattributes", "gitattributes"}, + {"gitignore", "gitignore"}, + {"mod", "gomod"}, + {"ini", "ini"}, + {"md", "markdown"}, + {"markdown", "markdown"}, + {"conf", "nginx"}, + {"php", "php"}, + {"scm", "query"}, + {"regex", "regex"}, + {"sql", "sql"}, + {"toml", "toml"}, + {"yaml", "yaml"}, + {"yml", "yaml"}, + {"cabal", "cabal"}, }; static const std::unordered_map kMimeToLang = { @@ -60,6 +113,22 @@ static const std::unordered_map kMimeToLang = { {"text/x-go", "go"}, {"text/x-haskell", "haskell"}, {"text/x-lua", "lua"}, + {"text/x-diff", "diff"}, + {"text/x-embedded-template", "embedded_template"}, + {"text/x-gdscript", "gdscript"}, + {"text/x-gitattributes", "gitattributes"}, + {"text/x-gitignore", "gitignore"}, + {"text/x-gomod", "gomod"}, + {"text/x-ini", "ini"}, + {"text/markdown", "markdown"}, + {"text/x-nginx-conf", "nginx"}, + {"application/x-php", "php"}, + {"text/x-tree-sitter-query", "query"}, + {"text/x-regex", "regex"}, + {"text/x-sql", "sql"}, + {"text/x-toml", "toml"}, + {"text/x-yaml", "yaml"}, + {"text/x-cabal", "cabal"}, }; #endif diff --git a/include/ts_def.h b/include/ts_def.h index 7afa358..6fa6f69 100644 --- a/include/ts_def.h +++ b/include/ts_def.h @@ -4,7 +4,7 @@ #include "./pch.h" #define LANG(name) tree_sitter_##name -#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)(); +#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)() struct Language { std::string name; @@ -12,27 +12,36 @@ struct Language { uint8_t lsp_id = 0; }; -TS_DEF(bash) -TS_DEF(c) -TS_DEF(cpp) -TS_DEF(css) -TS_DEF(fish) -TS_DEF(go) -TS_DEF(haskell) -TS_DEF(html) -TS_DEF(javascript) -TS_DEF(json) -TS_DEF(lua) -TS_DEF(make) -TS_DEF(python) -TS_DEF(ruby) -TS_DEF(rust) - -// TO ADD -// sql -// wasm -// conf -// yaml, toml -// godot +TS_DEF(bash); +TS_DEF(c); +TS_DEF(cpp); +TS_DEF(css); +TS_DEF(fish); +TS_DEF(go); +TS_DEF(haskell); +TS_DEF(html); +TS_DEF(javascript); +TS_DEF(json); +TS_DEF(lua); +TS_DEF(make); +TS_DEF(python); +TS_DEF(ruby); +TS_DEF(rust); +TS_DEF(diff); +TS_DEF(embedded_template); +TS_DEF(gdscript); +TS_DEF(gitattributes); +TS_DEF(gitignore); +TS_DEF(gomod); +TS_DEF(ini); +TS_DEF(markdown); +TS_DEF(nginx); +TS_DEF(php); +TS_DEF(query); +TS_DEF(regex); +TS_DEF(sql); +TS_DEF(toml); +TS_DEF(yaml); +TS_DEF(cabal); #endif diff --git a/include/utils.h b/include/utils.h index 23230fb..611ac33 100644 --- a/include/utils.h +++ b/include/utils.h @@ -52,6 +52,7 @@ struct Coord { bool operator>=(const Coord &other) const { return !(*this < other); } }; +std::string path_abs(const std::string &path_str); std::string path_to_file_uri(const std::string &path_str); int display_width(const char *str, size_t len); uint32_t get_visual_col_from_bytes(const char *line, uint32_t len, diff --git a/libs/tree-sitter-cabal b/libs/tree-sitter-cabal new file mode 160000 index 0000000..d1105d9 --- /dev/null +++ b/libs/tree-sitter-cabal @@ -0,0 +1 @@ +Subproject commit d1105d9ed6156e4329e0dd92fddf1ea0adc933c6 diff --git a/libs/tree-sitter-diff b/libs/tree-sitter-diff new file mode 160000 index 0000000..2520c3f --- /dev/null +++ b/libs/tree-sitter-diff @@ -0,0 +1 @@ +Subproject commit 2520c3f934b3179bb540d23e0ef45f75304b5fed diff --git a/libs/tree-sitter-embedded-template b/libs/tree-sitter-embedded-template new file mode 160000 index 0000000..3499d85 --- /dev/null +++ b/libs/tree-sitter-embedded-template @@ -0,0 +1 @@ +Subproject commit 3499d85f0a0d937c507a4a65368f2f63772786e1 diff --git a/libs/tree-sitter-gdscript b/libs/tree-sitter-gdscript new file mode 160000 index 0000000..89e66b6 --- /dev/null +++ b/libs/tree-sitter-gdscript @@ -0,0 +1 @@ +Subproject commit 89e66b6bdc002ab976283f277cbb48b780c5d0e9 diff --git a/libs/tree-sitter-gitattributes b/libs/tree-sitter-gitattributes new file mode 160000 index 0000000..1b7af09 --- /dev/null +++ b/libs/tree-sitter-gitattributes @@ -0,0 +1 @@ +Subproject commit 1b7af09d45b579f9f288453b95ad555f1f431645 diff --git a/libs/tree-sitter-gitignore b/libs/tree-sitter-gitignore new file mode 160000 index 0000000..f4685bf --- /dev/null +++ b/libs/tree-sitter-gitignore @@ -0,0 +1 @@ +Subproject commit f4685bf11ac466dd278449bcfe5fd014e94aa504 diff --git a/libs/tree-sitter-go-mod b/libs/tree-sitter-go-mod new file mode 160000 index 0000000..2e88687 --- /dev/null +++ b/libs/tree-sitter-go-mod @@ -0,0 +1 @@ +Subproject commit 2e886870578eeba1927a2dc4bd2e2b3f598c5f9a diff --git a/libs/tree-sitter-ini b/libs/tree-sitter-ini new file mode 160000 index 0000000..e4018b5 --- /dev/null +++ b/libs/tree-sitter-ini @@ -0,0 +1 @@ +Subproject commit e4018b5176132b4f3c5d6e61cea383f42288d0f5 diff --git a/libs/tree-sitter-markdown b/libs/tree-sitter-markdown new file mode 160000 index 0000000..2dfd57f --- /dev/null +++ b/libs/tree-sitter-markdown @@ -0,0 +1 @@ +Subproject commit 2dfd57f547f06ca5631a80f601e129d73fc8e9f0 diff --git a/libs/tree-sitter-nginx b/libs/tree-sitter-nginx new file mode 160000 index 0000000..f6d13cf --- /dev/null +++ b/libs/tree-sitter-nginx @@ -0,0 +1 @@ +Subproject commit f6d13cf6281b25f2ce342a49a41a10a0381e00f0 diff --git a/libs/tree-sitter-php b/libs/tree-sitter-php new file mode 160000 index 0000000..7d07b41 --- /dev/null +++ b/libs/tree-sitter-php @@ -0,0 +1 @@ +Subproject commit 7d07b41ce2d442ca9a90ed85d0075eccc17ae315 diff --git a/libs/tree-sitter-query b/libs/tree-sitter-query new file mode 160000 index 0000000..a4e379d --- /dev/null +++ b/libs/tree-sitter-query @@ -0,0 +1 @@ +Subproject commit a4e379d4a4b77a09e91c1c9e12d4b898214f990e diff --git a/libs/tree-sitter-regex b/libs/tree-sitter-regex new file mode 160000 index 0000000..b2ac15e --- /dev/null +++ b/libs/tree-sitter-regex @@ -0,0 +1 @@ +Subproject commit b2ac15e27fce703d2f37a79ccd94a5c0cbe9720b diff --git a/libs/tree-sitter-sql b/libs/tree-sitter-sql new file mode 160000 index 0000000..2d5dcd1 --- /dev/null +++ b/libs/tree-sitter-sql @@ -0,0 +1 @@ +Subproject commit 2d5dcd16f9ee49cb5a6d99eabb00fd4ea298587f diff --git a/libs/tree-sitter-toml b/libs/tree-sitter-toml new file mode 160000 index 0000000..64b5683 --- /dev/null +++ b/libs/tree-sitter-toml @@ -0,0 +1 @@ +Subproject commit 64b56832c2cffe41758f28e05c756a3a98d16f41 diff --git a/libs/tree-sitter-yaml b/libs/tree-sitter-yaml new file mode 160000 index 0000000..7708026 --- /dev/null +++ b/libs/tree-sitter-yaml @@ -0,0 +1 @@ +Subproject commit 7708026449bed86239b1cd5bce6e3c34dbca6415 diff --git a/src/editor.cc b/src/editor.cc index d052c73..8078f05 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -6,12 +6,13 @@ extern "C" { #include "../include/main.h" #include "../include/utils.h" -Editor *new_editor(const char *filename, Coord position, Coord size) { +Editor *new_editor(const char *filename_arg, Coord position, Coord size) { Editor *editor = new Editor(); if (!editor) return nullptr; uint32_t len = 0; - char *str = load_file(filename, &len); + std::string filename = path_abs(filename_arg); + char *str = load_file(filename.c_str(), &len); if (!str) { free_editor(editor); return nullptr; @@ -23,7 +24,7 @@ Editor *new_editor(const char *filename, Coord position, Coord size) { editor->cursor_preffered = UINT32_MAX; editor->root = load(str, len, optimal_chunk_size(len)); free(str); - Language language = language_for_file(filename); + Language language = language_for_file(filename.c_str()); if (language.name != "unknown" && len <= (1024 * 128)) { editor->ts.parser = ts_parser_new(); editor->ts.language = language.fn(); @@ -57,6 +58,17 @@ void free_editor(Editor *editor) { delete editor; } +void save_file(Editor *editor) { + if (!editor || !editor->root) + return; + char *str = read(editor->root, 0, editor->root->char_count); + if (!str) + return; + std::ofstream out(editor->filename); + out.write(str, editor->root->char_count); + free(str); +} + void render_editor(Editor *editor) { uint32_t sel_start = 0, sel_end = 0; uint32_t numlen = diff --git a/src/editor_events.cc b/src/editor_events.cc index ae9181e..709bab4 100644 --- a/src/editor_events.cc +++ b/src/editor_events.cc @@ -2,6 +2,7 @@ #include "../include/main.h" #include "../include/ts.h" #include +#include void handle_editor_event(Editor *editor, KeyEvent event) { static std::chrono::steady_clock::time_point last_click_time = @@ -294,6 +295,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) { case ',': dedent_line(editor, editor->cursor.row); break; + case CTRL('s'): + save_file(editor); + break; case 'p': uint32_t len; char *text = get_from_clipboard(&len); diff --git a/src/utils.cc b/src/utils.cc index b00080a..82bf929 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -21,11 +21,14 @@ static std::string percent_encode(const std::string &s) { return out; } -std::string path_to_file_uri(const std::string &path_str) { +std::string path_abs(const std::string &path_str) { namespace fs = std::filesystem; fs::path p = fs::weakly_canonical(fs::absolute(fs::path(path_str))); - std::string generic = p.generic_string(); - return "file://" + percent_encode(generic); + return p.generic_string(); +} + +std::string path_to_file_uri(const std::string &path_str) { + return "file://" + percent_encode(path_abs(path_str)); } uint64_t fnv1a_64(const char *s, size_t len) {