Compare commits

...

9 Commits

98 changed files with 11238 additions and 672 deletions

78
.gitmodules vendored
View File

@@ -14,10 +14,6 @@
path = libs/tree-sitter-ruby path = libs/tree-sitter-ruby
url = https://github.com/tree-sitter/tree-sitter-ruby.git url = https://github.com/tree-sitter/tree-sitter-ruby.git
ignore = dirty ignore = dirty
[submodule "libs/tree-sitter-c"]
path = libs/tree-sitter-c
url = https://github.com/tree-sitter/tree-sitter-c.git
ignore = dirty
[submodule "libs/tree-sitter-cpp"] [submodule "libs/tree-sitter-cpp"]
path = libs/tree-sitter-cpp path = libs/tree-sitter-cpp
url = https://github.com/tree-sitter/tree-sitter-cpp.git url = https://github.com/tree-sitter/tree-sitter-cpp.git
@@ -54,15 +50,83 @@
path = libs/tree-sitter-bash path = libs/tree-sitter-bash
url = https://github.com/tree-sitter/tree-sitter-bash.git url = https://github.com/tree-sitter/tree-sitter-bash.git
ignore = dirty 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"] [submodule "libs/tree-sitter-make"]
path = libs/tree-sitter-make path = libs/tree-sitter-make
url = https://github.com/tree-sitter-grammars/tree-sitter-make url = https://github.com/tree-sitter-grammars/tree-sitter-make
ignore = dirty
[submodule "libs/tree-sitter-lua"] [submodule "libs/tree-sitter-lua"]
path = libs/tree-sitter-lua path = libs/tree-sitter-lua
url = https://github.com/tree-sitter-grammars/tree-sitter-lua url = https://github.com/tree-sitter-grammars/tree-sitter-lua
ignore = dirty
[submodule "libs/tree-sitter-fish"] [submodule "libs/tree-sitter-fish"]
path = libs/tree-sitter-fish path = libs/tree-sitter-fish
url = https://github.com/ram02z/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-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

View File

@@ -1,10 +1,14 @@
SRC_DIR := src SRC_DIR := src
BIN_DIR := bin BIN_DIR := bin
OBJ_DIR := build OBJ_DIR := build
INCLUDE_DIR := include
TARGET_DEBUG := $(BIN_DIR)/crib-dbg TARGET_DEBUG := $(BIN_DIR)/crib-dbg
TARGET_RELEASE := $(BIN_DIR)/crib TARGET_RELEASE := $(BIN_DIR)/crib
PCH_DEBUG := $(OBJ_DIR)/debug/pch.h.gch
PCH_RELEASE := $(OBJ_DIR)/release/pch.h.gch
CCACHE := ccache CCACHE := ccache
CXX_DEBUG := $(CCACHE) g++ CXX_DEBUG := $(CCACHE) g++
CXX_RELEASE := $(CCACHE) clang++ CXX_RELEASE := $(CCACHE) clang++
@@ -18,21 +22,44 @@ CFLAGS_RELEASE := -std=c++20 -O3 -march=native -flto=thin \
-mllvm -vectorize-loops \ -mllvm -vectorize-loops \
-fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-asynchronous-unwind-tables
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
UNICODE_SRC := $(wildcard libs/unicode_width/*.c) UNICODE_SRC := $(wildcard libs/unicode_width/*.c)
UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_width/%.o,$(UNICODE_SRC)) UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_width/%.o,$(UNICODE_SRC))
UNICODE_OBJ_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC)) 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) TREE_SITTER_LIBS := $(wildcard libs/tree-sitter-*/libtree-sitter*.a)
PHP_LIB := libs/tree-sitter-php/php/libtree-sitter-php.a
NGINX_OBJ_PARSER := libs/tree-sitter-nginx/build/Release/obj.target/tree_sitter_nginx_binding/src/parser.o
GITIGNORE_OBJ_PARSER := libs/tree-sitter-gitignore/build/Release/obj.target/tree_sitter_ignore_binding/src/parser.o
FISH_OBJ_PARSER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/parser.o 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 FISH_OBJ_SCANNER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/scanner.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
MD_I_OBJ_PARSER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown-inline/src/parser.o
MD_I_OBJ_SCANNER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown-inline/src/scanner.o
LIBS := \ LIBS := \
libs/libgrapheme/libgrapheme.a \ libs/libgrapheme/libgrapheme.a \
libs/tree-sitter/libtree-sitter.a \ libs/tree-sitter/libtree-sitter.a \
$(TREE_SITTER_LIBS) \ $(TREE_SITTER_LIBS) \
$(PHP_LIB) \
$(NGINX_OBJ_PARSER) \
$(GITIGNORE_OBJ_PARSER) \
$(FISH_OBJ_PARSER) \ $(FISH_OBJ_PARSER) \
$(FISH_OBJ_SCANNER) \ $(FISH_OBJ_SCANNER) \
$(MD_OBJ_PARSER) \
$(MD_OBJ_SCANNER) \
$(MD_I_OBJ_PARSER) \
$(MD_I_OBJ_SCANNER) \
-lpcre2-8 -lmagic -lpcre2-8 -lmagic
SRC := $(wildcard $(SRC_DIR)/*.cc) SRC := $(wildcard $(SRC_DIR)/*.cc)
@@ -50,21 +77,29 @@ test: $(TARGET_DEBUG)
release: $(TARGET_RELEASE) release: $(TARGET_RELEASE)
$(TARGET_DEBUG): $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(PCH_DEBUG): $(INCLUDE_DIR)/pch.h
mkdir -p $(BIN_DIR)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -o $@ $^ $(LIBS)
$(TARGET_RELEASE): $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -o $@ $^ $(LIBS)
$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@ $(CXX_DEBUG) $(PCH_CFLAGS_DEBUG) -o $@ $<
$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE): $(INCLUDE_DIR)/pch.h
mkdir -p $(dir $@) mkdir -p $(dir $@)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@ $(CXX_RELEASE) $(PCH_CFLAGS_RELEASE) -o $@ $<
$(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG)
mkdir -p $(BIN_DIR)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS)
$(TARGET_RELEASE): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -o $@ $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(LIBS)
$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc $(PCH_DEBUG)
mkdir -p $(dir $@)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE)
mkdir -p $(dir $@)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/debug/unicode_width/%.o: libs/unicode_width/%.c $(OBJ_DIR)/debug/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@) mkdir -p $(dir $@)

View File

@@ -6,8 +6,7 @@ A TUI IDE.
# TODO # TODO
- [ ] Add a virtual text support (text that is rendered in the editor but not in the actual text) - [ ] Get lsp warnings byte offsets/lengths and render them as background color.
- Add a whitespace highlighter (nerd font). for spaces and tabs at start/end of line. as a test.
- [ ] Add support for LSP & autocomplete / snippets. - [ ] Add support for LSP & autocomplete / snippets.
- First research - First research
- `textDocument/documentHighlight` - for highlighting stuff (probably tree-sitter is enough) - `textDocument/documentHighlight` - for highlighting stuff (probably tree-sitter is enough)
@@ -21,6 +20,7 @@ A TUI IDE.
- `textDocument/foldingRange` - i will never use this for folding but it might be useful for other things. - `textDocument/foldingRange` - i will never use this for folding but it might be useful for other things.
- `textDocument/rename` & `textDocument/prepareRename` - probably useful - `textDocument/rename` & `textDocument/prepareRename` - probably useful
- And a lot more (just go through each for `clangd` and then expand to say `solargraph`). - And a lot more (just go through each for `clangd` and then expand to say `solargraph`).
- Make incremental edits apply. // make a bool field in LSP qhich says if it supports incremental and based on it apply edits
- Make a universal plug for lsp. So focus more on making a general purpose solid communication interface. Instead of something specific. - Make a universal plug for lsp. So focus more on making a general purpose solid communication interface. Instead of something specific.
- With a 4ish pass system. (more like each returned value from the lsp is used in 4 ways) - With a 4ish pass system. (more like each returned value from the lsp is used in 4 ways)
1. One for stuff like jump to x position. or rename symbol x to y. (stuff that explicitly requires user request to do something) 1. One for stuff like jump to x position. or rename symbol x to y. (stuff that explicitly requires user request to do something)
@@ -28,6 +28,12 @@ A TUI IDE.
2. One for stuff that only affects highlighting and styles . like symbol highlighting etc. 2. One for stuff that only affects highlighting and styles . like symbol highlighting etc.
3. One for Warnings/errors and inlay hints etc. (stuff that adds virtual text to the editor) 3. One for Warnings/errors and inlay hints etc. (stuff that adds virtual text to the editor)
4. One for fromatting and stuff like that. (stuff that edits the buffer text) 4. One for fromatting and stuff like that. (stuff that edits the buffer text)
- [ ] Make tree sitter spans truly incremental - or atleast make them pos based and not byte so minor changes only shifts inline
- And make inner trees incremental too
- [ ] Use LSP to add inlay hints in order to test virtual text. then make an iterator over screen that mimics the renderer for scrolling functions.
- [ ] Add codeium/copilot support for auto-completion (uses the VAI virtual text) as a test phase.
- [ ] Add a whitespace highlighter (nerd font). for spaces and tabs at start/end of line. not as virtual but instead at render time.
- [ ] Once renderer is proven to work well (i.e. redo this commit) merge `experimental` branch into `main`. commit `43f443e` on `experimental`.
- [ ] Add snippets from wherever i get them. (like luasnip or vsnip) - [ ] Add snippets from wherever i get them. (like luasnip or vsnip)
- [ ] Add this thing where select at end of screen scrolls down. (and vice versa) - [ ] Add this thing where select at end of screen scrolls down. (and vice versa)
- Can be acheived by updating `main.cc` to send drag events to the selected editor instead of just under cursor. - Can be acheived by updating `main.cc` to send drag events to the selected editor instead of just under cursor.
@@ -38,7 +44,6 @@ A TUI IDE.
- [ ] Add support for undo/redo. - [ ] Add support for undo/redo.
- [ ] Add `.scm` files for all the supported languages. (2/14) Done. - [ ] Add `.scm` files for all the supported languages. (2/14) Done.
- [ ] Add splash screen / minigame jumping. - [ ] Add splash screen / minigame jumping.
- [ ] Add codeium/copilot support.
- [ ] Normalize / validate unicode on file open. - [ ] Normalize / validate unicode on file open.
- [ ] Add git stuff. - [ ] Add git stuff.
- [ ] Add SQL support. (viewer and basic editor) - [ ] Add SQL support. (viewer and basic editor)
@@ -51,3 +56,4 @@ A TUI IDE.
- [ ] Add this thing where selection double click on a bracket selects whole block. - [ ] Add this thing where selection double click on a bracket selects whole block.
- (only on the first time) and sets mode to `WORD`. - (only on the first time) and sets mode to `WORD`.
- [ ] Redo folding system and its relation to move_line_* functions. (Currently its a mess) - [ ] Redo folding system and its relation to move_line_* functions. (Currently its a mess)
- [ ] Make whole thing event driven and not clock driven.

View File

@@ -1,4 +1,4 @@
;; #bd9ae6 #000000 0 0 0 1 ;; #BFBDB6 #000000 0 0 0 1
[ [
"(" "("
")" ")"
@@ -12,7 +12,7 @@
"))" "))"
] @punctuation.bracket ] @punctuation.bracket
;; #bd9ae6 #000000 0 0 0 1 ;; #BFBDB6 #000000 0 0 0 1
[ [
";" ";"
";;" ";;"
@@ -21,7 +21,7 @@
"&" "&"
] @punctuation.delimiter ] @punctuation.delimiter
;; #ffffff #000000 0 1 0 1 ;; #F29668 #000000 0 1 0 1
[ [
">" ">"
">>" ">>"
@@ -49,7 +49,7 @@
"!" "!"
] @operator ] @operator
;; #aad84c #000000 0 0 0 1 ;; #AAD94C #000000 0 0 0 1
[ [
(string) (string)
(raw_string) (raw_string)
@@ -57,14 +57,14 @@
(heredoc_body) (heredoc_body)
] @string ] @string
;; #fbb152 #000000 0 0 0 1 ;; #E6C08A #000000 0 0 0 1
[ [
(heredoc_start) (heredoc_start)
(heredoc_end) (heredoc_end)
] @label ] @label
(variable_assignment (variable_assignment
(word) @string) (word) @variable)
(command (command
argument: "$" @string) ; bare dollar argument: "$" @string) ; bare dollar
@@ -72,7 +72,7 @@
(concatenation (concatenation
(word) @string) (word) @string)
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"if" "if"
"then" "then"
@@ -84,7 +84,7 @@
"esac" "esac"
] @keyword.conditional ] @keyword.conditional
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"for" "for"
"do" "do"
@@ -94,7 +94,7 @@
"while" "while"
] @keyword.repeat ] @keyword.repeat
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"declare" "declare"
"typeset" "typeset"
@@ -104,39 +104,39 @@
"unsetenv" "unsetenv"
] @keyword ] @keyword
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
"export" @keyword.import "export" @keyword.import
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
"function" @keyword.function "function" @keyword.function
;; #ebda8c #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
(special_variable_name) @constant (special_variable_name) @constant
;; #ebda8c #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
((word) @constant.builtin ((word) @constant.builtin
(#match? @constant.builtin "^(SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGBUS|SIGFPE|SIGKILL|SIGUSR1|SIGSEGV|SIGUSR2|SIGPIPE|SIGALRM|SIGTERM|SIGSTKFLT|SIGCHLD|SIGCONT|SIGSTOP|SIGTSTP|SIGTTIN|SIGTTOU|SIGURG|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGIO|SIGPWR|SIGSYS|SIGRTMIN|SIGRTMIN\+1|SIGRTMIN\+2|SIGRTMIN\+3|SIGRTMIN\+4|SIGRTMIN\+5|SIGRTMIN\+6|SIGRTMIN\+7|SIGRTMIN\+8|SIGRTMIN\+9|SIGRTMIN\+10|SIGRTMIN\+11|SIGRTMIN\+12|SIGRTMIN\+13|SIGRTMIN\+14|SIGRTMIN\+15|SIGRTMAX\-14|SIGRTMAX\-13|SIGRTMAX\-12|SIGRTMAX\-11|SIGRTMAX\-10|SIGRTMAX\-9|SIGRTMAX\-8|SIGRTMAX\-7|SIGRTMAX\-6|SIGRTMAX\-5|SIGRTMAX\-4|SIGRTMAX\-3|SIGRTMAX\-2|SIGRTMAX\-1|SIGRTMAX)$")) (#match? @constant.builtin "^(SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGBUS|SIGFPE|SIGKILL|SIGUSR1|SIGSEGV|SIGUSR2|SIGPIPE|SIGALRM|SIGTERM|SIGSTKFLT|SIGCHLD|SIGCONT|SIGSTOP|SIGTSTP|SIGTTIN|SIGTTOU|SIGURG|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGIO|SIGPWR|SIGSYS|SIGRTMIN|SIGRTMIN\+1|SIGRTMIN\+2|SIGRTMIN\+3|SIGRTMIN\+4|SIGRTMIN\+5|SIGRTMIN\+6|SIGRTMIN\+7|SIGRTMIN\+8|SIGRTMIN\+9|SIGRTMIN\+10|SIGRTMIN\+11|SIGRTMIN\+12|SIGRTMIN\+13|SIGRTMIN\+14|SIGRTMIN\+15|SIGRTMAX\-14|SIGRTMAX\-13|SIGRTMAX\-12|SIGRTMAX\-11|SIGRTMAX\-10|SIGRTMAX\-9|SIGRTMAX\-8|SIGRTMAX\-7|SIGRTMAX\-6|SIGRTMAX\-5|SIGRTMAX\-4|SIGRTMAX\-3|SIGRTMAX\-2|SIGRTMAX\-1|SIGRTMAX)$"))
;; #51eeba #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
((word) @boolean.true ((word) @boolean.true
(#match? @boolean.true "^true$")) (#match? @boolean.true "^true$"))
;; #ee513a #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
((word) @boolean.false ((word) @boolean.false
(#match? @boolean.false "^false$")) (#match? @boolean.false "^false$"))
;; #AAAAAA #000000 0 1 0 1 ;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell (comment) @comment @spell
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
(test_operator) @operator (test_operator) @operator
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(command_substitution (command_substitution
"$(" @punctuation.special "$(" @punctuation.special
")" @punctuation.special) ")" @punctuation.special)
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(process_substitution (process_substitution
[ [
"<(" "<("
@@ -144,7 +144,7 @@
] @punctuation.special ] @punctuation.special
")" @punctuation.special) ")" @punctuation.special)
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(arithmetic_expansion (arithmetic_expansion
[ [
"$((" "$(("
@@ -152,43 +152,43 @@
] @punctuation.special ] @punctuation.special
"))" @punctuation.special) "))" @punctuation.special)
;; #bd9ae6 #000000 0 0 0 1 ;; #BFBDB6 #000000 0 0 0 1
(arithmetic_expansion (arithmetic_expansion
"," @punctuation.delimiter) "," @punctuation.delimiter)
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
(ternary_expression (ternary_expression
[ [
"?" "?"
":" ":"
] @keyword.conditional.ternary) ] @keyword.conditional.ternary)
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
(binary_expression (binary_expression
operator: _ @operator) operator: _ @operator)
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
(unary_expression (unary_expression
operator: _ @operator) operator: _ @operator)
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
(postfix_expression (postfix_expression
operator: _ @operator) operator: _ @operator)
;; #aad84c #000000 0 0 0 3 ;; #FFB454 #000000 0 0 0 3
(function_definition (function_definition
name: (word) @function) name: (word) @function)
;; #aad84c #000000 0 0 0 3 ;; #FFB454 #000000 0 0 0 3
(command_name (command_name
(word) @function.call) (word) @function.call)
;; #aad84c #000000 0 0 0 3 ;; #FFB454 #000000 0 0 0 3
(command_name (command_name
(word) @function.builtin (word) @function.builtin
(#match? @function.builtin "^(\.|\:|alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|compopt|continue|coproc|dirs|disown|echo|enable|eval|exec|exit|false|fc|fg|getopts|hash|help|history|jobs|kill|let|logout|mapfile|popd|printf|pushd|pwd|read|readarray|return|set|shift|shopt|source|suspend|test|time|times|trap|true|type|typeset|ulimit|umask|unalias|wait)$")) (#match? @function.builtin "^(\.|\:|alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|compopt|continue|coproc|dirs|disown|echo|enable|eval|exec|exit|false|fc|fg|getopts|hash|help|history|jobs|kill|let|logout|mapfile|popd|printf|pushd|pwd|read|readarray|return|set|shift|shopt|source|suspend|test|time|times|trap|true|type|typeset|ulimit|umask|unalias|wait)$"))
;; #ffffff #000000 0 0 0 1 ;; #FFFFFF #000000 0 0 0 1
(command (command
argument: [ argument: [
(word) @variable.parameter (word) @variable.parameter
@@ -196,83 +196,240 @@
(word) @variable.parameter) (word) @variable.parameter)
]) ])
;; #ffffff #000000 0 0 0 1 ;; #FFFFFF #000000 0 0 0 1
(declaration_command (declaration_command
(word) @variable.parameter) (word) @variable.parameter)
;; #ffffff #000000 0 0 0 1 ;; #FFFFFF #000000 0 0 0 1
(unset_command (unset_command
(word) @variable.parameter) (word) @variable.parameter)
;; #ebda8c #000000 0 0 0 2 ;; #D2A6FF #000000 0 0 0 2
(number) @number (number) @number
;; #ebda8c #000000 0 0 0 2 ;; #D2A6FF #000000 0 0 0 2
((word) @number ((word) @number
(#match? @number "^[0-9]+$")) (#match? @number "^[0-9]+$"))
;; #aad84c #000000 0 0 0 1 ;; #AAD94C #000000 0 0 0 1
(file_redirect (file_redirect
(word) @string.special.path) (word) @string.special.path)
;; #aad84c #000000 0 0 0 1 ;; #AAD94C #000000 0 0 0 1
(herestring_redirect (herestring_redirect
(word) @string) (word) @string)
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
(file_descriptor) @operator (file_descriptor) @operator
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(simple_expansion (simple_expansion
"$" @punctuation.special) @none "$" @punctuation.special) @none
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(expansion (expansion
"${" @punctuation.special "${" @punctuation.special
"}" @punctuation.special) @none "}" @punctuation.special) @none
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(expansion (expansion
operator: _ @punctuation.special) operator: _ @punctuation.special)
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(expansion (expansion
"@" "@"
. .
operator: _ @character.special) operator: _ @character.special)
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
((expansion ((expansion
(subscript (subscript
index: (word) @character.special)) index: (word) @character.special))
(#any-of? @character.special "@" "*")) (#any-of? @character.special "@" "*"))
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
"``" @punctuation.special "``" @punctuation.special
;; #ffffff #000000 0 0 0 1 ;; #FFFFFF #000000 0 0 0 1
(variable_name) @variable (variable_name) @variable
;; #ebda8c #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
((variable_name) @constant ((variable_name) @constant
(#match? @constant "^[A-Z][A-Z_0-9]*$")) (#match? @constant "^[A-Z][A-Z_0-9]*$"))
;; #ffffff #000000 0 0 0 1 ;; #F07178 #000000 0 0 0 1
((variable_name) @variable.builtin ((variable_name) @variable.builtin
(#match? @variable.builtin "^(CDPATH|HOME|IFS|MAIL|MAILPATH|OPTARG|OPTIND|PATH|PS1|PS2|_|BASH|BASHOPTS|BASHPID|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_ARGV0|BASH_CMDS|BASH_COMMAND|BASH_COMPAT|BASH_ENV|BASH_EXECUTION_STRING|BASH_LINENO|BASH_LOADABLES_PATH|BASH_REMATCH|BASH_SOURCE|BASH_SUBSHELL|BASH_VERSINFO|BASH_VERSION|BASH_XTRACEFD|CHILD_MAX|COLUMNS|COMP_CWORD|COMP_LINE|COMP_POINT|COMP_TYPE|COMP_KEY|COMP_WORDBREAKS|COMP_WORDS|COMPREPLY|COPROC|DIRSTACK|EMACS|ENV|EPOCHREALTIME|EPOCHSECONDS|EUID|EXECIGNORE|FCEDIT|FIGNORE|FUNCNAME|FUNCNEST|GLOBIGNORE|GROUPS|histchars|HISTCMD|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTIGNORE|HISTSIZE|HISTTIMEFORMAT|HOSTFILE|HOSTNAME|HOSTTYPE|IGNOREEOF|INPUTRC|INSIDE_EMACS|LANG|LC_ALL|LC_COLLATE|LC_CTYPE|LC_MESSAGES|LC_NUMERIC|LC_TIME|LINENO|LINES|MACHTYPE|MAILCHECK|MAPFILE|OLDPWD|OPTERR|OSTYPE|PIPESTATUS|POSIXLY_CORRECT|PPID|PROMPT_COMMAND|PROMPT_DIRTRIM|PS0|PS3|PS4|PWD|RANDOM|READLINE_ARGUMENT|READLINE_LINE|READLINE_MARK|READLINE_POINT|REPLY|SECONDS|SHELL|SHELLOPTS|SHLVL|SRANDOM|TIMEFORMAT|TMOUT|TMPDIR|UID)$")) (#match? @variable.builtin "^(CDPATH|HOME|IFS|MAIL|MAILPATH|OPTARG|OPTIND|PATH|PS1|PS2|_|BASH|BASHOPTS|BASHPID|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_ARGV0|BASH_CMDS|BASH_COMMAND|BASH_COMPAT|BASH_ENV|BASH_EXECUTION_STRING|BASH_LINENO|BASH_LOADABLES_PATH|BASH_REMATCH|BASH_SOURCE|BASH_SUBSHELL|BASH_VERSINFO|BASH_VERSION|BASH_XTRACEFD|CHILD_MAX|COLUMNS|COMP_CWORD|COMP_LINE|COMP_POINT|COMP_TYPE|COMP_KEY|COMP_WORDBREAKS|COMP_WORDS|COMPREPLY|COPROC|DIRSTACK|EMACS|ENV|EPOCHREALTIME|EPOCHSECONDS|EUID|EXECIGNORE|FCEDIT|FIGNORE|FUNCNAME|FUNCNEST|GLOBIGNORE|GROUPS|histchars|HISTCMD|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTIGNORE|HISTSIZE|HISTTIMEFORMAT|HOSTFILE|HOSTNAME|HOSTTYPE|IGNOREEOF|INPUTRC|INSIDE_EMACS|LANG|LC_ALL|LC_COLLATE|LC_CTYPE|LC_MESSAGES|LC_NUMERIC|LC_TIME|LINENO|LINES|MACHTYPE|MAILCHECK|MAPFILE|OLDPWD|OPTERR|OSTYPE|PIPESTATUS|POSIXLY_CORRECT|PPID|PROMPT_COMMAND|PROMPT_DIRTRIM|PS0|PS3|PS4|PWD|RANDOM|READLINE_ARGUMENT|READLINE_LINE|READLINE_MARK|READLINE_POINT|REPLY|SECONDS|SHELL|SHELLOPTS|SHLVL|SRANDOM|TIMEFORMAT|TMOUT|TMPDIR|UID)$"))
;; #ffffff #000000 0 0 0 1 ;; #FFFFFF #000000 0 0 0 1
(case_item (case_item
value: (word) @variable.parameter) value: (word) @variable.parameter)
;; #e6a24c #000000 0 0 0 2 ;; #AAD94C #000000 0 0 0 3
((program
.
(comment) @keyword.directive @nospell)
(#match? @keyword.directive "^#!/"))
; Injections
;; !regex
[ [
(regex) (regex)
(extglob_pattern) (extglob_pattern)
] @string.regexp ] @string.regexp
;; #51eeba #000000 0 0 0 3 ;; !bash
((program ((heredoc_body) @bash_injection
. ((heredoc_end) @lang
(comment) @keyword.directive @nospell) (#match? @lang "BASH")))
(#match? @keyword.directive "^#!/"))
;; !c
((heredoc_body) @c_injection
((heredoc_end) @lang
(#match? @lang "C$")))
;; !cpp
((heredoc_body) @cpp_injection
((heredoc_end) @lang
(#match? @lang "CPP")))
;; !css
((heredoc_body) @css_injection
((heredoc_end) @lang
(#match? @lang "CSS")))
;; !fish
((heredoc_body) @fish_injection
((heredoc_end) @lang
(#match? @lang "FISH")))
;; !go
((heredoc_body) @go_injection
((heredoc_end) @lang
(#match? @lang "GO")))
;; !haskell
((heredoc_body) @haskell_injection
((heredoc_end) @lang
(#match? @lang "HASKELL")))
;; !html
((heredoc_body) @html_injection
((heredoc_end) @lang
(#match? @lang "HTML")))
;; !javascript
((heredoc_body) @javascript_injection
((heredoc_end) @lang
(#match? @lang "JAVASCRIPT")))
;; !json
((heredoc_body) @json_injection
((heredoc_end) @lang
(#match? @lang "JSON")))
;; !lua
((heredoc_body) @lua_injection
((heredoc_end) @lang
(#match? @lang "LUA")))
;; !make
((heredoc_body) @make_injection
((heredoc_end) @lang
(#match? @lang "MAKE")))
;; !python
((heredoc_body) @python_injection
((heredoc_end) @lang
(#match? @lang "PYTHON")))
;; !ruby
((heredoc_body) @ruby_injection
((heredoc_end) @lang
(#match? @lang "RUBY")))
;; !rust
((heredoc_body) @rust_injection
((heredoc_end) @lang
(#match? @lang "RUST")))
;; !diff
((heredoc_body) @diff_injection
((heredoc_end) @lang
(#match? @lang "DIFF")))
;; !embedded_template
((heredoc_body) @embedded_template_injection
((heredoc_end) @lang
(#match? @lang "ERB")))
;; !gdscript
((heredoc_body) @gdscript_injection
((heredoc_end) @lang
(#match? @lang "GDSCRIPT")))
;; !gitattributes
((heredoc_body) @gitattributes_injection
((heredoc_end) @lang
(#match? @lang "GITATTRIBUTES")))
;; !gitignore
((heredoc_body) @gitignore_injection
((heredoc_end) @lang
(#match? @lang "GITIGNORE")))
;; !gomod
((heredoc_body) @gomod_injection
((heredoc_end) @lang
(#match? @lang "GOMOD")))
;; !ini
((heredoc_body) @ini_injection
((heredoc_end) @lang
(#match? @lang "INI")))
;; !markdown
((heredoc_body) @markdown_injection
((heredoc_end) @lang
(#match? @lang "MARKDOWN")))
;; !nginx
((heredoc_body) @nginx_injection
((heredoc_end) @lang
(#match? @lang "NGINX")))
;; !php
((heredoc_body) @php_injection
((heredoc_end) @lang
(#match? @lang "PHP")))
;; !query
((heredoc_body) @query_injection
((heredoc_end) @lang
(#match? @lang "QUERY")))
;; !regex
((heredoc_body) @regex_injection
((heredoc_end) @lang
(#match? @lang "REGEX")))
;; !sql
((heredoc_body) @sql_injection
((heredoc_end) @lang
(#match? @lang "SQL")))
;; !toml
((heredoc_body) @toml_injection
((heredoc_end) @lang
(#match? @lang "TOML")))
;; !yaml
((heredoc_body) @yaml_injection
((heredoc_end) @lang
(#match? @lang "YAML")))
;; !cabal
((heredoc_body) @cabal_injection
((heredoc_end) @lang
(#match? @lang "CABAL")))

579
grammar/c.scm Normal file
View File

@@ -0,0 +1,579 @@
; ============================================================
; Identifiers
; ============================================================
;; #FFFFFF #000000 0 0 0 1
((identifier) @variable)
;; #FFB870 #000000 0 0 0 9
(function_declarator
declarator: (identifier) @function)
;; #C4B5FF #000000 0 0 0 2
((identifier) @constant
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
;; #C4B5FF #000000 0 0 0 2
(preproc_def
(preproc_arg) @constant
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
;; #F29CC3 #000000 0 0 0 2
((identifier) @constant.builtin
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
;; #F29CC3 #000000 0 0 0 2
(preproc_def
(preproc_arg) @constant.builtin
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
;; #8AD5FF #000000 0 0 0 2
(preproc_def
(preproc_arg) @variable)
;; #8AD5FF #000000 0 0 0 2
(statement_identifier) @label
;; #8AD5FF #000000 0 0 0 2
(declaration
type: (type_identifier) @_type
declarator: (identifier) @label
(#match? @_type "^__label__$"))
;; #7CD5CF #000000 0 0 0 2
((identifier) @variable.member
(#match? @variable.member "^m_.*$"))
; ============================================================
; Keywords
; ============================================================
;; #9AD4FF #000000 0 0 0 2
[
"default"
"goto"
"asm"
"__asm__"
] @keyword
;; #9AD4FF #000000 0 0 0 2
[
"enum"
"struct"
"union"
"typedef"
] @keyword.type
;; #F29CC3 #000000 0 0 0 2
[
"sizeof"
"offsetof"
] @keyword.operator
;; #F29CC3 #000000 0 0 0 2
(alignof_expression
.
_ @keyword.operator)
;; #FFB870 #000000 0 0 0 2
"return" @keyword.return
;; #9AD4FF #000000 0 0 0 2
[
"while"
"for"
"do"
"continue"
"break"
] @keyword.repeat
;; #FFB870 #000000 0 0 0 2
[
"if"
"else"
"case"
"switch"
] @keyword.conditional
;; #9AD4FF #000000 0 0 0 2
(conditional_expression
[
"?"
":"
] @keyword.conditional.ternary)
;; #8AD5FF #000000 0 0 0 2
[
"#if"
"#ifdef"
"#ifndef"
"#else"
"#elif"
"#endif"
"#elifdef"
"#elifndef"
(preproc_directive)
] @keyword.directive
;; #8AD5FF #000000 0 0 0 2
"#define" @keyword.directive.define
;; #8AD5FF #000000 0 0 0 2
"#include" @keyword.import
;; #9AD4FF #000000 0 0 0 2
[
"try"
"catch"
"noexcept"
"throw"
] @keyword.exception
;; #9AD4FF #000000 0 0 0 2
[
"decltype"
"explicit"
"friend"
"override"
"using"
"requires"
"constexpr"
] @keyword
;; #9AD4FF #000000 0 0 0 2
[
"class"
"namespace"
"template"
"typename"
"concept"
] @keyword.type
;; #9AD4FF #000000 0 0 0 2
[
"co_await"
"co_yield"
"co_return"
] @keyword.coroutine
;; #F29CC3 #000000 0 0 0 2
[
"public"
"private"
"protected"
"final"
"virtual"
] @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
(storage_class_specifier) @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
[
(type_qualifier)
(gnu_asm_qualifier)
"__extension__"
] @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
(linkage_specification
"extern" @keyword.modifier)
;; #F29668 #000000 0 0 0 2
[
"new"
"delete"
"xor"
"bitand"
"bitor"
"compl"
"not"
"xor_eq"
"and_eq"
"or_eq"
"not_eq"
"and"
"or"
] @keyword.operator
;; #F29668 #000000 0 1 0 2
"<=>" @operator
; ============================================================
; Types & modules
; ============================================================
;; #C4B5FF #000000 0 0 0 2
[
(type_identifier)
(type_descriptor)
] @type
;; #C4B5FF #000000 0 0 0 2
(type_definition
declarator: (type_identifier) @type.definition)
;; #C4B5FF #000000 0 0 0 2
(primitive_type) @type.builtin
;; #C4B5FF #000000 0 0 0 2
(sized_type_specifier
_ @type.builtin
type: _?)
;; #C4B5FF #000000 0 0 0 2
(type_definition declarator: (type_identifier) @name) @definition.type
;; #C4B5FF #000000 0 0 0 2
(enum_specifier name: (type_identifier) @name) @definition.type
;; #C4B5FF #000000 0 0 0 2
(class_specifier name: (type_identifier) @name) @definition.class
;; #C4B5FF #000000 0 0 0 2
(struct_specifier name: (type_identifier) @name body:(_)) @definition.class
;; #C4B5FF #000000 0 0 0 2
(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class
;; #9AD4FF #000000 0 0 0 2
(namespace_identifier) @module
;; #9AD4FF #000000 0 0 0 2
((namespace_identifier) @type
(#match? @type "^[A-Z]"))
;; #9AD4FF #000000 0 0 0 2
(using_declaration
.
"using"
.
"namespace"
.
[
(qualified_identifier)
(identifier)
] @module)
; ============================================================
; Functions & calls
; ============================================================
;; #FFB870 #000000 0 0 0 1
(operator_name) @function
;; #FFB870 #000000 0 0 0 3
"operator" @function
;; #78C2FF #000000 0 0 0 2
(call_expression
function: (identifier) @function.call)
;; #F29CC3 #000000 0 0 0 2
((call_expression
function: (identifier) @function.builtin)
(#match? @function.builtin "^__builtin_"))
;; #F29CC3 #000000 0 0 0 2
((call_expression
function: (identifier) @function.builtin))
; ============================================================
; Constructors & methods
; ============================================================
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (identifier) @constructor)
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (qualified_identifier
name: (identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (field_expression
field: (field_identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((field_initializer
(field_identifier) @constructor
(argument_list))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 4
(destructor_name
(identifier) @function.method)
; ============================================================
; Properties & members
; ============================================================
;; #F29CC3 #000000 0 0 0 2
((field_expression
(field_identifier) @property) @_parent)
(field_designator) @property
((field_identifier) @property)
(field_initializer
(field_identifier) @property)
;; #F29CC3 #000000 0 0 1 2
(field_declaration
(field_identifier) @variable.member)
; ============================================================
; Parameters
; ============================================================
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (identifier) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (array_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (pointer_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(preproc_params
(identifier) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (reference_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(variadic_parameter_declaration
declarator: (variadic_declarator
(_) @variable.parameter))
;; #7CD5CF #000000 0 0 0 2
(optional_parameter_declaration
declarator: (_) @variable.parameter)
; ============================================================
; Attributes & specifiers
; ============================================================
;; #7CD5CF #000000 0 0 0 2
[
"__attribute__"
"__declspec"
"__based"
"__cdecl"
"__clrcall"
"__stdcall"
"__fastcall"
"__thiscall"
"__vectorcall"
(ms_pointer_modifier)
(attribute_declaration)
] @attribute
;; #7CD5CF #000000 0 0 0 2
(attribute_specifier
(argument_list
(identifier) @variable.builtin))
;; #7CD5CF #000000 0 0 0 2
(attribute_specifier
(argument_list
(call_expression
function: (identifier) @variable.builtin)))
; ============================================================
; Operators & punctuation
; ============================================================
;; #F29668 #000000 0 1 0 1
[
"="
"-"
"*"
"/"
"+"
"%"
"~"
"|"
"&"
"^"
"<<"
">>"
"->"
"<"
"<="
">="
">"
"=="
"!="
"!"
"&&"
"||"
"-="
"+="
"*="
"/="
"%="
"|="
"&="
"^="
">>="
"<<="
"--"
"++"
] @operator
;; #F29668 #000000 0 1 0 1
(comma_expression
"," @operator)
;; #B6BEC8 #000000 0 0 0 1
[
";"
":"
","
"."
"::"
] @punctuation.delimiter
;; #B6BEC8 #000000 0 0 0 1
"::" @punctuation.delimiter
;; #B6BEC8 #000000 0 0 0 1
"..." @punctuation.special
;; #B6BEC8 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
;; #B6BEC8 #000000 0 0 0 1
(template_argument_list
[
"<"
">"
] @punctuation.bracket)
;; #B6BEC8 #000000 0 0 0 1
(template_parameter_list
[
"<"
">"
] @punctuation.bracket)
; ============================================================
; Literals
; ============================================================
;; #C2E8FF #000000 0 0 0 2
[
(true)
(false)
] @boolean
;; #C2E8FF #000000 0 0 0 2
(true) @boolean_true
;; #C2E8FF #000000 0 0 0 2
(false) @boolean_false
;; #A6E3A1 #000000 0 0 0 2
(string_literal) @string
;; #A6E3A1 #000000 0 0 0 2
(system_lib_string) @string
;; #A6E3A1 #000000 0 0 0 2
(raw_string_literal) @string
;; #A6E3A1 #000000 0 0 0 2
(escape_sequence) @string.escape
;; #B8E986 #000000 0 0 0 2
(number_literal) @number
;; #B8E986 #000000 0 0 0 2
(char_literal) @character
;; #F29CC3 #000000 0 0 0 2
(null) @constant.builtin
;; #F29CC3 #000000 0 0 0 2
(null
"nullptr" @constant.builtin)
; ============================================================
; Macros & directives
; ============================================================
;; #F29CC3 #000000 0 0 0 2
(preproc_def
name: (_) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_call
directive: (preproc_directive) @_u
argument: (_) @constant.macro
(#match? @_u "^#undef$"))
;; #F29CC3 #000000 0 0 0 2
(preproc_ifdef
name: (identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_elifdef
name: (identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_defined
(identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_defined) @function.macro
; ============================================================
; Builtins & special identifiers
; ============================================================
;; #F28FAD #000000 0 0 0 2
(attribute_specifier
(argument_list
(identifier) @variable.builtin))
;; #F28FAD #000000 0 0 0 2
(attribute_specifier
(argument_list
(call_expression
function: (identifier) @variable.builtin)))
;; #F28FAD #000000 0 0 0 2
(this) @variable.builtin
; ============================================================
; Exceptions & control helpers
; ============================================================
;; #FFB870 #000000 0 0 0 2
"static_assert" @function.builtin
; ============================================================
; Comments
; ============================================================
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell

579
grammar/cpp.scm Normal file
View File

@@ -0,0 +1,579 @@
; ============================================================
; Identifiers
; ============================================================
;; #FFFFFF #000000 0 0 0 1
((identifier) @variable)
;; #FFB870 #000000 0 0 0 9
(function_declarator
declarator: (identifier) @function)
;; #C4B5FF #000000 0 0 0 2
((identifier) @constant
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
;; #C4B5FF #000000 0 0 0 2
(preproc_def
(preproc_arg) @constant
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
;; #F29CC3 #000000 0 0 0 2
((identifier) @constant.builtin
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
;; #F29CC3 #000000 0 0 0 2
(preproc_def
(preproc_arg) @constant.builtin
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
;; #8AD5FF #000000 0 0 0 2
(preproc_def
(preproc_arg) @variable)
;; #8AD5FF #000000 0 0 0 2
(statement_identifier) @label
;; #8AD5FF #000000 0 0 0 2
(declaration
type: (type_identifier) @_type
declarator: (identifier) @label
(#match? @_type "^__label__$"))
;; #7CD5CF #000000 0 0 0 2
((identifier) @variable.member
(#match? @variable.member "^m_.*$"))
; ============================================================
; Keywords
; ============================================================
;; #9AD4FF #000000 0 0 0 2
[
"default"
"goto"
"asm"
"__asm__"
] @keyword
;; #9AD4FF #000000 0 0 0 2
[
"enum"
"struct"
"union"
"typedef"
] @keyword.type
;; #F29CC3 #000000 0 0 0 2
[
"sizeof"
"offsetof"
] @keyword.operator
;; #F29CC3 #000000 0 0 0 2
(alignof_expression
.
_ @keyword.operator)
;; #FFB870 #000000 0 0 0 2
"return" @keyword.return
;; #9AD4FF #000000 0 0 0 2
[
"while"
"for"
"do"
"continue"
"break"
] @keyword.repeat
;; #FFB870 #000000 0 0 0 2
[
"if"
"else"
"case"
"switch"
] @keyword.conditional
;; #9AD4FF #000000 0 0 0 2
(conditional_expression
[
"?"
":"
] @keyword.conditional.ternary)
;; #8AD5FF #000000 0 0 0 2
[
"#if"
"#ifdef"
"#ifndef"
"#else"
"#elif"
"#endif"
"#elifdef"
"#elifndef"
(preproc_directive)
] @keyword.directive
;; #8AD5FF #000000 0 0 0 2
"#define" @keyword.directive.define
;; #8AD5FF #000000 0 0 0 2
"#include" @keyword.import
;; #9AD4FF #000000 0 0 0 2
[
"try"
"catch"
"noexcept"
"throw"
] @keyword.exception
;; #9AD4FF #000000 0 0 0 2
[
"decltype"
"explicit"
"friend"
"override"
"using"
"requires"
"constexpr"
] @keyword
;; #9AD4FF #000000 0 0 0 2
[
"class"
"namespace"
"template"
"typename"
"concept"
] @keyword.type
;; #9AD4FF #000000 0 0 0 2
[
"co_await"
"co_yield"
"co_return"
] @keyword.coroutine
;; #F29CC3 #000000 0 0 0 2
[
"public"
"private"
"protected"
"final"
"virtual"
] @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
(storage_class_specifier) @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
[
(type_qualifier)
(gnu_asm_qualifier)
"__extension__"
] @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
(linkage_specification
"extern" @keyword.modifier)
;; #F29668 #000000 0 0 0 2
[
"new"
"delete"
"xor"
"bitand"
"bitor"
"compl"
"not"
"xor_eq"
"and_eq"
"or_eq"
"not_eq"
"and"
"or"
] @keyword.operator
;; #F29668 #000000 0 1 0 2
"<=>" @operator
; ============================================================
; Types & modules
; ============================================================
;; #C4B5FF #000000 0 0 0 2
[
(type_identifier)
(type_descriptor)
] @type
;; #C4B5FF #000000 0 0 0 2
(type_definition
declarator: (type_identifier) @type.definition)
;; #C4B5FF #000000 0 0 0 2
(primitive_type) @type.builtin
;; #C4B5FF #000000 0 0 0 2
(sized_type_specifier
_ @type.builtin
type: _?)
;; #C4B5FF #000000 0 0 0 2
(type_definition declarator: (type_identifier) @name) @definition.type
;; #C4B5FF #000000 0 0 0 2
(enum_specifier name: (type_identifier) @name) @definition.type
;; #C4B5FF #000000 0 0 0 2
(class_specifier name: (type_identifier) @name) @definition.class
;; #C4B5FF #000000 0 0 0 2
(struct_specifier name: (type_identifier) @name body:(_)) @definition.class
;; #C4B5FF #000000 0 0 0 2
(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class
;; #9AD4FF #000000 0 0 0 2
(namespace_identifier) @module
;; #9AD4FF #000000 0 0 0 2
((namespace_identifier) @type
(#match? @type "^[A-Z]"))
;; #9AD4FF #000000 0 0 0 2
(using_declaration
.
"using"
.
"namespace"
.
[
(qualified_identifier)
(identifier)
] @module)
; ============================================================
; Functions & calls
; ============================================================
;; #FFB870 #000000 0 0 0 1
(operator_name) @function
;; #FFB870 #000000 0 0 0 3
"operator" @function
;; #78C2FF #000000 0 0 0 2
(call_expression
function: (identifier) @function.call)
;; #F29CC3 #000000 0 0 0 2
((call_expression
function: (identifier) @function.builtin)
(#match? @function.builtin "^__builtin_"))
;; #F29CC3 #000000 0 0 0 2
((call_expression
function: (identifier) @function.builtin))
; ============================================================
; Constructors & methods
; ============================================================
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (identifier) @constructor)
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (qualified_identifier
name: (identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (field_expression
field: (field_identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((field_initializer
(field_identifier) @constructor
(argument_list))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 4
(destructor_name
(identifier) @function.method)
; ============================================================
; Properties & members
; ============================================================
;; #F29CC3 #000000 0 0 0 2
((field_expression
(field_identifier) @property) @_parent)
(field_designator) @property
((field_identifier) @property)
(field_initializer
(field_identifier) @property)
;; #F29CC3 #000000 0 0 1 2
(field_declaration
(field_identifier) @variable.member)
; ============================================================
; Parameters
; ============================================================
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (identifier) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (array_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (pointer_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(preproc_params
(identifier) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (reference_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(variadic_parameter_declaration
declarator: (variadic_declarator
(_) @variable.parameter))
;; #7CD5CF #000000 0 0 0 2
(optional_parameter_declaration
declarator: (_) @variable.parameter)
; ============================================================
; Attributes & specifiers
; ============================================================
;; #7CD5CF #000000 0 0 0 2
[
"__attribute__"
"__declspec"
"__based"
"__cdecl"
"__clrcall"
"__stdcall"
"__fastcall"
"__thiscall"
"__vectorcall"
(ms_pointer_modifier)
(attribute_declaration)
] @attribute
;; #7CD5CF #000000 0 0 0 2
(attribute_specifier
(argument_list
(identifier) @variable.builtin))
;; #7CD5CF #000000 0 0 0 2
(attribute_specifier
(argument_list
(call_expression
function: (identifier) @variable.builtin)))
; ============================================================
; Operators & punctuation
; ============================================================
;; #F29668 #000000 0 1 0 1
[
"="
"-"
"*"
"/"
"+"
"%"
"~"
"|"
"&"
"^"
"<<"
">>"
"->"
"<"
"<="
">="
">"
"=="
"!="
"!"
"&&"
"||"
"-="
"+="
"*="
"/="
"%="
"|="
"&="
"^="
">>="
"<<="
"--"
"++"
] @operator
;; #F29668 #000000 0 1 0 1
(comma_expression
"," @operator)
;; #B6BEC8 #000000 0 0 0 1
[
";"
":"
","
"."
"::"
] @punctuation.delimiter
;; #B6BEC8 #000000 0 0 0 1
"::" @punctuation.delimiter
;; #B6BEC8 #000000 0 0 0 1
"..." @punctuation.special
;; #B6BEC8 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
;; #B6BEC8 #000000 0 0 0 1
(template_argument_list
[
"<"
">"
] @punctuation.bracket)
;; #B6BEC8 #000000 0 0 0 1
(template_parameter_list
[
"<"
">"
] @punctuation.bracket)
; ============================================================
; Literals
; ============================================================
;; #C2E8FF #000000 0 0 0 2
[
(true)
(false)
] @boolean
;; #C2E8FF #000000 0 0 0 2
(true) @boolean_true
;; #C2E8FF #000000 0 0 0 2
(false) @boolean_false
;; #A6E3A1 #000000 0 0 0 2
(string_literal) @string
;; #A6E3A1 #000000 0 0 0 2
(system_lib_string) @string
;; #A6E3A1 #000000 0 0 0 2
(raw_string_literal) @string
;; #A6E3A1 #000000 0 0 0 2
(escape_sequence) @string.escape
;; #B8E986 #000000 0 0 0 2
(number_literal) @number
;; #B8E986 #000000 0 0 0 2
(char_literal) @character
;; #F29CC3 #000000 0 0 0 2
(null) @constant.builtin
;; #F29CC3 #000000 0 0 0 2
(null
"nullptr" @constant.builtin)
; ============================================================
; Macros & directives
; ============================================================
;; #F29CC3 #000000 0 0 0 2
(preproc_def
name: (_) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_call
directive: (preproc_directive) @_u
argument: (_) @constant.macro
(#match? @_u "^#undef$"))
;; #F29CC3 #000000 0 0 0 2
(preproc_ifdef
name: (identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_elifdef
name: (identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_defined
(identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_defined) @function.macro
; ============================================================
; Builtins & special identifiers
; ============================================================
;; #F28FAD #000000 0 0 0 2
(attribute_specifier
(argument_list
(identifier) @variable.builtin))
;; #F28FAD #000000 0 0 0 2
(attribute_specifier
(argument_list
(call_expression
function: (identifier) @variable.builtin)))
;; #F28FAD #000000 0 0 0 2
(this) @variable.builtin
; ============================================================
; Exceptions & control helpers
; ============================================================
;; #FFB870 #000000 0 0 0 2
"static_assert" @function.builtin
; ============================================================
; Comments
; ============================================================
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell

95
grammar/css.scm Normal file
View File

@@ -0,0 +1,95 @@
;; #D2A6FF #000000 0 0 0 1
(tag_name) @tag
(nesting_selector) @tag
(universal_selector) @tag
;; #F29668 #000000 0 0 0 1
"~" @operator
">" @operator
"+" @operator
"-" @operator
"*" @operator
"/" @operator
"=" @operator
"^=" @operator
"|=" @operator
"~=" @operator
"$=" @operator
"*=" @operator
"and" @operator
"or" @operator
"not" @operator
"only" @operator
;; #AAD94C #000000 0 0 0 2
(attribute_selector (plain_value) @string)
(string_value) @string
;; #FFFFFF #000000 0 0 0 1
((property_name) @variable
(#match? @variable "^--"))
((plain_value) @variable
(#match? @variable "^--"))
;; #7dcfff #000000 0 0 0 2
(class_name) @property
(id_name) @property
(namespace_name) @property
(property_name) @property
(feature_name) @property
;; #F07178 #000000 0 0 0 1
(pseudo_element_selector (tag_name) @attribute)
(pseudo_class_selector (class_name) @attribute)
(attribute_name) @attribute
;; #F07178 #000000 0 0 0 1
(function_name) @function
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #FFFFFF #000000 0 0 0 1
(color_value) @string.special
;; #FF8F40 #000000 0 0 0 1
(integer_value) @number
(float_value) @number
;; #FF8F40 #000000 0 0 0 1
(unit) @type
;; #AAD94C #000000 0 0 0 3
[
"#"
","
"."
":"
"::"
";"
] @punctuation.delimiter
;; #AAD94C #000000 0 0 0 3
[
"{"
"}"
")"
"("
"["
"]"
] @punctuation.bracket
;; #D2A6FF #000000 0 0 0 1
(at_keyword) @keyword
(to) @keyword
(from) @keyword
(important) @keyword
; This is put at the end as the regex parser will wrongly think @media is a capture name becouse of its @
; TODO: This should be fixed by not selecting if it is in a string
"@media" @keyword
"@import" @keyword
"@charset" @keyword
"@namespace" @keyword
"@supports" @keyword
"@keyframes" @keyword

57
grammar/diff.scm Normal file
View File

@@ -0,0 +1,57 @@
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #A6E3A1 #000000 0 0 0 2
(addition) @diff.plus
;; #F07178 #000000 0 0 0 2
(deletion) @diff.minus
;; #D2A6FF #000000 0 0 0 0
[
(new_file)
(old_file)
] @file
;; #D2A6FF #000000 0 0 0 1
(commit) @constant
;; #7dcfff #000000 0 0 0 2
(location) @attribute
;; #D2A6FF #000000 0 0 0 1
(command
"diff" @function
(argument) @variable.parameter)
;; #7dcfff #000000 0 0 0 6
(mode) @number
;; #888888 #000000 0 0 0 3
[
".."
"+"
"++"
"+++"
"++++"
"-"
"--"
"---"
"----"
] @punctuation.special
;; #7dcfff #000000 0 0 0 2
[
(binary_change)
(similarity)
(file_change)
] @label
;; #D2A6FF #000000 0 0 0 1
(index
"index" @keyword)
;; #FF8F40 #000000 0 0 0 1
(similarity
(score) @number
"%" @number)

View File

@@ -0,0 +1,20 @@
;; #99ADBF #000000 0 1 0 4
(comment_directive) @comment
;; #F29668 #000000 0 0 0 6
[
"<%#"
"<%"
"<%="
"<%_"
"<%-"
"%>"
"-%>"
"_%>"
] @keyword
;; !html
(content) @injection.html
;; !ruby
(code) @injection.ruby

191
grammar/fish.scm Normal file
View File

@@ -0,0 +1,191 @@
;; #F29668 #000000 0 1 0 1
[
"&&"
"||"
"|"
"&|"
"2>|"
"&"
".."
"!"
(direction)
(stream_redirect)
] @operator
(command
name: (word) @function.builtin
(#match? @function.builtin "^test$")
;; #FFFFFF #000000 0 0 0 3
argument: (word) @word
(#match? @word "^(!?=|-[a-zA-Z]+)$"))
(command
name: (word) @punctuation.bracket
(#match? @punctuation.bracket "^\\[$")
argument: (word) @word
(#match? @word "^(!?=|-[a-zA-Z]+)$"))
;; #F29668 #000000 0 0 0 1
[
"not"
"and"
"or"
] @keyword.operator
;; #FF8F40 #000000 0 0 0 1
(if_statement
[
"if"
"end"
] @keyword.conditional)
;; #FF8F40 #000000 0 0 0 1
(switch_statement
[
"switch"
"end"
] @keyword.conditional)
;; #FF8F40 #000000 0 0 0 1
(case_clause
"case" @keyword.conditional)
;; #FF8F40 #000000 0 0 0 1
(else_clause
"else" @keyword.conditional)
;; #FF8F40 #000000 0 0 0 1
(else_if_clause
[
"else"
"if"
] @keyword.conditional)
; Loops/Blocks
;; #FF8F40 #000000 0 0 0 1
(while_statement
[
"while"
"end"
] @keyword.repeat)
;; #FF8F40 #000000 0 0 0 1
(for_statement
[
"for"
"end"
] @keyword.repeat)
;; #FF8F40 #000000 0 0 0 1
(begin_statement
[
"begin"
"end"
] @keyword.repeat)
; Keywords
;; #FF8F40 #000000 0 0 0 1
[
"in"
(break)
(continue)
] @keyword
;; #FF8F40 #000000 0 0 0 1
"return" @keyword.return
;; #BFBDB6 #000000 0 0 0 1
[
"["
"]"
"{"
"}"
"("
")"
] @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
"," @punctuation.delimiter
;; #7dcfff #000000 0 0 0 2
(command_substitution
"$" @punctuation.special)
;; #FFB454 #000000 0 0 0 3
(command
name: (word) @function.call)
;; #FFB454 #000000 0 0 0 3
(command
name: (word) @function.builtin
(#match? @function.builtin
"^(\\.|:|_|abbr|alias|argparse|bg|bind|block|breakpoint|builtin|cd|command|commandline|complete|contains|count|disown|echo|emit|eval|exec|exit|fg|functions|history|isatty|jobs|math|path|printf|pwd|random|read|realpath|set|set_color|source|status|string|test|time|type|ulimit|wait)$"))
;; #FF8F40 #000000 0 0 0 1
(function_definition
[
"function"
"end"
] @keyword.function)
;; #FFB454 #000000 0 0 0 3
(function_definition
name: [
(word)
(concatenation)
] @function)
;; #FFFFFF #000000 0 0 0 1
(function_definition
option: [
(word)
(concatenation
(word))
] @variable.parameter
(#match? @variable.parameter "^[-]"))
;; #AAD94C #000000 0 0 0 1
[
(double_quote_string)
(single_quote_string)
] @string
;; #AAD94C #000000 0 0 0 1
(escape_sequence) @string.escape
;; #FFFFFF #000000 0 0 0 1
(variable_name) @variable
;; #D2A6FF #000000 0 0 0 1
(variable_expansion) @constant
;; #7dcfff #000000 0 0 0 2
(variable_expansion
"$" @punctuation.special) @none
;; #F07178 #000000 0 0 0 1
((variable_name) @variable.builtin
(#match? @variable.builtin
"^(PATH|CDPATH|LANG|LC_ALL|LC_COLLATE|LC_CTYPE|LC_MESSAGES|LC_MONETARY|LC_NUMERIC|LC_TIME|fish_color_normal|fish_color_command|fish_color_keyword|fish_color_redirection|fish_color_end|fish_color_error|fish_color_param|fish_color_valid_path|fish_color_option|fish_color_comment|fish_color_selection|fish_color_operator|fish_color_escape|fish_color_autosuggestion|fish_color_cwd|fish_color_cwd_root|fish_color_user|fish_color_host|fish_color_host_remote|fish_color_status|fish_color_cancel|fish_color_search_match|fish_color_history_current|fish_pager_color_progress|fish_pager_color_background|fish_pager_color_prefix|fish_pager_color_completion|fish_pager_color_description|fish_pager_color_selected_background|fish_pager_color_selected_prefix|fish_pager_color_selected_completion|fish_pager_color_selected_description|fish_pager_color_secondary_background|fish_pager_color_secondary_prefix|fish_pager_color_secondary_completion|fish_pager_color_secondary_description|fish_term24bit|fish_term256|fish_ambiguous_width|fish_emoji_width|fish_autosuggestion_enabled|fish_handle_reflow|fish_key_bindings|fish_escape_delay_ms|fish_sequence_key_delay_ms|fish_complete_path|fish_cursor_selection_mode|fish_cursor_default|fish_cursor_insert|fish_cursor_replace|fish_cursor_replace_one|fish_cursor_visual|fish_cursor_external|fish_function_path|fish_greeting|fish_history|fish_trace|FISH_DEBUG|FISH_DEBUG_OUTPUT|fish_user_paths|umask|BROWSER|_|argv|CMD_DURATION|COLUMNS|LINES|fish_kill_signal|fish_killring|fish_read_limit|fish_pid|history|HOME|hostname|IFS|last_pid|PWD|pipestatus|SHLVL|status|status_generation|TERM|USER|EUID|version|FISH_VERSION)$"))
;; #D2A6FF #000000 0 0 0 2
[
(integer)
(float)
] @number
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #99ADBF #000000 0 1 0 1
(comment) @spell
;; #D2A6FF #000000 0 0 0 1
((word) @boolean
(#match? @boolean "^(true|false)$"))
;; #AAD94C #000000 0 0 0 3
((program
.
(comment) @keyword.directive @nospell)
(#match? @keyword.directive "^#!"))

336
grammar/gdscript.scm Normal file

File diff suppressed because one or more lines are too long

70
grammar/gitattributes.scm Normal file
View File

@@ -0,0 +1,70 @@
;; #AAD94C #000000 0 0 0 3
(dir_sep) @punctuation.delimiter
;; #AAD94C #000000 0 0 0 3
(quoted_pattern
"\"" @punctuation.special)
;; #AAD94C #000000 0 0 0 3
(range_notation) @string.special
;; #AAD94C #000000 0 0 0 3
(range_notation
[ "[" "]" ] @punctuation.bracket)
;; #F29668 #000000 0 0 0 1
(wildcard) @string.regexp
;; #F29668 #000000 0 0 0 1
(range_negation) @operator
;; #7dcfff #000000 0 0 0 2
(character_class) @constant
;; #F29668 #000000 0 0 0 1
(class_range "-" @operator)
;; #FF8F40 #000000 0 0 0 1
[
(ansi_c_escape)
(escaped_char)
] @escape
;; #AAD94C #000000 0 0 0 3
(attribute
(attr_name) @variable.parameter)
;; #F07178 #000000 0 0 0 1
(attribute
(builtin_attr) @variable.builtin)
;; #F29668 #000000 0 0 0 1
[
(attr_reset)
(attr_unset)
(attr_set)
] @operator
;; #F29668 #000000 0 0 0 1
(boolean_value) @boolean
;; #AAD94C #000000 0 0 0 2
(string_value) @string
;; #D2A6FF #000000 0 0 0 1
(macro_tag) @keyword
;; #7dcfff #000000 0 0 0 2
(macro_def
macro_name: (_) @property)
;; #F07178 #000000 0 0 0 1
[
(pattern_negation)
(redundant_escape)
(trailing_slash)
(ignored_value)
] @error
;; #99ADBF #000000 0 1 0 1
(comment) @comment

46
grammar/gitignore.scm Normal file
View File

@@ -0,0 +1,46 @@
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #7dcfff #000000 0 0 0 2
(pattern_char) @string.special.path
;; #AAD94C #000000 0 0 0 3
[
(directory_separator)
(directory_separator_escaped)
] @punctuation.delimiter
;; #F29668 #000000 0 0 0 1
[
(wildcard_char_single)
(wildcard_chars)
(wildcard_chars_allow_slash)
] @character.special
;; #FF8F40 #000000 0 0 0 1
[
(pattern_char_escaped)
(bracket_char_escaped)
] @string.escape
;; #AAD94C #000000 0 0 0 3
(negation) @punctuation.special
;; #F07178 #000000 0 0 0 1
(bracket_negation) @operator
;; #AAD94C #000000 0 0 0 3
[
"["
"]"
] @punctuation.bracket
;; #7dcfff #000000 0 0 0 2
(bracket_char) @constant
;; #F29668 #000000 0 0 0 1
(bracket_range
"-" @operator)
;; #F07178 #000000 0 0 0 1
(bracket_char_class) @constant.builtin

286
grammar/go.scm Normal file
View File

@@ -0,0 +1,286 @@
;; #FFB454 #000000 0 0 0 3
(type_identifier) @type
;; #FFB454 #000000 0 0 0 3
(type_spec
name: (type_identifier) @type.definition)
;; #FFFFFF #000000 0 0 0 1
(field_identifier) @property
;; #FFFFFF #000000 0 0 0 1
(identifier) @variable
;; #FFFFFF #000000 0 0 0 1
(package_identifier) @module
;; #FFFFFF #000000 0 0 0 1
(parameter_declaration
(identifier) @variable.parameter)
;; #FFFFFF #000000 0 0 0 1
(variadic_parameter_declaration
(identifier) @variable.parameter)
;; #F07178 #000000 0 0 0 1
(label_name) @label
;; #D2A6FF #000000 0 0 0 1
(const_spec
name: (identifier) @constant)
;; #FFB454 #000000 0 0 0 3
(call_expression
function: (identifier) @function.call)
;; #FFB454 #000000 0 0 0 3
(call_expression
function: (selector_expression
field: (field_identifier) @function.method.call))
;; #FFB454 #000000 0 0 0 3
(function_declaration
name: (identifier) @function)
;; #FFB454 #000000 0 0 0 3
(method_declaration
name: (field_identifier) @function.method)
;; #FFB454 #000000 0 0 0 3
(method_elem
name: (field_identifier) @function.method)
;; #FFB454 #000000 0 0 0 3
((call_expression
(identifier) @constructor)
(#match? @constructor "^[nN]ew.+$"))
;; #FFB454 #000000 0 0 0 3
((call_expression
(identifier) @constructor)
(#match? @constructor "^[mM]ake.+$"))
;; #F29668 #000000 0 1 0 1
[
"--"
"-"
"-="
":="
"!"
"!="
"..."
"*"
"*="
"/"
"/="
"&"
"&&"
"&="
"&^"
"&^="
"%"
"%="
"^"
"^="
"+"
"++"
"+="
"<-"
"<"
"<<"
"<<="
"<="
"="
"=="
">"
">="
">>"
">>="
"|"
"|="
"||"
"~"
] @operator
;; #FF8F40 #000000 0 0 0 1
[
"break"
"const"
"continue"
"default"
"defer"
"goto"
"range"
"select"
"var"
"fallthrough"
] @keyword
;; #FF8F40 #000000 0 0 0 1
[
"type"
"struct"
"interface"
] @keyword.type
;; #FF8F40 #000000 0 0 0 1
"func" @keyword.function
;; #FF8F40 #000000 0 0 0 1
"return" @keyword.return
;; #FF8F40 #000000 0 0 0 1
"go" @keyword.coroutine
;; #FF8F40 #000000 0 0 0 1
"for" @keyword.repeat
;; #FF8F40 #000000 0 0 0 1
[
"import"
"package"
] @keyword.import
;; #FF8F40 #000000 0 0 0 1
[
"else"
"case"
"switch"
"if"
] @keyword.conditional
;; #F07178 #000000 0 0 0 1
[
"chan"
"map"
] @type.builtin
;; #F07178 #000000 0 0 0 1
((type_identifier) @type.builtin
(#match? @type.builtin
"^(any|bool|byte|comparable|complex128|complex64|error|float32|float64|int|int16|int32|int64|int8|rune|string|uint|uint16|uint32|uint64|uint8|uintptr)$"))
;; #FFB454 #000000 0 0 0 3
((identifier) @function.builtin
(#match? @function.builtin
"^(append|cap|clear|close|complex|copy|delete|imag|len|make|max|min|new|panic|print|println|real|recover)$"))
;; #BFBDB6 #000000 0 0 0 1
"." @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
"," @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
":" @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
";" @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
"(" @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
")" @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
"{" @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
"}" @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
"[" @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
"]" @punctuation.bracket
;; #AAD94C #000000 0 0 0 1
(interpreted_string_literal) @string
;; #AAD94C #000000 0 0 0 1
(raw_string_literal) @string
;; #AAD94C #000000 0 0 0 1
(rune_literal) @string
;; #AAD94C #000000 0 0 0 1
(escape_sequence) @string.escape
;; #D2A6FF #000000 0 0 0 2
(int_literal) @number
;; #D2A6FF #000000 0 0 0 2
(float_literal) @number.float
;; #D2A6FF #000000 0 0 0 2
(imaginary_literal) @number
;; #D2A6FF #000000 0 0 0 1
[
(true)
(false)
] @boolean
;; #D2A6FF #000000 0 0 0 1
[
(nil)
(iota)
] @constant.builtin
;; #FFFFFF #000000 0 0 0 1
(keyed_element
.
(literal_element
(identifier) @variable.member))
;; #FFFFFF #000000 0 0 0 1
(field_declaration
name: (field_identifier) @variable.member)
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #99ADBF #000000 0 1 0 1
(source_file
.
(comment)+ @comment.documentation)
;; #99ADBF #000000 0 1 0 1
(source_file
(comment)+ @comment.documentation
.
(const_declaration))
;; #99ADBF #000000 0 1 0 1
(source_file
(comment)+ @comment.documentation
.
(function_declaration))
;; #99ADBF #000000 0 1 0 1
(source_file
(comment)+ @comment.documentation
.
(type_declaration))
;; #99ADBF #000000 0 1 0 1
(source_file
(comment)+ @comment.documentation
.
(var_declaration))
;; #AAD94C #000000 0 0 0 1
(call_expression
(selector_expression) @_function
(#match? @_function
"^(regexp\.Match|regexp\.MatchReader|regexp\.MatchString|regexp\.Compile|regexp\.CompilePOSIX|regexp\.MustCompile|regexp\.MustCompilePOSIX)$")
(argument_list
.
[
;; !regex
(raw_string_literal
(raw_string_literal_content) @string.regexp)
(interpreted_string_literal
(interpreted_string_literal_content) @string.regexp)
]))

46
grammar/gomod.scm Normal file
View File

@@ -0,0 +1,46 @@
;; #D2A6FF #000000 0 0 0 1
[
"require"
"replace"
"toolchain"
"exclude"
"retract"
] @keyword
;; #F07178 #000000 0 0 0 1
[
"go"
"module"
] @keyword.directive
;; #F29668 #000000 0 1 0 1
"=>" @operator
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #7dcfff #000000 0 0 0 1
(module_path) @string.special.url
;; #D2A6FF #000000 0 0 0 1
(tool_directive) @keyword.directive
(tool) @string.special.url
;; #F29668 #000000 0 0 0 2
[
(version)
(go_version)
(toolchain_name)
] @string.special
;; #888888 #000000 0 0 0 3
[
"("
")"
"["
"]"
] @punctuation.bracket
;; #888888 #000000 0 1 0 3
"," @punctuation.delimiter

579
grammar/h.scm Normal file
View File

@@ -0,0 +1,579 @@
; ============================================================
; Identifiers
; ============================================================
;; #FFFFFF #000000 0 0 0 1
((identifier) @variable)
;; #FFB870 #000000 0 0 0 9
(function_declarator
declarator: (identifier) @function)
;; #C4B5FF #000000 0 0 0 2
((identifier) @constant
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
;; #C4B5FF #000000 0 0 0 2
(preproc_def
(preproc_arg) @constant
(#match? @constant "^[A-Z][A-Z0-9_]+$"))
;; #F29CC3 #000000 0 0 0 2
((identifier) @constant.builtin
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
;; #F29CC3 #000000 0 0 0 2
(preproc_def
(preproc_arg) @constant.builtin
(#match? @constant.builtin "^(stderr|stdin|stdout|__FILE__|__LINE__|__DATE__|__TIME__|__STDC__|__STDC_VERSION__|__STDC_HOSTED__|__cplusplus|__OBJC__|__ASSEMBLER__|__BASE_FILE__|__FILE_NAME__|__INCLUDE_LEVEL__|__TIMESTAMP__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__clang_literal_encoding__|__clang_wide_literal_encoding__|__FUNCTION__|__func__|__PRETTY_FUNCTION__|__VA_ARGS__|__VA_OPT__)$"))
;; #8AD5FF #000000 0 0 0 2
(preproc_def
(preproc_arg) @variable)
;; #8AD5FF #000000 0 0 0 2
(statement_identifier) @label
;; #8AD5FF #000000 0 0 0 2
(declaration
type: (type_identifier) @_type
declarator: (identifier) @label
(#match? @_type "^__label__$"))
;; #7CD5CF #000000 0 0 0 2
((identifier) @variable.member
(#match? @variable.member "^m_.*$"))
; ============================================================
; Keywords
; ============================================================
;; #9AD4FF #000000 0 0 0 2
[
"default"
"goto"
"asm"
"__asm__"
] @keyword
;; #9AD4FF #000000 0 0 0 2
[
"enum"
"struct"
"union"
"typedef"
] @keyword.type
;; #F29CC3 #000000 0 0 0 2
[
"sizeof"
"offsetof"
] @keyword.operator
;; #F29CC3 #000000 0 0 0 2
(alignof_expression
.
_ @keyword.operator)
;; #FFB870 #000000 0 0 0 2
"return" @keyword.return
;; #9AD4FF #000000 0 0 0 2
[
"while"
"for"
"do"
"continue"
"break"
] @keyword.repeat
;; #FFB870 #000000 0 0 0 2
[
"if"
"else"
"case"
"switch"
] @keyword.conditional
;; #9AD4FF #000000 0 0 0 2
(conditional_expression
[
"?"
":"
] @keyword.conditional.ternary)
;; #8AD5FF #000000 0 0 0 2
[
"#if"
"#ifdef"
"#ifndef"
"#else"
"#elif"
"#endif"
"#elifdef"
"#elifndef"
(preproc_directive)
] @keyword.directive
;; #8AD5FF #000000 0 0 0 2
"#define" @keyword.directive.define
;; #8AD5FF #000000 0 0 0 2
"#include" @keyword.import
;; #9AD4FF #000000 0 0 0 2
[
"try"
"catch"
"noexcept"
"throw"
] @keyword.exception
;; #9AD4FF #000000 0 0 0 2
[
"decltype"
"explicit"
"friend"
"override"
"using"
"requires"
"constexpr"
] @keyword
;; #9AD4FF #000000 0 0 0 2
[
"class"
"namespace"
"template"
"typename"
"concept"
] @keyword.type
;; #9AD4FF #000000 0 0 0 2
[
"co_await"
"co_yield"
"co_return"
] @keyword.coroutine
;; #F29CC3 #000000 0 0 0 2
[
"public"
"private"
"protected"
"final"
"virtual"
] @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
(storage_class_specifier) @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
[
(type_qualifier)
(gnu_asm_qualifier)
"__extension__"
] @keyword.modifier
;; #F29CC3 #000000 0 0 0 2
(linkage_specification
"extern" @keyword.modifier)
;; #F29668 #000000 0 0 0 2
[
"new"
"delete"
"xor"
"bitand"
"bitor"
"compl"
"not"
"xor_eq"
"and_eq"
"or_eq"
"not_eq"
"and"
"or"
] @keyword.operator
;; #F29668 #000000 0 1 0 2
"<=>" @operator
; ============================================================
; Types & modules
; ============================================================
;; #C4B5FF #000000 0 0 0 2
[
(type_identifier)
(type_descriptor)
] @type
;; #C4B5FF #000000 0 0 0 2
(type_definition
declarator: (type_identifier) @type.definition)
;; #C4B5FF #000000 0 0 0 2
(primitive_type) @type.builtin
;; #C4B5FF #000000 0 0 0 2
(sized_type_specifier
_ @type.builtin
type: _?)
;; #C4B5FF #000000 0 0 0 2
(type_definition declarator: (type_identifier) @name) @definition.type
;; #C4B5FF #000000 0 0 0 2
(enum_specifier name: (type_identifier) @name) @definition.type
;; #C4B5FF #000000 0 0 0 2
(class_specifier name: (type_identifier) @name) @definition.class
;; #C4B5FF #000000 0 0 0 2
(struct_specifier name: (type_identifier) @name body:(_)) @definition.class
;; #C4B5FF #000000 0 0 0 2
(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class
;; #9AD4FF #000000 0 0 0 2
(namespace_identifier) @module
;; #9AD4FF #000000 0 0 0 2
((namespace_identifier) @type
(#match? @type "^[A-Z]"))
;; #9AD4FF #000000 0 0 0 2
(using_declaration
.
"using"
.
"namespace"
.
[
(qualified_identifier)
(identifier)
] @module)
; ============================================================
; Functions & calls
; ============================================================
;; #FFB870 #000000 0 0 0 1
(operator_name) @function
;; #FFB870 #000000 0 0 0 3
"operator" @function
;; #78C2FF #000000 0 0 0 2
(call_expression
function: (identifier) @function.call)
;; #F29CC3 #000000 0 0 0 2
((call_expression
function: (identifier) @function.builtin)
(#match? @function.builtin "^__builtin_"))
;; #F29CC3 #000000 0 0 0 2
((call_expression
function: (identifier) @function.builtin))
; ============================================================
; Constructors & methods
; ============================================================
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (identifier) @constructor)
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (qualified_identifier
name: (identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((call_expression
function: (field_expression
field: (field_identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 2
((field_initializer
(field_identifier) @constructor
(argument_list))
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 4
(destructor_name
(identifier) @function.method)
; ============================================================
; Properties & members
; ============================================================
;; #F29CC3 #000000 0 0 0 2
((field_expression
(field_identifier) @property) @_parent)
(field_designator) @property
((field_identifier) @property)
(field_initializer
(field_identifier) @property)
;; #F29CC3 #000000 0 0 1 2
(field_declaration
(field_identifier) @variable.member)
; ============================================================
; Parameters
; ============================================================
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (identifier) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (array_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (pointer_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(preproc_params
(identifier) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(parameter_declaration
declarator: (reference_declarator) @variable.parameter)
;; #7CD5CF #000000 0 0 0 2
(variadic_parameter_declaration
declarator: (variadic_declarator
(_) @variable.parameter))
;; #7CD5CF #000000 0 0 0 2
(optional_parameter_declaration
declarator: (_) @variable.parameter)
; ============================================================
; Attributes & specifiers
; ============================================================
;; #7CD5CF #000000 0 0 0 2
[
"__attribute__"
"__declspec"
"__based"
"__cdecl"
"__clrcall"
"__stdcall"
"__fastcall"
"__thiscall"
"__vectorcall"
(ms_pointer_modifier)
(attribute_declaration)
] @attribute
;; #7CD5CF #000000 0 0 0 2
(attribute_specifier
(argument_list
(identifier) @variable.builtin))
;; #7CD5CF #000000 0 0 0 2
(attribute_specifier
(argument_list
(call_expression
function: (identifier) @variable.builtin)))
; ============================================================
; Operators & punctuation
; ============================================================
;; #F29668 #000000 0 1 0 1
[
"="
"-"
"*"
"/"
"+"
"%"
"~"
"|"
"&"
"^"
"<<"
">>"
"->"
"<"
"<="
">="
">"
"=="
"!="
"!"
"&&"
"||"
"-="
"+="
"*="
"/="
"%="
"|="
"&="
"^="
">>="
"<<="
"--"
"++"
] @operator
;; #F29668 #000000 0 1 0 1
(comma_expression
"," @operator)
;; #B6BEC8 #000000 0 0 0 1
[
";"
":"
","
"."
"::"
] @punctuation.delimiter
;; #B6BEC8 #000000 0 0 0 1
"::" @punctuation.delimiter
;; #B6BEC8 #000000 0 0 0 1
"..." @punctuation.special
;; #B6BEC8 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
;; #B6BEC8 #000000 0 0 0 1
(template_argument_list
[
"<"
">"
] @punctuation.bracket)
;; #B6BEC8 #000000 0 0 0 1
(template_parameter_list
[
"<"
">"
] @punctuation.bracket)
; ============================================================
; Literals
; ============================================================
;; #C2E8FF #000000 0 0 0 2
[
(true)
(false)
] @boolean
;; #C2E8FF #000000 0 0 0 2
(true) @boolean_true
;; #C2E8FF #000000 0 0 0 2
(false) @boolean_false
;; #A6E3A1 #000000 0 0 0 2
(string_literal) @string
;; #A6E3A1 #000000 0 0 0 2
(system_lib_string) @string
;; #A6E3A1 #000000 0 0 0 2
(raw_string_literal) @string
;; #A6E3A1 #000000 0 0 0 2
(escape_sequence) @string.escape
;; #B8E986 #000000 0 0 0 2
(number_literal) @number
;; #B8E986 #000000 0 0 0 2
(char_literal) @character
;; #F29CC3 #000000 0 0 0 2
(null) @constant.builtin
;; #F29CC3 #000000 0 0 0 2
(null
"nullptr" @constant.builtin)
; ============================================================
; Macros & directives
; ============================================================
;; #F29CC3 #000000 0 0 0 2
(preproc_def
name: (_) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_call
directive: (preproc_directive) @_u
argument: (_) @constant.macro
(#match? @_u "^#undef$"))
;; #F29CC3 #000000 0 0 0 2
(preproc_ifdef
name: (identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_elifdef
name: (identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_defined
(identifier) @constant.macro)
;; #F29CC3 #000000 0 0 0 2
(preproc_defined) @function.macro
; ============================================================
; Builtins & special identifiers
; ============================================================
;; #F28FAD #000000 0 0 0 2
(attribute_specifier
(argument_list
(identifier) @variable.builtin))
;; #F28FAD #000000 0 0 0 2
(attribute_specifier
(argument_list
(call_expression
function: (identifier) @variable.builtin)))
;; #F28FAD #000000 0 0 0 2
(this) @variable.builtin
; ============================================================
; Exceptions & control helpers
; ============================================================
;; #FFB870 #000000 0 0 0 2
"static_assert" @function.builtin
; ============================================================
; Comments
; ============================================================
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell

207
grammar/haskell.scm Normal file
View File

@@ -0,0 +1,207 @@
;; #FFFFFF #000000 0 0 0 1
(variable) @variable
;; Lambdas / patterns keep params white
;; #FFFFFF #000000 0 1 0 5
(expression/lambda
(_)+ @variable.parameter
"->")
;; #FFFFFF #000000 0 0 0 1
(decl/function
patterns: (patterns
(_) @variable.parameter))
;; #FFFFFF #000000 0 0 0 1
(decl/function
(infix
(pattern) @variable.parameter))
;; Types / builtins
;; #F07178 #000000 0 0 0 6
((name) @type.builtin
(#match? @type.builtin "^(Int|Integer|Bool|Char|String|Float|Double|Word)$"))
;; Strings / chars
;; #9ADE7A #000000 0 0 0 1
(char) @literal.char
;; #9ADE7A #000000 0 0 0 1
(string) @literal.string
;; Comments
;; #99ADBF #000000 0 1 0 5
(comment) @comment.general
;; #99ADBF #000000 0 1 0 5
(haddock) @comment.documentation
;; #99ADBF #000000 0 1 0 1
(comment) @spell
;; Punctuation
;; #BFBDB6 #000000 0 0 0 1
[
"(" ")" "{" "}" "[" "]"
] @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 1
[ "," ";" ] @punctuation.delimiter
;; Keywords (orange)
;; #FF8F40 #000000 0 0 0 1
[ "forall" ] @keyword.quantifier
;; #FF8F40 #000000 0 0 0 1
(pragma) @keyword.directive
;; #FF8F40 #000000 0 0 0 1
[
"if" "then" "else" "case" "of"
] @keyword.conditional
;; #FF8F40 #000000 0 0 0 1
[ "import" "qualified" "module" ] @keyword.import
;; #FF8F40 #000000 0 0 0 1
[
"where" "let" "in" "class" "instance" "pattern" "data"
"newtype" "family" "type" "as" "hiding" "deriving" "via"
"stock" "anyclass" "do" "mdo" "rec" "infix" "infixl" "infixr"
] @keyword.definition
;; #FF8F40 #000000 0 0 0 1
[ "forall" ] @keyword.repeat
;; Operators (italic white, high priority)
;; #FFFFFF #000000 0 1 0 6
[
(operator)
(constructor_operator)
(all_names)
"." ".." "=" "|" "::" "=>" "->" "<-" "\\" "`" "@"
] @operator.general
;; #FFFFFF #000000 0 1 0 6
(infix_id
[
(variable) @operator.infix
(qualified (variable) @operator.infix)
])
;; #FFFFFF #000000 0 1 0 6
[
(operator)
(constructor_operator)
(all_names)
(wildcard)
"." ".." "=" "|" "::" "=>" "->" "<-" "\\" "`" "@"
] @operator
;; Modules
;; #7dcfff #000000 0 0 0 1
(module
(module_id) @module.name)
;; #7dcfff #000000 0 0 0 1
(module
(module_id) @module)
;; Functions / calls (leave blue for function identifiers, but vars stay white due to higher priority var rules)
;; #82AAFF #000000 0 0 0 3
(decl/signature
[
name: (variable) @function.name
names: (binding_list (variable) @function.name)
])
;; #82AAFF #000000 0 0 0 3
(decl/function
[
name: (variable) @function.name
names: (binding_list (variable) @function.name)
])
;; #82AAFF #000000 0 0 0 3
(decl/bind
[
name: (variable) @function.name
names: (binding_list (variable) @function.name)
])
;; #82AAFF #000000 0 0 0 2
(decl
[
name: (variable) @function
names: (binding_list (variable) @function)
])
;; #82AAFF #000000 0 0 0 3
(decl/signature
name: (variable) @function.io
type: (type/apply
constructor: (name) @_io)
(#match? @_io "^IO$"))
;; Function calls kept white via var priority; ensure explicit call rule stays neutral/white
;; #FFFFFF #000000 0 0 0 3
(apply
[
(expression/variable) @function.call
(expression/qualified (variable) @function.call)
])
;; Types / constructors
;; #82AAFF #000000 0 0 0 3
(name) @type
;; #82AAFF #000000 0 0 0 3
(type/star) @type
;; #C6B5FF #000000 0 0 0 1
(constructor) @constructor.general
;; #9ADE7A #000000 0 0 0 2
((constructor) @boolean
(#match? @boolean "^(True|False)$"))
;; #9ADE7A #000000 0 0 0 1
((variable) @boolean
(#match? @boolean "^otherwise$"))
;; Quoters / quasiquotes
;; #82AAFF #000000 0 0 0 3
(quoter) @function.call
;; #9ADE7A #000000 0 0 0 1
(quasiquote
[
(quoter) @_name
(_
(variable) @_name)
]
(#match? @_name "^qq$")
(quasiquote_body) @string)
;; #9ADE7A #000000 0 0 0 1
(quasiquote
(_
(variable) @_name)
(#match? @_name "^qq$")
(quasiquote_body) @string)
;; #82AAFF #000000 0 0 0 3
(quasiquote
(_
(module) @module
.
(variable) @function.call))
;; Exceptions / Debug
;; #F07178 #000000 0 0 0 1
((variable) @keyword.exception
(#match? @keyword.exception "^(error|undefined|try|tryJust|tryAny|catch|catches|catchJust|handle|handleJust|throw|throwIO|throwTo|throwError|ioError|mask|mask_|uninterruptibleMask|uninterruptibleMask_|bracket|bracket_|bracketOnErrorSource|finally|fail|onException|expectationFailure)$"))
;; #F07178 #000000 0 0 0 1
((variable) @keyword.debug
(#match? @keyword.debug "^(trace|traceId|traceShow|traceShowId|traceWith|traceShowWith|traceStack|traceIO|traceM|traceShowM|traceEvent|traceEventWith|traceEventIO|flushEventLog|traceMarker|traceMarkerIO)$"))
;; Misc remaining structural
;; #C6B5FF #000000 0 0 0 1
(wildcard) @literal.special
;; #BFBDB6 #000000 0 0 0 1
[ "," ";" ] @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
[
"(" ")" "{" "}" "[" "]"
] @punctuation.bracket
;; #7dcfff #000000 0 0 0 1
(type/unit) @type.unit
(type/list) @type.list
(type/star) @type.star
;; #FFFFFF #000000 0 0 0 1
(field_name (variable) @variable.member)
(import_name (name) . (children (variable) @variable.member))
;; Numbers (bright yellow-green)
;; #DFFFA0 #000000 0 0 0 2
(integer) @number.integer
;; #DFFFA0 #000000 0 0 0 2
(negation) @number.integer
;; #DFFFA0 #000000 0 0 0 2
(expression/literal
(float) @number.float)

146
grammar/html.scm Normal file
View File

@@ -0,0 +1,146 @@
;; #99ADBF #000000 0 1 0 5
(comment) @comment @spell
;; #9ADE7A #000000 0 0 0 1
(attribute_name) @tag.attribute
;; #FF8F40 #000000 0 0 0 0
((attribute
(quoted_attribute_value) @string))
(attribute_value) @string
[
"'"
"\""
] @string
;; #82AAFF #000000 1 0 0 3
((element
(start_tag
(tag_name) @_tag)
(text) @markup.heading)
(#match? @_tag "^title$"))
;; #82AAFF #000000 1 0 1 3
((element
(start_tag
(tag_name) @_tag)
(text) @markup.heading.1)
(#match? @_tag "^h[1-6]$"))
;; #FFD700 #000000 1 0 0 2
((element
(start_tag
(tag_name) @_tag)
(text) @markup.strong)
(#match? @_tag "^(strong|b)$"))
;; #FF8F40 #000000 0 1 0 2
((element
(start_tag
(tag_name) @_tag)
(text) @markup.italic)
(#match? @_tag "^(em|i)$"))
;; #FF6347 #000000 0 0 1 2
((element
(start_tag
(tag_name) @_tag)
(text) @markup.strikethrough)
(#match? @_tag "^(s|del)$"))
;; #82AAFF #000000 0 0 1 2
((element
(start_tag
(tag_name) @_tag)
(text) @markup.underline)
(#match? @_tag "^u$"))
;; #9ADE7A #000000 0 0 0 2
((element
(start_tag
(tag_name) @_tag)
(text) @markup.raw)
(#match? @_tag "^(code|kbd)$"))
;; #7dcfff #000000 0 0 1 2
((element
(start_tag
(tag_name) @_tag)
(text) @markup.link.label)
(#match? @_tag "^a$"))
((attribute
(attribute_name) @_attr
(quoted_attribute_value
;; #7dcfff #000000 0 0 1 5
(attribute_value) @string.special.url))
(#match? @_attr "^(href|src)$"))
;; Punctuation
;; #BFBDB6 #000000 0 0 0 1
[
"<"
">"
"</"
"/>"
] @tag.delimiter
;; #FFFFFF #000000 0 1 0 1
"=" @operator
;; #7dcfff #000000 0 0 0 1
(tag_name) @tag
;; #FF8F40 #000000 0 0 0 1
(erroneous_end_tag_name) @tag.error
;; #FFD700 #000000 0 0 0 1
(doctype) @constant
;; #9ADE7A #000000 0 0 0 1
(attribute_name) @attribute
; Injections
((style_element
(start_tag) @_start_tag
;; !css
(raw_text) @injection.css))
((attribute
(attribute_name) @_attr
(quoted_attribute_value
(attribute_value) @injection.css))
(#match? @_attr "^style$"))
((script_element
(start_tag) @_start
;; !javascript
(raw_text) @injection.javascript)
(#match? @_start "^<script\\b(?![^>]*\\btype\\s*=\\s*\\\"(?!module|text/javascript)[^\\\"]*\\\")[^>]*>$"))
((attribute
(attribute_name) @_name
(quoted_attribute_value
(attribute_value) @injection.javascript))
(#match? @_name "^on[a-z]+$"))
((attribute
(quoted_attribute_value
(attribute_value) @injection.javascript))
(#match? @injection.javascript "\\$\\{"))
((script_element
(start_tag) @_start
;; !json
(raw_text) @injection.json)
(#match? @_start "^<script\\b(?![^>]*\\btype\\s*=\\s*\\\"(?!importmap)[^\\\"]*\\\")[^>]*>$"))
((attribute
(attribute_name) @_name
(quoted_attribute_value
;; !regex
(attribute_value) @injection.regex))
(#match? @_name "^pattern$"))

34
grammar/ini.scm Normal file
View File

@@ -0,0 +1,34 @@
;; #7dcfff #000000 0 0 0 2
(section_name
(text) @type)
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #888888 #000000 0 0 0 3
[
"["
"]"
] @punctuation.bracket
;; #F29668 #000000 0 1 0 1
"=" @operator
;; #F0F8FF #000000 0 0 0 2
(setting
(setting_name) @property)
;; #F29668 #000000 0 0 0 2
((setting_value) @boolean
(#match? @boolean "^\\s*(true|false|True|False|yes|no|Yes|No|on|off|On|Off|)\\s*$"))
;; #FF8F40 #000000 0 0 0 2
((setting_value) @number
(#match? @number "^\\s*[-+0-9]+\\s*$"))
;; #A6E3A1 #000000 0 0 0 2
((setting_value) @float
(#match? @float "^\\s*[-+0-9\\.]+\\s*$"))
;; #AAD94C #000000 0 0 0 1
(setting_value) @string

318
grammar/javascript.scm Normal file
View File

@@ -0,0 +1,318 @@
; ============================================================
; Identifiers
; ============================================================
;; #FFFFFF #000000 0 0 0 1
(identifier) @variable
;; #D2A6FF #000000 0 0 0 2
((identifier) @constant
(#match? @constant "^[A-Z_][A-Z0-9_]*$"))
;; #F07178 #000000 0 0 0 3
((identifier) @variable.builtin
(#match? @variable.builtin
"^(arguments|console|window|document|globalThis|process|module|exports)$"))
;; #59C2FF #000000 0 0 0 3
((identifier) @constructor
(#match? @constructor "^[A-Z][a-zA-Z0-9]*$"))
; ============================================================
; Properties
; ============================================================
;; #F07178 #000000 0 0 0 1
(property_identifier) @property
; ============================================================
; Functions
; ============================================================
;; #FFB454 #000000 0 0 0 3
(function_declaration
name: (identifier) @function)
(function_expression
name: (identifier) @function)
;; #FFB454 #000000 0 0 0 2
(method_definition
name: (property_identifier) @function.method)
(variable_declarator
name: (identifier) @function
value: [(function_expression) (arrow_function)])
(assignment_expression
left: (identifier) @function
right: [(function_expression) (arrow_function)])
(pair
key: (property_identifier) @function.method
value: [(function_expression) (arrow_function)])
; ------------------------------------------------------------
; Function calls
; ------------------------------------------------------------
;; #FFB454 #000000 0 0 0 2
(call_expression
function: (identifier) @function.call)
;; #FFB454 #000000 0 0 0 2
(call_expression
function: (member_expression
property: (property_identifier) @function.method))
; ============================================================
; Highlighted definitions & references
; ============================================================
;; #FFB454 #000000 0 0 0 3
(assignment_expression
left: [
(identifier) @name
(member_expression
property: (property_identifier) @name)
]
right: [(arrow_function) (function_expression)]
) @definition.function
;; #FFB454 #000000 0 0 0 3
(pair
key: (property_identifier) @name
value: [(arrow_function) (function_expression)]) @definition.function
;; #59C2FF #000000 0 0 0 2
(
(call_expression
function: (identifier) @name) @reference.call
(#not-match? @name "^(require)$")
)
;; #7dcfff #000000 0 0 0 2
(new_expression
constructor: (_) @name) @reference.class
;; #D2A6FF #000000 0 0 0 2
(export_statement value: (assignment_expression left: (identifier) @name right: ([
(number)
(string)
(identifier)
(undefined)
(null)
(new_expression)
(binary_expression)
(call_expression)
]))) @definition.constant
; ============================================================
; Parameters
; ============================================================
;; #D2A6FF #000000 0 0 0 1
(formal_parameters
[
(identifier) @variable.parameter
(array_pattern
(identifier) @variable.parameter)
(object_pattern
[
(pair_pattern value: (identifier) @variable.parameter)
(shorthand_property_identifier_pattern) @variable.parameter
])
])
; ============================================================
; Keywords (split into semantic groups)
; ============================================================
;; #FF8F40 #000000 0 0 0 1
; Declarations
[
"var"
"let"
"const"
"function"
"class"
] @keyword.declaration
;; #FF8F40 #000000 0 0 0 1
; Control flow
[
"if"
"else"
"switch"
"case"
"default"
"for"
"while"
"do"
"break"
"continue"
"return"
"throw"
"try"
"catch"
"finally"
"extends"
] @keyword.control
;; #FF8F40 #000000 0 0 0 1
; Imports / exports
[
"import"
"export"
"from"
"as"
] @keyword.import
;; #F29668 #000000 0 0 0 1
; Operators-as-keywords
[
"in"
"instanceof"
"new"
"delete"
"typeof"
"void"
"await"
"yield"
] @keyword.operator
;; #FF8F40 #000000 0 0 0 1
; Modifiers
[
"async"
"static"
"get"
"set"
] @keyword.modifier
; ============================================================
; Literals
; ============================================================
;; #F07178 #000000 0 0 0 1
(this) @variable.builtin
(super) @variable.builtin
;; #D2A6FF #000000 0 0 0 4
[
(true)
(false)
(null)
(undefined)
] @constant.builtin
;; #D2A6FF #000000 0 0 0 2
(number) @number
;; #D2A6FF #000000 0 1 0 2
((string) @use_strict
(#match? @use_strict "^['\"]use strict['\"]$"))
;; #AAD94C #000000 0 0 0 0
(string) @string
;; #AAD94C #000000 0 0 0 0
(template_string) @string.special
;; #99ADBF #000000 0 1 0 1
(comment) @comment
; ============================================================
; Operators & punctuation
; ============================================================
;; #F29668 #000000 0 1 0 1
[
"+"
"-"
"*"
"/"
"%"
"**"
"++"
"--"
"=="
"!="
"==="
"!=="
"<"
"<="
">"
">="
"&&"
"||"
"??"
"!"
"~"
"&"
"|"
"^"
"<<"
">>"
">>>"
"="
"+="
"-="
"*="
"/="
"%="
"<<="
">>="
">>>="
"&="
"|="
"^="
"&&="
"||="
"??="
"=>"
] @operator
;; #BFBDB6 #000000 0 0 0 1
[
"."
","
";"
] @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
;; #7dcfff #000000 0 0 0 2
(template_substitution
"${" @punctuation.special
"}" @punctuation.special)
; ============================================================
; JSX
; ============================================================
;; #59C2FF #000000 0 0 0 2
(jsx_opening_element (identifier) @tag (#match? @tag "^[a-z][^.]*$"))
(jsx_closing_element (identifier) @tag (#match? @tag "^[a-z][^.]*$"))
(jsx_self_closing_element (identifier) @tag (#match? @tag "^[a-z][^.]*$"))
;; #F07178 #000000 0 0 0 1
(jsx_attribute (property_identifier) @attribute)
;; #BFBDB6 #000000 0 0 0 1
(jsx_opening_element (["<" ">"]) @punctuation.bracket)
(jsx_closing_element (["</" ">"]) @punctuation.bracket)
(jsx_self_closing_element (["<" "/>"]) @punctuation.bracket)
; Injections
;; !regex
(regex) @string.regex

22
grammar/json.scm Normal file
View File

@@ -0,0 +1,22 @@
;; #D2A6FF #000000 0 0 0 2
(pair
key: (_) @string.special.key)
;; #AAD94C #000000 0 0 0 1
(string) @string
;; #7dcfff #000000 0 0 0 2
(number) @number
;; #F07178 #000000 0 0 0 1
[
(null)
(true)
(false)
] @constant.builtin
;; #7dcfff #000000 0 0 0 2
(escape_sequence) @escape
;; #99ADBF #000000 0 1 0 1
(comment) @comment

312
grammar/lua.scm Normal file
View File

@@ -0,0 +1,312 @@
; ============================================================
; Identifiers
; ============================================================
;; #FFFFFF #000000 0 0 0 1
(identifier) @variable
;; #C9B4FF #000000 0 0 0 2
((identifier) @constant
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
;; #F28FAD #000000 0 0 0 3
((identifier) @variable.builtin
(#match? @variable.builtin "^self$"))
; Attributes (generic parameters)
;; #7CD5CF #000000 0 0 0 2
(variable_list
(attribute
"<" @punctuation.bracket
(identifier) @attribute
">" @punctuation.bracket))
; ============================================================
; Control flow & keywords
; ============================================================
;; #9AD4FF #000000 0 0 0 2
"return" @keyword.return
;; #FF9E64 #000000 0 0 0 2
[
"goto"
"in"
"local"
] @keyword
;; #9AD4FF #000000 0 0 0 2
(label_statement) @label
;; #FF9E64 #000000 0 0 0 2
(break_statement) @keyword
;; #9AD4FF #000000 0 0 0 2
(do_statement
[
"do"
"end"
] @keyword)
;; #9AD4FF #000000 0 0 0 2
(while_statement
[
"while"
"do"
"end"
] @repeat)
;; #9AD4FF #000000 0 0 0 2
(repeat_statement
[
"repeat"
"until"
] @repeat)
;; #FFB870 #000000 0 0 0 2
(if_statement
[
"if"
"elseif"
"else"
"then"
"end"
] @conditional)
;; #9AD4FF #000000 0 0 0 2
(elseif_statement
[
"elseif"
"then"
"end"
] @conditional)
;; #9AD4FF #000000 0 0 0 2
(else_statement
[
"else"
"end"
] @conditional)
;; #9AD4FF #000000 0 0 0 2
(for_statement
[
"for"
"do"
"end"
] @repeat)
;; #FFB870 #000000 0 0 0 2
(function_declaration
[
"function"
"end"
] @keyword.function)
;; #FFB870 #000000 0 0 0 2
(function_definition
[
"function"
"end"
] @keyword.function)
; ============================================================
; Operators
; ============================================================
;; #6BD9DF #000000 0 1 0 1
(binary_expression operator: _ @operator)
;; #6BD9DF #000000 0 1 0 1
(unary_expression operator: _ @operator)
;; #F29CC3 #000000 0 0 0 1
[
"and"
"not"
"or"
] @keyword.operator
; ============================================================
; Punctuation
; ============================================================
;; #B6BEC8 #000000 0 0 0 1
[
";"
":"
","
"."
] @punctuation.delimiter
; Brackets
;; #B6BEC8 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
; ============================================================
; Tables & fields
; ============================================================
;; #9AD4FF #000000 0 0 0 1
(field name: (identifier) @field)
;; #9AD4FF #000000 0 0 0 1
(dot_index_expression field: (identifier) @field)
;; #7CD5CF #000000 0 0 0 1
(table_constructor
[
"{"
"}"
] @constructor)
; ============================================================
; Functions
; ============================================================
;; #FFC877 #000000 0 0 0 3
(parameters (identifier) @parameter)
;; #FFC877 #000000 0 0 0 3
(function_declaration
name: [
(identifier) @function
(dot_index_expression
field: (identifier) @function)
])
;; #FFC877 #000000 0 0 0 3
(function_declaration
name: (method_index_expression
method: (identifier) @method))
;; #FFC877 #000000 0 0 0 3
(assignment_statement
(variable_list .
name: [
(identifier) @function
(dot_index_expression
field: (identifier) @function)
])
(expression_list .
value: (function_definition)))
;; #FFC877 #000000 0 0 0 3
(table_constructor
(field
name: (identifier) @function
value: (function_definition)))
; Function calls
;; #78C2FF #000000 0 0 0 2
(function_call
name: [
(identifier) @function.call
(dot_index_expression
field: (identifier) @function.call)
(method_index_expression
method: (identifier) @method.call)
])
; Highlighted definitions & references
;; #FFC877 #000000 0 0 0 3
(function_declaration
name: [
(identifier) @name
(dot_index_expression
field: (identifier) @name)
]) @definition.function
;; #FFC877 #000000 0 0 0 3
(function_declaration
name: (method_index_expression
method: (identifier) @name)) @definition.method
;; #FFC877 #000000 0 0 0 3
(assignment_statement
(variable_list .
name: [
(identifier) @name
(dot_index_expression
field: (identifier) @name)
])
(expression_list .
value: (function_definition))) @definition.function
;; #FFC877 #000000 0 0 0 3
(table_constructor
(field
name: (identifier) @name
value: (function_definition))) @definition.function
;; #78C2FF #000000 0 0 0 2
(function_call
name: [
(identifier) @name
(dot_index_expression
field: (identifier) @name)
(method_index_expression
method: (identifier) @name)
]) @reference.call
; Builtins
;; #F28FAD #000000 0 0 0 2
(function_call
(identifier) @function.builtin
(#match? @function.builtin "^(assert|collectgarbage|dofile|error|getfenv|getmetatable|ipairs|load|loadfile|loadstring|module|next|pairs|pcall|print|rawequal|rawget|rawset|required|select|setfenv|setmetatable|tonumber|tostring|type|unpack|xpcall)$"))
; ============================================================
; Literals & constants
; ============================================================
;; #B8E986 #000000 0 0 0 5
(number) @number
;; #A6E3A1 #000000 0 0 0 5
(string) @string
;; #A6E3A1 #000000 0 0 0 6
(escape_sequence) @string.escape
;; #C9B4FF #000000 0 0 0 2
(vararg_expression) @constant
;; #C9B4FF #000000 0 0 0 2
(nil) @constant.builtin
;; #C2E8FF #000000 0 0 0 2
[
(false)
(true)
] @boolean
; ============================================================
; Comments & directives
; ============================================================
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #7CD5CF #000000 0 0 0 1
(hash_bang_line) @preproc
; ============================================================
; Injections
; ============================================================
;; #7CD5CF #000000 0 1 0 2
((function_call
name: [
(identifier) @_cdef_identifier
(_ _ (identifier) @_cdef_identifier)
]
;; !c
arguments: (arguments (string content: _ @injection.c)))
(#match? @_cdef_identifier "^cdef$"))

191
grammar/make.scm Normal file
View File

@@ -0,0 +1,191 @@
;; #9CDCFE #000000 0 0 0 3
[
"("
")"
"{"
"}"
] @punctuation.bracket
;; #C2E8FF #000000 0 1 0 2
[
":"
"&:"
"::"
"|"
";"
"\""
"'"
","
] @punctuation.delimiter
;; #FFD700 #000000 0 0 0 2
[
"$"
"$$"
] @punctuation.special
;; #FF8F40 #000000 0 0 0 2
(automatic_variable
[ "@" "%" "<" "?" "^" "+" "/" "*" "D" "F"] @punctuation.special)
;; #FF6347 #000000 0 0 0 2
(automatic_variable
"/" @error . ["D" "F"])
;; #F29668 #000000 0 1 0 2
[
"="
":="
"::="
"?="
"+="
"!="
"@"
"-"
"+"
] @operator
;; #FFFFFF #000000 0 0 0 1
[
(text)
(string)
(raw_text)
] @string
;; #9AD4FF #000000 0 0 0 2
(variable_assignment (word) @string)
;; #7AA2F7 #000000 0 0 0 1
[
"ifeq"
"ifneq"
"ifdef"
"ifndef"
"else"
"endif"
"if"
"or" ; boolean functions are conditional in make grammar
"and"
] @conditional
;; #9ADE7A #000000 0 0 0 2
"foreach" @repeat
;; #D2A6FF #000000 0 0 0 1
[
"define"
"endef"
"vpath"
"undefine"
"export"
"unexport"
"override"
"private"
; "load"
] @keyword
;; #C6B5FF #000000 0 0 0 2
[
"include"
"sinclude"
"-include"
] @include
;; #82AAFF #000000 0 0 0 2
[
"subst"
"patsubst"
"strip"
"findstring"
"filter"
"filter-out"
"sort"
"word"
"words"
"wordlist"
"firstword"
"lastword"
"dir"
"notdir"
"suffix"
"basename"
"addsuffix"
"addprefix"
"join"
"wildcard"
"realpath"
"abspath"
"call"
"eval"
"file"
"value"
"shell"
] @keyword.function
;; #FF9D5C #000000 0 0 0 2
[
"error"
"warning"
"info"
] @exception
;; #B8E986 #000000 0 0 0 2
(variable_assignment
name: (word) @constant)
;; #B8E986 #000000 0 0 0 2
(variable_reference
(word) @constant)
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #F28FAD #000000 0 0 0 2
((word) @clean @string.regex
(#match? @clean "[%\*\?]"))
;; #F07178 #000000 0 0 0 2
(function_call
function: "error"
(arguments (text) @text.danger))
;; #FFC877 #000000 0 0 0 2
(function_call
function: "warning"
(arguments (text) @text.warning))
;; #61AFEF #000000 0 0 0 2
(function_call
function: "info"
(arguments (text) @text.note))
;; #95E6CB #000000 0 0 0 2
[
"VPATH"
".RECIPEPREFIX"
] @constant.builtin
;; #95E6CB #000000 0 0 0 2
(variable_assignment
name: (word) @clean @constant.builtin
(#match? @clean "^(AR|AS|CC|CXX|CPP|FC|M2C|PC|CO|GET|LEX|YACC|LINT|MAKEINFO|TEX|TEXI2DVI|WEAVE|CWEAVE|TANGLE|CTANGLE|RM|ARFLAGS|ASFLAGS|CFLAGS|CXXFLAGS|COFLAGS|CPPFLAGS|FFLAGS|GFLAGS|LDFLAGS|LDLIBS|LFLAGS|YFLAGS|PFLAGS|RFLAGS|LINTFLAGS|PRE_INSTALL|POST_INSTALL|NORMAL_INSTALL|PRE_UNINSTALL|POST_UNINSTALL|NORMAL_UNINSTALL|MAKEFILE_LIST|MAKE_RESTARTS|MAKE_TERMOUT|MAKE_TERMERR|\\.DEFAULT_GOAL|\\.RECIPEPREFIX|\\.EXTRA_PREREQS)$"))
;; #95E6CB #000000 0 0 0 2
(variable_reference
(word) @clean @constant.builtin
(#match? @clean "^(AR|AS|CC|CXX|CPP|FC|M2C|PC|CO|GET|LEX|YACC|LINT|MAKEINFO|TEX|TEXI2DVI|WEAVE|CWEAVE|TANGLE|CTANGLE|RM|ARFLAGS|ASFLAGS|CFLAGS|CXXFLAGS|COFLAGS|CPPFLAGS|FFLAGS|GFLAGS|LDFLAGS|LDLIBS|LFLAGS|YFLAGS|PFLAGS|RFLAGS|LINTFLAGS|PRE_INSTALL|POST_INSTALL|NORMAL_INSTALL|PRE_UNINSTALL|POST_UNINSTALL|NORMAL_UNINSTALL|MAKEFILE_LIST|MAKE_RESTARTS|MAKE_TERMOUT|MAKE_TERMERR|\\.DEFAULT_GOAL|\\.RECIPEPREFIX|\\.EXTRA_PREREQS\\.VARIABLES|\\.FEATURES|\\.INCLUDE_DIRS|\\.LOADED)$"))
;; #C792EA #000000 0 0 0 2
(targets
(word) @constant.macro
(#match? @constant.macro "^(all|install|install-html|install-dvi|install-pdf|install-ps|uninstall|install-strip|clean|distclean|mostlyclean|maintainer-clean|TAGS|info|dvi|html|pdf|ps|dist|check|installcheck|installdirs)$"))
;; #C792EA #000000 0 0 0 2
(targets
(word) @constant.macro
(#match? @constant.macro "^(all|install|install-html|install-dvi|install-pdf|install-ps|uninstall|install-strip|clean|distclean|mostlyclean|maintainer-clean|TAGS|info|dvi|html|pdf|ps|dist|check|installcheck|installdirs)$"))
;; #C792EA #000000 0 0 0 2
(targets
(word) @constant.macro
(#match? @constant.macro "^\\.(PHONY|SUFFIXES|DEFAULT|PRECIOUS|INTERMEDIATE|SECONDARY|SECONDEXPANSION|DELETE_ON_ERROR|IGNORE|LOW_RESOLUTION_TIME|SILENT|EXPORT_ALL_VARIABLES|NOTPARALLEL|ONESHELL|POSIX)$"))

321
grammar/markdown.scm Normal file
View File

@@ -0,0 +1,321 @@
;; #82AAFF #000000 1 0 1 4
(setext_heading
(paragraph) @markup.heading.1
(setext_h1_underline) @markup.heading.1)
;; #82AAFF #000000 1 0 1 4
(setext_heading
(paragraph) @markup.heading.2
(setext_h2_underline) @markup.heading.2)
(atx_heading
(atx_h1_marker)) @markup.heading.1
(atx_heading
(atx_h2_marker)) @markup.heading.2
;; #82AAFF #000000 1 0 0 4
(atx_heading
(atx_h3_marker)) @markup.heading.3
;; #82AAFF #000000 1 0 0 4
(atx_heading
(atx_h4_marker)) @markup.heading.4
;; #82AAFF #000000 1 0 0 4
(atx_heading
(atx_h5_marker)) @markup.heading.5
;; #82AAFF #000000 1 0 0 4
(atx_heading
(atx_h6_marker)) @markup.heading.6
;; #82AAFF #000000 0 0 0 4
(info_string) @label
;; #FF6347 #000000 0 0 0 4
(pipe_table_header
(pipe_table_cell) @markup.heading)
;; #FF8F40 #000000 0 0 0 4
(pipe_table_header
"|" @punctuation.special)
(pipe_table_row
"|" @punctuation.special)
(pipe_table_delimiter_row
"|" @punctuation.special)
(pipe_table_delimiter_cell) @punctuation.special
;; #AAD94C #000000 0 0 0 2
(indented_code_block) @markup.raw.block
(fenced_code_block) @markup.raw.block
(fenced_code_block
(fenced_code_block_delimiter) @markup.raw.block)
(fenced_code_block
(info_string
(language) @label))
;; #7dcfff #000000 0 0 1 6
(link_destination) @markup.link.url
;; #7dcfff #000000 0 0 1 6
[
(link_title)
(link_label)
] @markup.link.label
;; #FF8F40 #000000 0 0 0 4
((link_label)
.
":" @punctuation.delimiter)
;; #9ADE7A #000000 0 0 0 4
[
(list_marker_plus)
(list_marker_minus)
(list_marker_star)
(list_marker_dot)
(list_marker_parenthesis)
] @markup.list
(thematic_break) @punctuation.special
;; #FF8F40 #000000 0 0 0 4
(task_list_marker_unchecked) @markup.list.unchecked
;; #AAD94C #000000 0 0 0 4
(task_list_marker_checked) @markup.list.checked
[
(plus_metadata)
(minus_metadata)
] @keyword.directive
[
(block_continuation)
(block_quote_marker)
] @punctuation.special
;; #AAD94C #000000 0 0 0 6
(backslash_escape) @string.escape
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^ruby$"))
;; !ruby
(code_fence_content) @injection.ruby)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^bash$"))
;; !bash
(code_fence_content) @injection.bash)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^cpp$"))
;; !cpp
(code_fence_content) @injection.cpp)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^h$"))
;; !h
(code_fence_content) @injection.h)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^c$"))
;; !c
(code_fence_content) @injection.h)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^css$"))
;; !css
(code_fence_content) @injection.css)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^fish$"))
;; !fish
(code_fence_content) @injection.fish)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^go$"))
;; !go
(code_fence_content) @injection.go)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^haskell$"))
;; !haskell
(code_fence_content) @injection.haskell)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^html$"))
;; !html
(code_fence_content) @injection.html)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^javascript$"))
;; !javascript
(code_fence_content) @injection.javascript)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^json$"))
;; !json
(code_fence_content) @injection.json)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^lua$"))
;; !lua
(code_fence_content) @injection.lua)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^regex$"))
;; !regex
(code_fence_content) @injection.regex)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^query$"))
;; !query
(code_fence_content) @injection.query)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^markdown$"))
;; !markdown
(code_fence_content) @injection.markdown)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^markdown_inline$"))
;; !markdown_inline
(code_fence_content) @injection.markdown_inline)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^erb$"))
;; !embedded_template
(code_fence_content) @injection.embedded_template)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^python$"))
;; !python
(code_fence_content) @injection.python)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^php$"))
;; !php
(code_fence_content) @injection.php)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^rust$"))
;; !rust
(code_fence_content) @injection.rust)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^sql$"))
;; !sql
(code_fence_content) @injection.sql)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^gitattributes$"))
;; !gitattributes
(code_fence_content) @injection.gitattributes)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^gitignore$"))
;; !gitignore
(code_fence_content) @injection.gitignore)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^gdscript$"))
;; !gdscript
(code_fence_content) @injection.gdscript)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^make$"))
;; !make
(code_fence_content) @injection.make)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^diff$"))
;; !diff
(code_fence_content) @injection.diff)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^ini$"))
;; !ini
(code_fence_content) @injection.ini)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^nginx$"))
;; !nginx
(code_fence_content) @injection.nginx)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^toml$"))
;; !toml
(code_fence_content) @injection.toml)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^yaml$"))
;; !yaml
(code_fence_content) @injection.yaml)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^gomod$"))
;; !gomod
(code_fence_content) @injection.gomod)
(fenced_code_block
(info_string
(language) @injection.language (#match? @injection.language "^cabal$"))
;; !cabal
(code_fence_content) @injection.cabal)
;; !html
(html_block) @injection.html
;; !yaml
(minus_metadata) @injection.yaml
;; !toml
(plus_metadata) @injection.toml
;; !markdown_inline
(paragraph) @inline
(pipe_table_row
(pipe_table_cell) @inline)
(block_quote ((paragraph) @inline))

View File

@@ -0,0 +1,90 @@
;; #AAD94C #000000 0 0 0 0
(code_span) @markup.raw
;; #FF8F40 #000000 0 1 0 1
(emphasis) @markup.italic
;; #FFD700 #000000 1 0 0 1
(strong_emphasis) @markup.strong
;; #FF6347 #000000 0 0 1 1
(strikethrough) @markup.strikethrough
;; #7dcfff #000000 0 0 0 1
[
(backslash_escape)
(hard_line_break)
] @string.escape
;; #7dcfff #000000 0 0 1 1
(inline_link
[
"["
"]"
"("
(link_destination)
")"
] @markup.link)
;; #7dcfff #000000 0 0 1 1
[
(link_label)
(link_text)
(link_title)
(image_description)
] @markup.link.label
;; #7dcfff #000000 0 0 1 1
((inline_link
(link_destination) @_url) @_label)
;; #7dcfff #000000 0 0 1 1
((image
(link_destination) @_url) @_label)
;; #7dcfff #000000 0 0 1 1
(image
[
"!"
"["
"]"
"("
(link_destination)
")"
] @markup.link)
;; #7dcfff #000000 0 0 1 1
(full_reference_link
[
"["
"]"
(link_label)
] @markup.link)
;; #7dcfff #000000 0 0 1 1
(collapsed_reference_link
[
"["
"]"
] @markup.link)
;; #7dcfff #000000 0 0 1 1
(shortcut_link
[
"["
"]"
] @markup.link)
;; #7dcfff #000000 0 0 1 1
[
(link_destination)
(uri_autolink)
(email_autolink)
] @markup.link.url @nospell
;; #7dcfff #000000 0 0 1 1
(uri_autolink) @_url
;; #FF8F40 #000000 0 0 0 0
;; !html
(html_tag) @injection.html

54
grammar/nginx.scm Normal file
View File

@@ -0,0 +1,54 @@
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #7dcfff #000000 0 0 0 2
(number) @number
(metric) @number
;; !regex
(regex) @regex
;; #FFFFFF #000000 0 0 0 1
(variable) @variable
;; #F29668 #000000 0 0 0 1
(modifier) @operator
;; #D2A6FF #000000 0 0 0 1
(simple_directive
name: (directive) @function)
;; #D2A6FF #000000 0 0 0 1
(block_directive
name: (directive) @function)
;; #D2A6FF #000000 0 0 0 1
(lua_block_directive
"access_by_lua_block" @function)
;; #F07178 #000000 0 0 0 1
((generic) @constant.builtin
(#match? @constant.builtin "^(off|on)$"))
;; #AAD94C #000000 0 0 0 2
(generic) @string
(string) @string
;; #FFFFFF #000000 0 0 0 1
(scheme) @string
(ipv4) @number
;; #888888 #000000 0 1 0 3
[
";"
] @delimiter
;; #888888 #000000 0 0 0 3
[
"{"
"}"
"("
")"
"["
"]"
] @punctuation.bracket

453
grammar/php.scm Normal file
View File

@@ -0,0 +1,453 @@
;; =========================================================
;; PHP SYNTAX HIGHLIGHTING
;; Coolwarm balanced palette (blue / teal / purple / orange)
;; =========================================================
;; #FF9D5C #000000 0 0 0 1
;; Keywords (logic / flow)
[
"and"
"as"
"instanceof"
"or"
"xor"
] @keyword.operator
;; #FF9D5C #000000 0 0 0 1
[
"fn"
"function"
] @keyword.function
;; #FF9D5C #000000 0 0 0 1
[
"clone"
"declare"
"default"
"echo"
"enddeclare"
"extends"
"global"
"goto"
"implements"
"insteadof"
"print"
"new"
"unset"
] @keyword
;; #6FB3FF #000000 0 0 0 1
[
"enum"
"class"
"interface"
"namespace"
"trait"
] @keyword.type
;; #FF9D5C #000000 0 0 0 1
[
"abstract"
"const"
"final"
"private"
"protected"
"public"
"readonly"
"static"
] @keyword.modifier
;; #FF9D5C #000000 0 0 0 1
[
"return"
"exit"
"yield"
"yield from"
] @keyword.return
;; #FF9D5C #000000 0 0 0 1
[
"case"
"else"
"elseif"
"endif"
"endswitch"
"if"
"switch"
"match"
"??"
] @keyword.conditional
;; #FF9D5C #000000 0 0 0 1
[
"break"
"continue"
"do"
"endfor"
"endforeach"
"endwhile"
"for"
"foreach"
"while"
] @keyword.repeat
;; #FF9D5C #000000 0 0 0 1
[
"catch"
"finally"
"throw"
"try"
] @keyword.exception
;; #8BD5CA #000000 0 0 0 1
[
"include_once"
"include"
"require_once"
"require"
"use"
] @keyword.import
;; #B0BEC5 #000000 0 0 0 1
[
","
";"
":"
"\\"
] @punctuation.delimiter
;; #B0BEC5 #000000 0 0 0 1
[
(php_tag)
(php_end_tag)
"("
")"
"["
"]"
"{"
"}"
"#["
] @punctuation.bracket
;; #F29668 #000000 0 1 0 1
[
"="
"."
"-"
"*"
"/"
"+"
"%"
"**"
"~"
"|"
"^"
"&"
"<<"
">>"
"<<<"
"->"
"?->"
"=>"
"<"
"<="
">="
">"
"<>"
"<=>"
"=="
"!="
"==="
"!=="
"!"
"&&"
"||"
".="
"-="
"+="
"*="
"/="
"%="
"**="
"&="
"|="
"^="
"<<="
">>="
"??="
"--"
"++"
"@"
"::"
] @operator
;; #7DCFFF #000000 0 0 0 1
(variable_name) @variable
;; #C792EA #000000 0 0 0 1
((name) @constant
(#lua-match? @constant "^_?[A-Z][A-Z%d_]*$"))
;; #C792EA #000000 0 0 0 1
((name) @constant.builtin
(#lua-match? @constant.builtin "^__[A-Z][A-Z%d_]+__$"))
;; #6FB3FF #000000 0 0 0 1
(const_declaration
(const_element
(name) @constant))
;; #82AAFF #000000 0 0 0 1
[
(primitive_type)
(cast_type)
(bottom_type)
] @type.builtin
;; #82AAFF #000000 0 0 0 1
(named_type
[
(name) @type
(qualified_name (name) @type)
(relative_name (name) @type)
])
;; #82AAFF #000000 0 0 0 1
(named_type
(name) @type.builtin
(#any-of? @type.builtin "static" "self"))
;; #82AAFF #000000 0 0 0 1
(class_declaration
name: (name) @type)
;; #82AAFF #000000 0 0 0 1
(enum_declaration
name: (name) @type)
;; #82AAFF #000000 0 0 0 1
(interface_declaration
name: (name) @type)
;; #7DCFFF #000000 0 0 0 1
(namespace_use_clause
[
(name) @type
(qualified_name (name) @type)
alias: (name) @type.definition
])
;; #7DCFFF #000000 0 0 0 1
(namespace_use_clause
type: "function"
[
(name) @function
(qualified_name (name) @function)
alias: (name) @function
])
;; #7DCFFF #000000 0 0 0 1
(namespace_use_clause
type: "const"
[
(name) @constant
(qualified_name (name) @constant)
alias: (name) @constant
])
;; #7DCFFF #000000 0 0 0 1
(scoped_call_expression
scope: [
(name) @type
(qualified_name (name) @type)
(relative_name (name) @type)
])
;; #7DCFFF #000000 0 0 0 1
(class_constant_access_expression
.
[
(name) @type
(qualified_name (name) @type)
(relative_name (name) @type)
]
(name) @constant)
;; #A6E3A1 #000000 0 0 0 1
(scoped_property_access_expression
name: (variable_name) @variable.member)
;; #A6E3A1 #000000 0 0 0 1
(trait_declaration
name: (name) @type)
;; #A6E3A1 #000000 0 0 0 1
(use_declaration
(name) @type)
;; #FF9D5C #000000 0 0 0 1
(binary_expression
operator: "instanceof"
right: [
(name) @type
(qualified_name (name) @type)
(relative_name (name) @type)
])
;; #FFD580 #000000 0 0 0 1
(array_creation_expression
"array" @function.builtin)
;; #FFD580 #000000 0 0 0 1
(list_literal
"list" @function.builtin)
;; #FFD580 #000000 0 0 0 1
(exit_statement
"exit" @function.builtin
"(")
;; #89DDFF #000000 0 0 0 1
(method_declaration
name: (name) @function.method)
;; #89DDFF #000000 0 0 0 1
(function_call_expression
function: [
(name) @function.call
(qualified_name (name) @function.call)
(relative_name (name) @function.call)
])
;; #89DDFF #000000 0 0 0 1
(scoped_call_expression
name: (name) @function.call)
;; #89DDFF #000000 0 0 0 1
(member_call_expression
name: (name) @function.method)
;; #89DDFF #000000 0 0 0 1
(nullsafe_member_call_expression
name: (name) @function.method)
;; #FFD580 #000000 0 0 0 1
(method_declaration
name: (name) @constructor
(#eq? @constructor "__construct"))
;; #FFD580 #000000 0 0 0 1
(object_creation_expression
[
(name) @constructor
(qualified_name (name) @constructor)
(relative_name (name) @constructor)
])
;; #9CDCFE #000000 0 0 0 1
(variadic_parameter
"..." @operator
name: (variable_name) @variable.parameter)
;; #9CDCFE #000000 0 0 0 1
(simple_parameter
name: (variable_name) @variable.parameter)
;; #9CDCFE #000000 0 0 0 1
(argument
(name) @variable.parameter)
;; #9CDCFE #000000 0 0 0 1
(property_element
(variable_name) @property)
;; #9CDCFE #000000 0 0 0 1
(member_access_expression
name: (variable_name (name)) @variable.member)
;; #9CDCFE #000000 0 0 0 1
(relative_scope) @variable.builtin
;; #7AA2F7 #000000 0 0 0 1
((variable_name) @variable.builtin
(#eq? @variable.builtin "$this"))
;; #C792EA #000000 0 0 0 1
(namespace_definition
name: (namespace_name (name) @module))
;; #C792EA #000000 0 0 0 1
(namespace_name
(name) @module)
;; #7AA2F7 #000000 0 0 0 1
(relative_name
"namespace" @module.builtin)
;; #89DDFF #000000 0 0 0 1
(attribute_list) @attribute
;; #FF9D5C #000000 0 0 0 1
(conditional_expression
"?" @keyword.conditional.ternary
":" @keyword.conditional.ternary)
;; #9CDCFE #000000 0 0 0 1
(declare_directive
[
"strict_types"
"ticks"
"encoding"
] @variable.parameter)
;; #A6E3A1 #000000 0 0 0 1
[
(string)
(encapsed_string)
(heredoc_body)
(nowdoc_body)
(shell_command_expression)
] @string
;; #A6E3A1 #000000 0 0 0 1
(escape_sequence) @string.escape
;; #A6E3A1 #000000 0 0 0 1
[
(heredoc_start)
(heredoc_end)
] @label
;; #DDB6F2 #000000 0 0 0 1
(nowdoc
"'" @label)
;; #F38BA8 #000000 0 0 0 1
(boolean) @boolean
;; #F38BA8 #000000 0 0 0 1
(null) @constant.builtin
;; #F38BA8 #000000 0 0 0 1
(integer) @number
;; #F38BA8 #000000 0 0 0 1
(float) @number.float
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #A6E3A1 #000000 0 0 0 1
(named_label_statement) @label
;; #7AA2F7 #000000 0 0 0 1
(property_hook
(name) @label)
;; #7AA2F7 #000000 0 0 0 1
(visibility_modifier
(operation) @label)
;; #89DDFF #000000 0 0 0 1
;; !html
(text) @injection.html

412
grammar/python.scm Normal file
View File

@@ -0,0 +1,412 @@
; ============================================================
; Identifiers
; ============================================================
;; #FFFFFF #000000 0 0 0 1
(identifier) @variable
;; #D2A6FF #000000 0 0 0 2
((identifier) @type
(#match? @type "^[A-Z].*[a-z]"))
;; #D2A6FF #000000 0 0 0 2
((identifier) @constant
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
;; #D2A6FF #000000 0 0 0 2
((identifier) @constant.builtin
(#match? @constant.builtin "^__[a-zA-Z0-9_]*__$"))
;; #D2A6FF #000000 0 0 0 2
((identifier) @constant.builtin
(#match? @constant.builtin "^(NotImplemented|Ellipsis|quit|exit|copyright|credits|license)$"))
;; #FFB454 #000000 0 0 0 3
((assignment
left: (identifier) @type.definition
(type
(identifier) @_annotation))
(#match? @_annotation "^TypeAlias$"))
;; #FFB454 #000000 0 0 0 3
((assignment
left: (identifier) @type.definition
right: (call
function: (identifier) @_func))
(#match? @_func "^(TypeVar|NewType)$"))
; ============================================================
; Function definitions
; ============================================================
;; #FFB454 #000000 0 0 0 3
(function_definition
name: (identifier) @function)
;; #FFB454 #000000 0 0 0 2
(type
(identifier) @type)
;; #FFB454 #000000 0 0 0 2
(type
(subscript
(identifier) @type))
;; #FFB454 #000000 0 0 0 2
((call
function: (identifier) @_isinstance
arguments: (argument_list
(_)
(identifier) @type))
(#match? @_isinstance "^isinstance$"))
; ============================================================
; Literals
; ============================================================
;; #D2A6FF #000000 0 0 0 2
(none) @constant.builtin
;; #D2A6FF #000000 0 0 0 2
[
(true)
(false)
] @boolean
;; #D2A6FF #000000 0 0 0 2
(integer) @number
;; #D2A6FF #000000 0 0 0 2
(float) @number.float
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
;; #F29668 #000000 0 0 0 1
((module
.
(comment) @keyword.directive @nospell)
(#match? @keyword.directive "^#!/"))
;; #AAD94C #000000 0 0 0 0
(string) @string
;; #AAD94C #000000 0 0 0 0
[
(escape_sequence)
(escape_interpolation)
] @string.escape
;; #AAD94C #000000 0 0 0 0
(expression_statement
(string
(string_content) @spell) @string.documentation)
; ============================================================
; Operators
; ============================================================
;; #FF8F40 #000000 0 0 0 1
[ "if" "elif" "else" "for" "while" "break" "continue" ] @keyword.control_flow_loops
;; #FF8F40 #000000 0 0 0 1
[ "def" "return" "lambda" "yield" "async" "await" ] @keyword.functions_coroutines
;; #7dcfff #000000 0 0 0 2
[ "class" ] @keyword.class
;; #F07178 #000000 0 0 0 1
[ "try" "except" "finally" "raise" ] @keyword.exceptions
;; #D2A6FF #000000 0 0 0 2
[ "with" ] @keyword.context_management
;; #7dcfff #000000 0 0 0 2
[ "import" "from" "exec" ] @keyword.imports_execution
;; #D2A6FF #000000 0 0 0 2
[ "match" "case" ] @keyword.pattern_matching
;; #F07178 #000000 0 0 0 1
[ "global" "nonlocal" ] @keyword.scope_bindings
;; #FF8F40 #000000 0 0 0 1
[ "del" ] @keyword.deletion
;; #FF8F40 #000000 0 0 0 1
[ "pass" "assert" "as" "print" ] @keyword.utility
;; #F29668 #000000 0 1 0 1
[
"-"
"-="
"!="
"*"
"**"
"**="
"*="
"/"
"//"
"//="
"/="
"&"
"&="
"%"
"%="
"^"
"^="
"+"
"->"
"+="
"<"
"<<"
"<<="
"<="
"<>"
"="
":="
"=="
">"
">="
">>"
">>="
"|"
"|="
"~"
"@="
"and"
"in"
"is"
"not"
"or"
"is not"
"not in"
] @operatoroperator
;; #BFBDB6 #000000 0 0 0 1
[
","
"."
":"
";"
(ellipsis)
] @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
;; #7dcfff #000000 0 0 0 2
(interpolation
"{" @punctuation.special
"}" @punctuation.special)
;; #7dcfff #000000 0 0 0 2
(format_expression
"{" @punctuation.special
"}" @punctuation.special)
;; #7dcfff #000000 0 0 0 2
(line_continuation) @punctuation.special
;; #FFB454 #000000 0 0 0 2
(type_conversion) @function.macro
; ============================================================
; Builtins / Exception types
; ============================================================
;; #D2A6FF #000000 0 0 0 2
((identifier) @type.builtin
(#match? @type.builtin
"^(BaseException|Exception|ArithmeticError|BufferError|LookupError|AssertionError|AttributeError|EOFError|FloatingPointError|GeneratorExit|ImportError|ModuleNotFoundError|IndexError|KeyError|KeyboardInterrupt|MemoryError|NameError|NotImplementedError|OSError|OverflowError|RecursionError|ReferenceError|RuntimeError|StopIteration|StopAsyncIteration|SyntaxError|IndentationError|TabError|SystemError|SystemExit|TypeError|UnboundLocalError|UnicodeError|UnicodeEncodeError|UnicodeDecodeError|UnicodeTranslateError|ValueError|ZeroDivisionError|EnvironmentError|IOError|WindowsError|BlockingIOError|ChildProcessError|ConnectionError|BrokenPipeError|ConnectionAbortedError|ConnectionRefusedError|ConnectionResetError|FileExistsError|FileNotFoundError|InterruptedError|IsADirectoryError|NotADirectoryError|PermissionError|ProcessLookupError|TimeoutError|Warning|UserWarning|DeprecationWarning|PendingDeprecationWarning|SyntaxWarning|RuntimeWarning|FutureWarning|ImportWarning|UnicodeWarning|BytesWarning|ResourceWarning)$"))
; ============================================================
; Function / Lambda parameters
; ============================================================
;; #D2A6FF #000000 0 0 0 1
(parameters
(identifier) @variable.parameter)
;; #D2A6FF #000000 0 0 0 1
(lambda_parameters
(identifier) @variable.parameter)
;; #D2A6FF #000000 0 0 0 1
(lambda_parameters
(tuple_pattern
(identifier) @variable.parameter))
;; #D2A6FF #000000 0 0 0 1
(keyword_argument
name: (identifier) @variable.parameter)
;; #D2A6FF #000000 0 0 0 1
(default_parameter
name: (identifier) @variable.parameter)
;; #D2A6FF #000000 0 0 0 1
(typed_parameter
(identifier) @variable.parameter)
;; #D2A6FF #000000 0 0 0 1
(typed_default_parameter
name: (identifier) @variable.parameter)
;; #D2A6FF #000000 0 0 0 1
(parameters
(list_splat_pattern
(identifier) @variable.parameter))
;; #D2A6FF #000000 0 0 0 1
(parameters
(dictionary_splat_pattern
(identifier) @variable.parameter))
;; #D2A6FF #000000 0 0 0 1
(lambda_parameters
(list_splat_pattern
(identifier) @variable.parameter))
;; #D2A6FF #000000 0 0 0 1
(lambda_parameters
(dictionary_splat_pattern
(identifier) @variable.parameter))
;; #FFB454 #000000 0 0 0 2
((identifier) @variable.builtin
(#match? @variable.builtin "^(self|cls)$"))
; ============================================================
; Attributes / Class members
; ============================================================
;; #FFB454 #000000 0 0 0 2
((attribute
attribute: (identifier) @variable.member)
(#match? @variable.member "^[%l_].*$"))
; ============================================================
; Class definitions
; ============================================================
;; #59C2FF #000000 0 0 0 2
(class_definition
name: (identifier) @type)
;; #FFB454 #000000 0 0 0 2
(class_definition
body: (block
(function_definition
name: (identifier) @function.method)))
;; #D2A6FF #000000 0 0 0 2
(class_definition
superclasses: (argument_list
(identifier) @type))
;; #FFB454 #000000 0 0 0 2
((class_definition
body: (block
(expression_statement
(assignment
left: (identifier) @variable.member))))
(#match? @variable.member "^[%l_].*$"))
;; #FFB454 #000000 0 0 0 2
((class_definition
body: (block
(expression_statement
(assignment
left: (_
(identifier) @variable.member)))))
(#match? @variable.member "^[%l_].*$"))
;; #FFB454 #000000 0 0 0 2
((class_definition
(block
(function_definition
name: (identifier) @constructor)))
(#match? @constructor "^(__new__|__init__)$"))
; ============================================================
; Function calls
; ============================================================
;; #FFB454 #000000 0 0 0 2
(call
function: (identifier) @function.call)
;; #FFB454 #000000 0 0 0 2
(call
function: (attribute
attribute: (identifier) @function.method.call))
;; #59C2FF #000000 0 0 0 3
((call
function: (identifier) @constructor)
(#match? @constructor "^[A-Z]"))
;; #59C2FF #000000 0 0 0 3
((call
function: (attribute
attribute: (identifier) @constructor))
(#match? @constructor "^[A-Z]"))
;; #FFB454 #000000 0 0 0 2
((call
function: (identifier) @function.builtin)
(#match? @function.builtin
"^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$"))
; ============================================================
; Regex call
; ============================================================
(call
function: (identifier) @_re
arguments: (argument_list
;; !regex
(string) @string.regexp
)
(#match? @_re "re"))
; ============================================================
; Decorators
; ============================================================
;; #FFB454 #000000 0 0 0 2
(decorator
"@" @attribute)
;; #FFB454 #000000 0 0 0 2
(decorator
(identifier) @attribute)
;; #FFB454 #000000 0 0 0 2
(decorator
(attribute
attribute: (identifier) @attribute))
;; #FFB454 #000000 0 0 0 2
(decorator
(call
(identifier) @attribute))
;; #FFB454 #000000 0 0 0 2
(decorator
(call
(attribute
attribute: (identifier) @attribute)))
;; #59C2FF #000000 0 0 0 3
((decorator
(identifier) @attribute.builtin)
(#match? @attribute.builtin "^(classmethod|property|staticmethod)$"))

122
grammar/query.scm Normal file
View File

@@ -0,0 +1,122 @@
;; ============================================================
;; Strings & escapes
;; ============================================================
;; #AAD94C #000000 0 0 0 2
(string) @string
;; #95E6CB #000000 0 0 0 2
(escape_sequence) @string.escape
;; ============================================================
;; Identifiers
;; ============================================================
;; #C4B5FF #000000 0 0 0 2
(capture
(identifier) @type)
;; #FFB454 #000000 0 0 0 2
(predicate
name: (identifier) @function.call)
;; #F29CC3 #000000 0 0 0 2
(named_node
name: (identifier) @variable)
;; #F29CC3 #000000 0 0 0 2
(missing_node
name: (identifier) @variable)
;; #F07178 #000000 0 0 0 2
(field_definition
name: (identifier) @variable.member)
;; #F29CC3 #000000 0 0 0 2
(negated_field
"!" @operator
(identifier) @property)
;; ============================================================
;; Comments
;; ============================================================
;; #99ADBF #000000 0 1 0 2
(comment) @comment @spell
;; ============================================================
;; Operators & punctuation
;; ============================================================
;; #F29668 #000000 0 0 0 2
(quantifier) @operator
;; #BFBDB6 #000000 0 0 0 2
(predicate_type) @punctuation.special
;; #F29668 #000000 0 0 0 2
"." @operator
;; #BFBDB6 #000000 0 0 0 2
[
"["
"]"
"("
")"
] @punctuation.bracket
;; #BFBDB6 #000000 0 0 0 2
[
":"
"/"
] @punctuation.delimiter
;; #BFBDB6 #000000 0 0 0 2
[
"@"
"#"
] @punctuation.special
;; #BFBDB6 #000000 0 0 0 2
(predicate
"." @punctuation.special)
;; #D2A6FF #000000 0 0 0 2
"_" @character.special
;; #FF8F40 #000000 0 0 0 2
"MISSING" @keyword
;; ============================================================
;; Numbers
;; ============================================================
;; #B8E986 #000000 0 0 0 2
((parameters
(identifier) @number)
(#match? @number "^[-+]?[0-9]+(.[0-9]+)?$"))
;; ============================================================
;; Predicate parameters
;; ============================================================
;; #F29CC3 #000000 0 0 0 2
((predicate
name: (identifier) @_name
parameters: (parameters
.
(capture)?
.
(identifier) @property))
(#match? @_name "^set$"))
;; #AAD94C #000000 0 0 0 2
((predicate
name: (identifier) @_name
parameters: (parameters
(string
"\"" @string
"\"" @string)
;; !regex
@string.regexp))
(#match? @_name "^(match|not-match)$"))

77
grammar/regex.scm Normal file
View File

@@ -0,0 +1,77 @@
;; ============================================================
;; Punctuation / brackets
;; ============================================================
;; #B6BEC8 #000000 0 0 0 1
[
"("
")"
"(?"
"(?:"
"(?<"
"(?P<"
"(?P="
">"
"["
"]"
"{"
"}"
"[:"
":]"
] @punctuation.bracket
;; #F29CC3 #000000 0 0 0 2
(group_name) @property
;; #F29668 #000000 0 0 0 1
[
"*"
"+"
"?"
"|"
"="
"!"
] @operator
;; #B8E986 #000000 0 0 0 2
(count_quantifier
[
(decimal_digits) @number
"," @punctuation.delimiter
])
;; #F29668 #000000 0 0 0 2
(inline_flags_group
"-"? @operator
":"? @punctuation.delimiter)
;; #F29CC3 #000000 0 0 0 2
(flags) @character.special
;; #C2E8FF #000000 0 0 0 2
(character_class
[
"^" @operator
(class_range "-" @operator)
])
;; #D2A6FF #000000 0 0 0 2
[
(class_character)
(posix_class_name)
] @constant.character
;; #D2A6FF #000000 0 0 0 2
(pattern_character) @string
;; #95E6CB #000000 0 0 0 2
[
(identity_escape)
(control_letter_escape)
(character_class_escape)
(control_escape)
(start_assertion)
(end_assertion)
(boundary_assertion)
(non_boundary_assertion)
] @escape

View File

@@ -1,10 +1,10 @@
;; #ffffff #000000 0 0 0 1 ;; #FFFFFF #000000 0 0 0 1
[ [
(identifier) (identifier)
(global_variable) (global_variable)
] @variable ] @variable
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"alias" "alias"
"begin" "begin"
@@ -16,17 +16,17 @@
"then" "then"
] @keyword ] @keyword
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
"class" @keyword.type "class" @keyword.type
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"return" "return"
"yield" "yield"
] @keyword.return ] @keyword.return
;; #fbb152 #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
[ [
"and" "and"
"or" "or"
@@ -34,7 +34,7 @@
"not" "not"
] @keyword.operator ] @keyword.operator
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"def" "def"
"undef" "undef"
@@ -44,7 +44,7 @@
"end" @keyword.function) "end" @keyword.function)
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"case" "case"
"else" "else"
@@ -58,7 +58,7 @@
(if (if
"end" @keyword.conditional) "end" @keyword.conditional)
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"for" "for"
"until" "until"
@@ -69,27 +69,28 @@
"next" "next"
] @keyword.repeat ] @keyword.repeat
;; #ebda8c #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
(constant) @constant (constant) @constant
;; #fbb152 #000000 0 0 0 1 ;; #FF8F40 #000000 0 0 0 1
[ [
"rescue" "rescue"
"ensure" "ensure"
] @keyword.exception ] @keyword.exception
;; #aad84c #000000 0 0 0 3 ;; #FFB454 #000000 0 0 0 3
"defined?" @function "defined?" @function
;; #aad84c #000000 0 0 0 3 ;; #FFB454 #000000 0 0 0 3
(call (call
receiver: (constant)? @type receiver: (constant)? @type
method: [ method: [
(identifier) (identifier)
(constant) (constant)
;; #ff5689 #000000 0 0 0 2 ;; #FFB454 #000000 0 0 0 2
] @function.call) ] @function.call)
;; #FFB454 #000000 0 0 0 2
(alias (alias
(identifier) @function) (identifier) @function)
@@ -108,6 +109,7 @@
(constant) @type (constant) @type
]) ])
;; #59C2FF #000000 0 0 0 2
(class (class
name: (constant) @type) name: (constant) @type)
@@ -117,44 +119,46 @@
(superclass (superclass
(constant) @type) (constant) @type)
;; #ffffff #000000 0 0 0 1 ;; #F07178 #000000 0 0 0 2
[ [
(class_variable) (class_variable)
(instance_variable) (instance_variable)
] @variable.member ] @variable.member
;; #FF8F40 #000000 0 0 0 2
((identifier) @keyword.modifier ((identifier) @keyword.modifier
(#match? @keyword.modifier "^(private|protected|public)$" )) (#match? @keyword.modifier "^(private|protected|public)$" ))
;; #fbb152 #000000 0 0 0 3 ;; #FF8F40 #000000 0 0 0 3
(program (program
(call (call
(identifier) @keyword.import) (identifier) @keyword.import)
(#match? @keyword.import "^(require|require_relative|load)$")) (#match? @keyword.import "^(require|require_relative|load)$"))
;; #fbb152 #000000 0 0 0 4 ;; #D2A6FF #000000 0 0 0 4
((identifier) @constant.builtin ((identifier) @constant.builtin
(#match? @constant.builtin "^(__callee__|__dir__|__id__|__method__|__send__|__ENCODING__|__FILE__|__LINE__)$" )) (#match? @constant.builtin "^(__callee__|__dir__|__id__|__method__|__send__|__ENCODING__|__FILE__|__LINE__)$" ))
;; #aad84c #000000 0 0 0 3 ;; #FFB454 #000000 0 0 0 3
((identifier) @function.builtin ((identifier) @function.builtin
(#match? @function.builtin "^(attr_reader|attr_writer|attr_accessor|module_function)$" )) (#match? @function.builtin "^(attr_reader|attr_writer|attr_accessor|module_function)$" ))
((call ((call
!receiver !receiver
method: (identifier) @function.builtin) method: (identifier) @function.builtin)
(#match? @function.builtin "^(include|extend|prepend|refine|using)")) (#match? @function.builtin "^(include|extend|prepend|refine|using)$"))
;; #FF8F40 #000000 0 0 0 3
((identifier) @keyword.exception ((identifier) @keyword.exception
(#match? @keyword.exception "^(raise|fail|catch|throw)" )) (#match? @keyword.exception "^(raise|fail|catch|throw)$" ))
;; #ffffff #000000 0 0 0 1 ;; #F07178 #000000 0 0 0 1
[ [
(self) (self)
(super) (super)
] @variable.builtin ] @variable.builtin
;; #ffffff #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
(method_parameters (method_parameters
(identifier) @variable.parameter) (identifier) @variable.parameter)
@@ -182,7 +186,7 @@
(keyword_parameter (keyword_parameter
(identifier) @variable.parameter) (identifier) @variable.parameter)
;; #aad84c #000000 0 0 0 1 ;; #AAD94C #000000 0 0 0 1
[ [
(string_content) (string_content)
(heredoc_content) (heredoc_content)
@@ -190,13 +194,13 @@
"`" "`"
] @string ] @string
;; #fbb152 #000000 0 0 0 1 ;; #E6C08A #000000 0 0 0 1
[ [
(heredoc_beginning) (heredoc_beginning)
(heredoc_end) (heredoc_end)
] @label ] @label
;; #bd9ae6 #000000 0 0 0 2 ;; #39BAE6 #000000 0 0 0 2
[ [
(bare_symbol) (bare_symbol)
(simple_symbol) (simple_symbol)
@@ -204,38 +208,34 @@
(hash_key_symbol) (hash_key_symbol)
] @string.special.symbol ] @string.special.symbol
;; #e6a24c #000000 0 0 0 2 ;; #95E6CB #000000 0 0 0 2
(regex
(string_content) @string.regexp)
;; #e6a24c #000000 0 0 0 2
(escape_sequence) @string.escape (escape_sequence) @string.escape
;; #ebda8c #000000 0 0 0 2 ;; #D2A6FF #000000 0 0 0 2
(integer) @number (integer) @number
;; #ebda8c #000000 0 0 0 2 ;; #D2A6FF #000000 0 0 0 2
(float) @number.float (float) @number.float
;; #51eeba #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
(true) @boolean.true (true) @boolean.true
;; #ee513a #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
(false) @boolean.false (false) @boolean.false
;; #ee8757 #000000 0 0 0 1 ;; #D2A6FF #000000 0 0 0 1
(nil) @constant.nil (nil) @constant.nil
;; #AAAAAA #000000 0 1 0 1 ;; #99ADBF #000000 0 1 0 1
(comment) @comment (comment) @comment
;; #51eeba #000000 0 0 0 3 ;; #AAD94C #000000 0 0 0 3
((program ((program
. .
(comment) @shebang @nospell) (comment) @shebang @nospell)
(#match? @shebang "^#!/")) (#match? @shebang "^#!/"))
;; #ffffff #000000 0 0 0 1 ;; #F29668 #000000 0 0 0 1
[ [
"!" "!"
"=" "="
@@ -263,7 +263,7 @@
":" ":"
] @operator ] @operator
;; #ffffff #000000 0 1 0 1 ;; #F29668 #000000 0 1 0 1
[ [
"==" "=="
"===" "==="
@@ -281,7 +281,7 @@
"..." "..."
] @operator.ligature ] @operator.ligature
;; #bd9ae6 #000000 0 0 0 1 ;; #BFBDB6 #000000 0 0 0 1
[ [
"," ","
";" ";"
@@ -293,7 +293,7 @@
(pair (pair
":" @punctuation.delimiter) ":" @punctuation.delimiter)
;; #bd9ae6 #000000 0 0 0 1 ;; #BFBDB6 #000000 0 0 0 1
[ [
"(" "("
")" ")"
@@ -311,7 +311,199 @@
(block_parameters (block_parameters
"|" @punctuation.bracket) "|" @punctuation.bracket)
;; #e6a24c #000000 0 0 0 2 ;; #7dcfff #000000 0 0 0 2
(interpolation (interpolation
"#{" @punctuation.special "#{" @punctuation.special
"}" @punctuation.special) "}" @punctuation.special)
; Injections
;; !regex
(regex
(string_content) @string.regexp)
(heredoc_body
;; !bash
(heredoc_content) @bash_injection
((heredoc_end) @lang
(#match? @lang "BASH")))
(heredoc_body
;; !c
(heredoc_content) @c_injection
((heredoc_end) @lang
(#match? @lang "C$")))
(heredoc_body
;; !cpp
(heredoc_content) @cpp_injection
((heredoc_end) @lang
(#match? @lang "CPP")))
(heredoc_body
;; !css
(heredoc_content) @css_injection
((heredoc_end) @lang
(#match? @lang "CSS")))
(heredoc_body
;; !fish
(heredoc_content) @fish_injection
((heredoc_end) @lang
(#match? @lang "FISH")))
(heredoc_body
;; !go
(heredoc_content) @go_injection
((heredoc_end) @lang
(#match? @lang "GO")))
(heredoc_body
;; !haskell
(heredoc_content) @haskell_injection
((heredoc_end) @lang
(#match? @lang "HASKELL")))
(heredoc_body
;; !html
(heredoc_content) @html_injection
((heredoc_end) @lang
(#match? @lang "HTML")))
(heredoc_body
;; !javascript
(heredoc_content) @javascript_injection
((heredoc_end) @lang
(#match? @lang "JAVASCRIPT")))
(heredoc_body
;; !json
(heredoc_content) @json_injection
((heredoc_end) @lang
(#match? @lang "JSON")))
(heredoc_body
;; !lua
(heredoc_content) @lua_injection
((heredoc_end) @lang
(#match? @lang "LUA")))
(heredoc_body
;; !make
(heredoc_content) @make_injection
((heredoc_end) @lang
(#match? @lang "MAKE")))
(heredoc_body
;; !python
(heredoc_content) @python_injection
((heredoc_end) @lang
(#match? @lang "PYTHON")))
(heredoc_body
;; !ruby
(heredoc_content) @ruby_injection
((heredoc_end) @lang
(#match? @lang "RUBY")))
(heredoc_body
;; !rust
(heredoc_content) @rust_injection
((heredoc_end) @lang
(#match? @lang "RUST")))
(heredoc_body
;; !diff
(heredoc_content) @diff_injection
((heredoc_end) @lang
(#match? @lang "DIFF")))
(heredoc_body
;; !embedded_template
(heredoc_content) @embedded_template_injection
((heredoc_end) @lang
(#match? @lang "ERB")))
(heredoc_body
;; !gdscript
(heredoc_content) @gdscript_injection
((heredoc_end) @lang
(#match? @lang "GDSCRIPT")))
(heredoc_body
;; !gitattributes
(heredoc_content) @gitattributes_injection
((heredoc_end) @lang
(#match? @lang "GITATTRIBUTES")))
(heredoc_body
;; !gitignore
(heredoc_content) @gitignore_injection
((heredoc_end) @lang
(#match? @lang "GITIGNORE")))
(heredoc_body
;; !gomod
(heredoc_content) @gomod_injection
((heredoc_end) @lang
(#match? @lang "GOMOD")))
(heredoc_body
;; !ini
(heredoc_content) @ini_injection
((heredoc_end) @lang
(#match? @lang "INI")))
(heredoc_body
;; !markdown
(heredoc_content) @markdown_injection
((heredoc_end) @lang
(#match? @lang "MARKDOWN")))
(heredoc_body
;; !nginx
(heredoc_content) @nginx_injection
((heredoc_end) @lang
(#match? @lang "NGINX")))
(heredoc_body
;; !php
(heredoc_content) @php_injection
((heredoc_end) @lang
(#match? @lang "PHP")))
(heredoc_body
;; !query
(heredoc_content) @query_injection
((heredoc_end) @lang
(#match? @lang "QUERY")))
(heredoc_body
;; !regex
(heredoc_content) @regex_injection
((heredoc_end) @lang
(#match? @lang "REGEX")))
(heredoc_body
;; !sql
(heredoc_content) @sql_injection
((heredoc_end) @lang
(#match? @lang "SQL")))
(heredoc_body
;; !toml
(heredoc_content) @toml_injection
((heredoc_end) @lang
(#match? @lang "TOML")))
(heredoc_body
;; !yaml
(heredoc_content) @yaml_injection
((heredoc_end) @lang
(#match? @lang "YAML")))
(heredoc_body
;; !cabal
(heredoc_content) @cabal_injection
((heredoc_end) @lang
(#match? @lang "CABAL")))

663
grammar/rust.scm Normal file
View File

@@ -0,0 +1,663 @@
; ============================================================
; Identifiers & Modules
; ============================================================
;; #82AAFF #000000 0 0 0 1
(shebang) @keyword.directive1
;; #E5C07B #000000 0 0 0 1
(identifier) @variable1
;; #A6E22E #000000 0 0 0 2
((identifier) @type1
(#match? @type1 "^[A-Z]"))
;; #FFD700 #000000 0 0 0 2
(const_item
name: (identifier) @constant1)
;; #FF9E64 #000000 0 0 0 3
((identifier) @constant2
(#match? @constant2 "^[A-Z][A-Z%d_]*$"))
;; #7DCFFF #000000 0 0 0 4
(type_identifier) @type2
;; #7DCFFF #000000 0 0 0 2
(primitive_type) @type.builtin1
;; #C678DD #000000 0 0 0 2
(field_identifier) @variable.member1
;; #C678DD #000000 0 0 0 2
(shorthand_field_identifier) @variable.member2
;; #C678DD #000000 0 0 0 2
(shorthand_field_initializer
(identifier) @variable.member3)
;; #61AFEF #000000 0 0 0 2
(mod_item
name: (identifier) @module1)
;; #D19A66 #000000 0 0 0 2
(self) @variable.builtin1
;; #5C6370 #000000 0 0 0 1
"_" @character.special1
;; #61AFEF #000000 0 0 1 2
(label
[
"'"
(identifier)
] @label1)
; ============================================================
; Functions & Parameters
; ============================================================
;; #FFB454 #000000 0 0 0 3
(function_item
(identifier) @function1)
;; #FFB454 #000000 0 0 0 3
(function_signature_item
(identifier) @function2)
;; #D2A6FF #000000 0 0 0 1
(parameter
[
(identifier)
"_"
] @variable.parameter1)
;; #D2A6FF #000000 0 0 0 1
(parameter
(ref_pattern
[
(mut_pattern
(identifier) @variable.parameter2)
(identifier) @variable.parameter3
]))
;; #D2A6FF #000000 0 0 0 1
(closure_parameters
(_) @variable.parameter4)
; ============================================================
; Function Calls & Constructors
; ============================================================
;; #FFB454 #000000 0 0 0 2
(call_expression
function: (identifier) @function.call1)
;; #FFB454 #000000 0 0 0 2
(call_expression
function: (scoped_identifier
(identifier) @function.call2 .))
;; #FFB454 #000000 0 0 0 2
(call_expression
function: (field_expression
field: (field_identifier) @function.call3))
;; #FFB454 #000000 0 0 0 2
(generic_function
function: (identifier) @function.call4)
;; #FFB454 #000000 0 0 0 2
(generic_function
function: (scoped_identifier
name: (identifier) @function.call5))
;; #FFB454 #000000 0 0 0 2
(generic_function
function: (field_expression
field: (field_identifier) @function.call6))
;; #9ADE7A #000000 0 0 0 32
((field_identifier) @constant3
(#match? @constant3 "^[A-Z]"))
;; #9ADE7A #000000 0 0 0 32
(enum_variant
name: (identifier) @constant4)
; ============================================================
; Scoped Identifiers & Paths
; ============================================================
;; #82AAFF #000000 0 0 0 9
(scoped_identifier
path: (identifier) @module2)
;; #82AAFF #000000 0 0 0 9
(scoped_identifier
(scoped_identifier
name: (identifier) @module3))
;; #7DCFFF #000000 0 0 0 9
(scoped_type_identifier
path: (identifier) @module4)
;; #7DCFFF #000000 0 0 0 9
(scoped_type_identifier
path: (identifier) @type3
(#match? @type3 "^[A-Z]"))
;; #7DCFFF #000000 0 0 0 9
(scoped_type_identifier
(scoped_identifier
name: (identifier) @module5))
;; #7DCFFF #000000 0 0 0 9
((scoped_identifier
path: (identifier) @type4)
(#match? @type4 "^[A-Z]"))
;; #7DCFFF #000000 0 0 0 9
((scoped_identifier
name: (identifier) @type5)
(#match? @type5 "^[A-Z]"))
;; #FFD700 #000000 0 0 0 7
((scoped_identifier
name: (identifier) @constant5)
(#match? @constant5 "^[A-Z][A-Z%d_]*$"))
;; #FFD700 #000000 0 0 0 7
((scoped_identifier
path: (identifier) @type6
name: (identifier) @constant6)
(#match? @type6 "^[A-Z]")
(#match? @constant6 "^[A-Z]"))
;; #FFD700 #000000 0 0 0 7
((scoped_type_identifier
path: (identifier) @type7
name: (type_identifier) @constant7)
(#match? @type7 "^[A-Z]")
(#match? @constant7 "^[A-Z]"))
;; #61AFEF #000000 0 0 0 0
[
(crate)
(super)
] @module6
;; #61AFEF #000000 0 0 0 0
(scoped_use_list
path: (identifier) @module7)
;; #61AFEF #000000 0 0 0 0
(scoped_use_list
path: (scoped_identifier
(identifier) @module8))
;; #7DCFFF #000000 0 0 0 0
(use_list
(scoped_identifier
(identifier) @module9
.
(_)))
;; #7DCFFF #000000 0 0 0 0
(use_list
(identifier) @type8
(#match? @type8 "^[A-Z]"))
;; #7DCFFF #000000 0 0 0 0
(use_as_clause
alias: (identifier) @type9
(#match? @type9 "^[A-Z]"))
; ============================================================
; Enum Constructors & Match Arms
; ============================================================
;; #9ADE7A #000000 0 0 0 9
; Correct enum constructors
(call_expression
function: (scoped_identifier
"::"
name: (identifier) @constant8)
(#match? @constant8 "^[A-Z]"))
;; #FFD700 #000000 0 0 0 2
; Assume uppercase names in a match arm are constants.
((match_arm
pattern: (match_pattern
(identifier) @constant9))
(#match? @constant9 "^[A-Z]"))
;; #FFD700 #000000 0 0 0 2
((match_arm
pattern: (match_pattern
(scoped_identifier
name: (identifier) @constant10)))
(#match? @constant10 "^[A-Z]"))
;; #D2A6FF #000000 0 0 0 3
((identifier) @constant.builtin1
(#match? @constant.builtin1 "^(Some|None|Ok|Err)$"))
; ============================================================
; Macros
; ============================================================
;; #FF8F40 #000000 0 0 0 2
"$" @function.macro1
;; #FF8F40 #000000 0 0 0 2
(metavariable) @function.macro2
;; #FF8F40 #000000 0 0 0 2
(macro_definition
"macro_rules!" @function.macro3)
;; #FF8F40 #000000 0 0 0 2
(attribute_item
(attribute
(identifier) @function.macro4))
;; #FF8F40 #000000 0 0 0 2
(inner_attribute_item
(attribute
(identifier) @function.macro5))
;; #FF8F40 #000000 0 0 0 2
(attribute
(scoped_identifier
(identifier) @function.macro6 .))
;; #FF8F40 #000000 0 0 0 2
(macro_invocation
macro: (identifier) @function.macro7)
;; #FF8F40 #000000 0 0 0 2
(macro_invocation
macro: (scoped_identifier
(identifier) @function.macro8 .))
; ============================================================
; Literals
; ============================================================
;; #D2A6FF #000000 0 0 0 1
(boolean_literal) @boolean1
;; #D2A6FF #000000 0 0 0 1
(integer_literal) @number1
;; #D2A6FF #000000 0 0 0 1
(float_literal) @number.float1
;; #AAD94C #000000 0 0 0 0
[
(raw_string_literal)
(string_literal)
] @string1
;; #AAD94C #000000 0 0 0 0
(escape_sequence) @string.escape1
;; #F07178 #000000 0 0 0 1
(char_literal) @character1
; ============================================================
; Keywords
; ============================================================
;; #FF8F40 #000000 0 0 0 1
[
"use"
"mod"
] @keyword.import1
;; #FF8F40 #000000 0 0 0 1
(use_as_clause
"as" @keyword.import2)
;; #FF8F40 #000000 0 0 0 1
[
"default"
"impl"
"let"
"move"
"unsafe"
"where"
] @keyword1
;; #FF8F40 #000000 0 0 0 1
[
"enum"
"struct"
"union"
"trait"
"type"
] @keyword.type1
;; #82AAFF #000000 0 0 0 1
[
"async"
"await"
"gen"
] @keyword.coroutine1
;; #FF6347 #000000 0 0 0 1
"try" @keyword.exception1
;; #FF8F40 #000000 0 0 0 1
[
"ref"
"pub"
"raw"
(mutable_specifier)
"const"
"static"
"dyn"
"extern"
] @keyword.modifier1
;; #FF8F40 #000000 0 0 0 1
(lifetime
"'" @keyword.modifier2)
;; #9ADE7A #000000 0 0 0 5
(lifetime
(identifier) @attribute1)
;; #9ADE7A #000000 0 0 0 5
(lifetime
(identifier) @attribute.builtin1
(#match? @attribute.builtin1 "^(static|_)$"))
;; #FF8F40 #000000 0 0 0 1
"fn" @keyword.function1
;; #FF8F40 #000000 0 0 0 1
[
"return"
"yield"
] @keyword.return1
;; #F29668 #000000 0 0 0 1
(type_cast_expression
"as" @keyword.operator1)
;; #F29668 #000000 0 0 0 1
(qualified_type
"as" @keyword.operator2)
;; #61AFEF #000000 0 0 0 9
(use_list
(self) @module10)
;; #61AFEF #000000 0 0 0 9
(scoped_use_list
(self) @module11)
;; #61AFEF #000000 0 0 0 9
(scoped_identifier
[
(crate)
(super)
(self)
] @module12)
;; #61AFEF #000000 0 0 0 9
(visibility_modifier
[
(crate)
(super)
(self)
] @module13)
;; #FF8F40 #000000 0 0 0 1
[
"if"
"else"
"match"
] @keyword.conditional1
;; #FF8F40 #000000 0 0 0 1
[
"break"
"continue"
"in"
"loop"
"while"
] @keyword.repeat1
;; #FF8F40 #000000 0 0 0 1
"for" @keyword2
;; #FF8F40 #000000 0 0 0 1
(for_expression
"for" @keyword.repeat2)
; ============================================================
; Operators
; ============================================================
;; #F29668 #000000 0 1 0 1
[
"!"
"!="
"%"
"%="
"&"
"&&"
"&="
"*"
"*="
"+"
"+="
"-"
"-="
".."
"..="
"..."
"/"
"/="
"<"
"<<"
"<<="
"<="
"="
"=="
">"
">="
">>"
">>="
"?"
"@"
"^"
"^="
"|"
"|="
"||"
] @operator1
;; #BFBDB6 #000000 0 0 0 1
(use_wildcard
"*" @character.special2)
;; #BFBDB6 #000000 0 0 0 1
(remaining_field_pattern
".." @character.special3)
;; #BFBDB6 #000000 0 0 0 1
(range_pattern
[
".."
"..="
"..."
] @character.special4)
; ============================================================
; Punctuation
; ============================================================
;; #BFBDB6 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket1
;; #BFBDB6 #000000 0 0 0 1
(closure_parameters
"|" @punctuation.bracket2)
;; #BFBDB6 #000000 0 0 0 1
(type_arguments
[
"<"
">"
] @punctuation.bracket3)
;; #BFBDB6 #000000 0 0 0 1
(type_parameters
[
"<"
">"
] @punctuation.bracket4)
;; #BFBDB6 #000000 0 0 0 1
(bracketed_type
[
"<"
">"
] @punctuation.bracket5)
;; #BFBDB6 #000000 0 0 0 1
(for_lifetimes
[
"<"
">"
] @punctuation.bracket6)
;; #BFBDB6 #000000 0 1 0 1
[
","
"."
":"
"::"
";"
"->"
"=>"
] @punctuation.delimiter1
;; #BFBDB6 #000000 0 0 0 1
(attribute_item
"#" @punctuation.special1)
;; #BFBDB6 #000000 0 0 0 1
(inner_attribute_item
[
"!"
"#"
] @punctuation.special2)
;; #FF8F40 #000000 0 0 0 2
(macro_invocation
"!" @function.macro9)
;; #7DCFFF #000000 0 0 0 1
(never_type
"!" @type.builtin2)
; ============================================================
; Panic / Assert / Debug Macros
; ============================================================
;; #FF6347 #000000 0 0 0 2
(macro_invocation
macro: (identifier) @_identifier1 @keyword.exception2
"!" @keyword.exception2
(#match? @_identifier1 "^panic$"))
;; #FF8F40 #000000 0 0 0 2
(macro_invocation
macro: (identifier) @_identifier2 @keyword.exception3
"!" @keyword.exception3
(#match? @_identifier2 "assert"))
;; #7DCFFF #000000 0 0 0 2
(macro_invocation
macro: (identifier) @_identifier3 @keyword.debug1
"!" @keyword.debug1
(#match? @_identifier3 "^dbg$"))
; ============================================================
; Comments
; ============================================================
;; #99ADBF #000000 0 1 0 1
[
(line_comment)
(block_comment)
(outer_doc_comment_marker)
(inner_doc_comment_marker)
] @comment1
(line_comment
(doc_comment)) @comment2
(block_comment
(doc_comment)) @comment3
; ============================================================
; Regex Strings (highlighted)
; ============================================================
(call_expression
function: (scoped_identifier
path: (identifier) @_regex1
(#match? @_regex1 "Regex")
name: (identifier) @_new1
(#match? @_new1 "^new$"))
arguments: (arguments
(raw_string_literal
;; !regex
(string_content) @string.regexp)))
(call_expression
function: (scoped_identifier
path: (scoped_identifier
(identifier) @_regex2
(#match? @_regex2 "Regex") .)
name: (identifier) @_new2
(#match? @_new2 "^new$"))
arguments: (arguments
(raw_string_literal
(string_content) @string.regexp)))
(call_expression
function: (scoped_identifier
path: (identifier) @_regex3
(#match? @_regex3 "Regex")
name: (identifier) @_new3
(#match? @_new3 "^new$"))
arguments: (arguments
(array_expression
(raw_string_literal
(string_content) @string.regexp))))
(call_expression
function: (scoped_identifier
path: (scoped_identifier
(identifier) @_regex4
(#match? @_regex4 "Regex") .)
name: (identifier) @_new4
(#match? @_new4 "^new$"))
arguments: (arguments
(array_expression
(raw_string_literal
(string_content) @string.regexp))))

469
grammar/sql.scm Normal file
View File

@@ -0,0 +1,469 @@
;; #D2A6FF #000000 0 0 0 1
(object_reference
name: (identifier) @type)
;; #7dcfff #000000 0 0 0 2
(invocation
(object_reference
name: (identifier) @function.call))
((term
value: (cast
name: (keyword_cast) @function.call
parameter: [(literal)]?)))
[
(keyword_gist)
(keyword_btree)
(keyword_hash)
(keyword_spgist)
(keyword_gin)
(keyword_brin)
(keyword_array)
(keyword_object_id)
] @function.call
;; #D2A6FF #000000 0 0 0 1
(relation
alias: (identifier) @variable)
(term
alias: (identifier) @variable)
;; #7dcfff #000000 0 0 0 2
(field
name: (identifier) @field)
;; #FF8F40 #000000 0 0 0 2
((literal) @number
(#match? @number "^[-+0-9]+$"))
;; #F29668 #000000 0 0 0 2
((literal) @float
(#match? @float "^[-+0-9]+\\.[0-9]+$"))
;; #AAD94C #000000 0 0 0 0
(literal) @string
;; #99ADBF #000000 0 1 0 1
(comment) @comment @spell
(marginalia) @comment
(parameter) @parameter
;; #F29668 #000000 0 0 0 1
[
(keyword_true)
(keyword_false)
] @boolean
;; #F07178 #000000 0 0 0 1
[
(keyword_asc)
(keyword_desc)
(keyword_terminated)
(keyword_escaped)
(keyword_unsigned)
(keyword_nulls)
(keyword_last)
(keyword_delimited)
(keyword_replication)
(keyword_auto_increment)
(keyword_default)
(keyword_collate)
(keyword_concurrently)
(keyword_engine)
(keyword_always)
(keyword_generated)
(keyword_preceding)
(keyword_following)
(keyword_first)
(keyword_current_timestamp)
(keyword_immutable)
(keyword_atomic)
(keyword_parallel)
(keyword_leakproof)
(keyword_safe)
(keyword_cost)
(keyword_strict)
] @attribute
;; #7dcfff #000000 0 0 0 2
[
(keyword_materialized)
(keyword_recursive)
(keyword_temp)
(keyword_temporary)
(keyword_unlogged)
(keyword_external)
(keyword_parquet)
(keyword_csv)
(keyword_rcfile)
(keyword_textfile)
(keyword_orc)
(keyword_avro)
(keyword_jsonfile)
(keyword_sequencefile)
(keyword_volatile)
] @storageclass
;; #F29668 #000000 0 0 0 1
[
(keyword_case)
(keyword_when)
(keyword_then)
(keyword_else)
] @conditional
;; #D2A6FF #000000 0 0 0 1
[
(keyword_select)
(keyword_from)
(keyword_where)
(keyword_index)
(keyword_join)
(keyword_primary)
(keyword_delete)
(keyword_create)
(keyword_show)
(keyword_unload)
(keyword_insert)
(keyword_merge)
(keyword_distinct)
(keyword_replace)
(keyword_update)
(keyword_into)
(keyword_overwrite)
(keyword_matched)
(keyword_values)
(keyword_value)
(keyword_attribute)
(keyword_set)
(keyword_left)
(keyword_right)
(keyword_outer)
(keyword_inner)
(keyword_full)
(keyword_order)
(keyword_partition)
(keyword_group)
(keyword_with)
(keyword_without)
(keyword_as)
(keyword_having)
(keyword_limit)
(keyword_offset)
(keyword_table)
(keyword_tables)
(keyword_key)
(keyword_references)
(keyword_foreign)
(keyword_constraint)
(keyword_force)
(keyword_use)
(keyword_include)
(keyword_for)
(keyword_if)
(keyword_exists)
(keyword_column)
(keyword_columns)
(keyword_cross)
(keyword_lateral)
(keyword_natural)
(keyword_alter)
(keyword_drop)
(keyword_add)
(keyword_view)
(keyword_end)
(keyword_is)
(keyword_using)
(keyword_between)
(keyword_window)
(keyword_no)
(keyword_data)
(keyword_type)
(keyword_rename)
(keyword_to)
(keyword_schema)
(keyword_owner)
(keyword_authorization)
(keyword_all)
(keyword_any)
(keyword_some)
(keyword_returning)
(keyword_begin)
(keyword_commit)
(keyword_rollback)
(keyword_transaction)
(keyword_only)
(keyword_like)
(keyword_similar)
(keyword_over)
(keyword_change)
(keyword_modify)
(keyword_after)
(keyword_before)
(keyword_range)
(keyword_rows)
(keyword_groups)
(keyword_exclude)
(keyword_current)
(keyword_ties)
(keyword_others)
(keyword_zerofill)
(keyword_format)
(keyword_fields)
(keyword_row)
(keyword_sort)
(keyword_compute)
(keyword_comment)
(keyword_location)
(keyword_cached)
(keyword_uncached)
(keyword_lines)
(keyword_stored)
(keyword_virtual)
(keyword_partitioned)
(keyword_analyze)
(keyword_explain)
(keyword_verbose)
(keyword_truncate)
(keyword_rewrite)
(keyword_optimize)
(keyword_vacuum)
(keyword_cache)
(keyword_language)
(keyword_called)
(keyword_conflict)
(keyword_declare)
(keyword_filter)
(keyword_function)
(keyword_input)
(keyword_name)
(keyword_oid)
(keyword_oids)
(keyword_precision)
(keyword_regclass)
(keyword_regnamespace)
(keyword_regproc)
(keyword_regtype)
(keyword_restricted)
(keyword_return)
(keyword_returns)
(keyword_separator)
(keyword_setof)
(keyword_stable)
(keyword_support)
(keyword_tblproperties)
(keyword_trigger)
(keyword_unsafe)
(keyword_admin)
(keyword_connection)
(keyword_cycle)
(keyword_database)
(keyword_encrypted)
(keyword_increment)
(keyword_logged)
(keyword_none)
(keyword_owned)
(keyword_password)
(keyword_reset)
(keyword_role)
(keyword_sequence)
(keyword_start)
(keyword_restart)
(keyword_tablespace)
(keyword_split)
(keyword_tablets)
(keyword_until)
(keyword_user)
(keyword_valid)
(keyword_action)
(keyword_definer)
(keyword_invoker)
(keyword_security)
(keyword_extension)
(keyword_version)
(keyword_out)
(keyword_inout)
(keyword_variadic)
(keyword_ordinality)
(keyword_session)
(keyword_isolation)
(keyword_level)
(keyword_serializable)
(keyword_repeatable)
(keyword_read)
(keyword_write)
(keyword_committed)
(keyword_uncommitted)
(keyword_deferrable)
(keyword_names)
(keyword_zone)
(keyword_immediate)
(keyword_deferred)
(keyword_constraints)
(keyword_snapshot)
(keyword_characteristics)
(keyword_off)
(keyword_follows)
(keyword_precedes)
(keyword_each)
(keyword_instead)
(keyword_of)
(keyword_initially)
(keyword_old)
(keyword_new)
(keyword_referencing)
(keyword_statement)
(keyword_execute)
(keyword_procedure)
(keyword_copy)
(keyword_delimiter)
(keyword_encoding)
(keyword_escape)
(keyword_force_not_null)
(keyword_force_null)
(keyword_force_quote)
(keyword_freeze)
(keyword_header)
(keyword_match)
(keyword_program)
(keyword_quote)
(keyword_stdin)
(keyword_extended)
(keyword_main)
(keyword_plain)
(keyword_storage)
(keyword_compression)
(keyword_duplicate)
(keyword_while)
] @keyword
;; #F07178 #000000 0 0 0 1
[
(keyword_restrict)
(keyword_unbounded)
(keyword_unique)
(keyword_cascade)
(keyword_delayed)
(keyword_high_priority)
(keyword_low_priority)
(keyword_ignore)
(keyword_nothing)
(keyword_check)
(keyword_option)
(keyword_local)
(keyword_cascaded)
(keyword_wait)
(keyword_nowait)
(keyword_metadata)
(keyword_incremental)
(keyword_bin_pack)
(keyword_noscan)
(keyword_stats)
(keyword_statistics)
(keyword_maxvalue)
(keyword_minvalue)
] @type.qualifier
;; #7dcfff #000000 0 0 0 2
[
(keyword_int)
(keyword_null)
(keyword_boolean)
(keyword_binary)
(keyword_varbinary)
(keyword_image)
(keyword_bit)
(keyword_inet)
(keyword_character)
(keyword_smallserial)
(keyword_serial)
(keyword_bigserial)
(keyword_smallint)
(keyword_mediumint)
(keyword_bigint)
(keyword_tinyint)
(keyword_decimal)
(keyword_float)
(keyword_double)
(keyword_numeric)
(keyword_real)
(double)
(keyword_money)
(keyword_smallmoney)
(keyword_char)
(keyword_nchar)
(keyword_varchar)
(keyword_nvarchar)
(keyword_varying)
(keyword_text)
(keyword_string)
(keyword_uuid)
(keyword_json)
(keyword_jsonb)
(keyword_xml)
(keyword_bytea)
(keyword_enum)
(keyword_date)
(keyword_datetime)
(keyword_time)
(keyword_datetime2)
(keyword_datetimeoffset)
(keyword_smalldatetime)
(keyword_timestamp)
(keyword_timestamptz)
(keyword_geometry)
(keyword_geography)
(keyword_box2d)
(keyword_box3d)
(keyword_interval)
] @type.builtin
;; #F29668 #000000 0 0 0 1
[
(keyword_in)
(keyword_and)
(keyword_or)
(keyword_not)
(keyword_by)
(keyword_on)
(keyword_do)
(keyword_union)
(keyword_except)
(keyword_intersect)
] @keyword.operator
;; #F29668 #000000 0 1 0 1
[
"+"
"-"
"*"
"/"
"%"
"^"
":="
"="
"<"
"<="
"!="
">="
">"
"<>"
(op_other)
(op_unary_other)
] @operator
;; #888888 #000000 0 0 0 1
[
"("
")"
] @punctuation.bracket
;; #888888 #000000 0 1 0 1
[
";"
","
"."
] @punctuation.delimiter

56
grammar/toml.scm Normal file
View File

@@ -0,0 +1,56 @@
;; #F0F8FF #000000 0 0 0 2
(bare_key) @type
;; #FFFFFF #000000 0 0 0 1
(quoted_key) @string.quoted
;; #D2A6FF #000000 0 0 0 0
(pair
(bare_key)) @property
;; #D2A6FF #000000 0 0 0 0
(pair
(dotted_key
(bare_key) @property))
;; #F29668 #000000 0 0 0 1
(boolean) @boolean
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #AAD94C #000000 0 0 0 1
(string) @string
;; #7dcfff #000000 0 0 0 2
[
(integer)
(float)
] @number
;; #FFFFFF #000000 0 0 0 1
[
(offset_date_time)
(local_date_time)
(local_date)
(local_time)
] @string.special
;; #888888 #000000 0 1 0 3
[
"."
","
] @punctuation.delimiter
;; #F29668 #000000 0 0 0 1
"=" @operator
;; #888888 #000000 0 0 0 3
[
"["
"]"
"[["
"]]"
"{"
"}"
] @punctuation.bracket

98
grammar/yaml.scm Normal file
View File

@@ -0,0 +1,98 @@
;; #F29668 #000000 0 0 0 1
(boolean_scalar) @boolean
;; #F07178 #000000 0 0 0 1
(null_scalar) @constant.builtin
;; #AAD94C #000000 0 0 0 0
[
(double_quote_scalar)
(single_quote_scalar)
] @string
;; #FFFFFF #000000 0 0 0 0
[
(block_scalar)
(string_scalar)
] @string.abs
;; #7dcfff #000000 0 0 0 2
[
(integer_scalar)
(float_scalar)
] @number
;; #99ADBF #000000 0 1 0 1
(comment) @comment
;; #D2A6FF #000000 0 0 0 1
[
(anchor_name)
(alias_name)
] @label
;; #7dcfff #000000 0 0 0 2
(tag) @type
;; #F07178 #000000 0 0 0 1
[
(yaml_directive)
(tag_directive)
(reserved_directive)
] @attribute
;; #D2A6FF #000000 0 0 0 1
(block_mapping_pair
key: (flow_node
[
(double_quote_scalar)
(single_quote_scalar)
] @property))
;; #D2A6FF #000000 0 0 0 1
(block_mapping_pair
key: (flow_node
(plain_scalar
(string_scalar) @property)))
;; #D2A6FF #000000 0 0 0 1
(flow_mapping
(_
key: (flow_node
[
(double_quote_scalar)
(single_quote_scalar)
] @property)))
;; #D2A6FF #000000 0 0 0 1
(flow_mapping
(_
key: (flow_node
(plain_scalar
(string_scalar) @property))))
;; #F38BA8 #000000 0 1 0 3
[
","
"-"
":"
">"
"?"
"|"
] @punctuation.delimiter
;; #888888 #000000 0 0 0 3
[
"["
"]"
"{"
"}"
] @punctuation.bracket
;; #AAD94C #000000 0 1 0 3
[
"*"
"&"
"---"
"..."
] @punctuation.special

View File

@@ -1,23 +1,19 @@
#ifndef EDITOR_H #ifndef EDITOR_H
#define EDITOR_H #define EDITOR_H
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h"
#include "./knot.h" #include "./knot.h"
#include "./pch.h"
#include "./ui.h" #include "./ui.h"
#include "./utils.h" #include "./utils.h"
#include <algorithm> #include "ts_def.h"
#include <cstdint> #include <cstdint>
#include <map>
#include <shared_mutex> #include <shared_mutex>
#include <unordered_map>
#include <vector>
#define CHAR 0 #define CHAR 0
#define WORD 1 #define WORD 1
#define LINE 2 #define LINE 2
#define EXTRA_META 4 #define EXTRA_META 4
#define INDENT_WIDTH 2 #define INDENT_WIDTH 2
struct Highlight { struct Highlight {
@@ -98,8 +94,52 @@ struct SpanCursor {
} }
}; };
struct VHint {
Coord pos;
std::string hint;
bool operator<(const VHint &other) const { return pos < other.pos; }
};
struct VWarn {
uint32_t line;
std::string text;
int8_t type; // For hl
bool operator<(const VWarn &other) const { return line < other.line; }
};
struct VAI {
Coord pos;
char *text;
uint32_t len;
uint32_t lines; // number of \n in text for speed .. the ai part will not
// line wrap but multiline ones need to have its own lines
// after the first one
};
struct TSSetBase {
std::string lang;
TSParser *parser;
std::string query_file;
TSQuery *query;
std::map<uint16_t, Highlight> query_map;
std::map<uint16_t, Language> injection_map;
const TSLanguage *language;
};
struct TSSet : TSSetBase {
std::vector<TSRange> ranges;
};
struct TSSetMain : TSSetBase {
TSTree *tree;
std::unordered_map<std::string, TSSet> injections;
};
struct Editor { struct Editor {
const char *filename; std::string filename;
std::string uri;
Knot *root; Knot *root;
std::shared_mutex knot_mtx; std::shared_mutex knot_mtx;
Coord cursor; Coord cursor;
@@ -110,17 +150,20 @@ struct Editor {
Coord position; Coord position;
Coord size; Coord size;
Coord scroll; Coord scroll;
TSTree *tree; TSSetMain ts;
TSParser *parser;
TSQuery *query;
const TSLanguage *language;
Queue<TSInputEdit> edit_queue; Queue<TSInputEdit> edit_queue;
std::vector<Highlight> query_map;
std::vector<Fold> folds; std::vector<Fold> folds;
Spans spans; Spans spans;
Spans def_spans; Spans def_spans;
uint32_t hooks[94]; uint32_t hooks[94];
bool jumper_set; bool jumper_set;
std::shared_mutex v_mtx;
std::vector<VHint> hints;
std::vector<VWarn> warnings;
VAI ai;
std::shared_mutex lsp_mtx;
struct LSPInstance *lsp;
int lsp_version = 1;
}; };
inline const Fold *fold_for_line(const std::vector<Fold> &folds, inline const Fold *fold_for_line(const std::vector<Fold> &folds,
@@ -180,7 +223,8 @@ void apply_edit(std::vector<Span> &spans, uint32_t x, int64_t y);
void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows); void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows);
void apply_hook_deletion(Editor *editor, uint32_t removal_start, void apply_hook_deletion(Editor *editor, uint32_t removal_start,
uint32_t removal_end); 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 free_editor(Editor *editor);
void render_editor(Editor *editor); void render_editor(Editor *editor);
void fold(Editor *editor, uint32_t start_line, uint32_t end_line); void fold(Editor *editor, uint32_t start_line, uint32_t end_line);
@@ -188,6 +232,8 @@ void cursor_up(Editor *editor, uint32_t number);
void cursor_down(Editor *editor, uint32_t number); void cursor_down(Editor *editor, uint32_t number);
Coord move_left(Editor *editor, Coord cursor, uint32_t number); Coord move_left(Editor *editor, Coord cursor, uint32_t number);
Coord move_right(Editor *editor, Coord cursor, uint32_t number); Coord move_right(Editor *editor, Coord cursor, uint32_t number);
Coord move_left_pure(Editor *editor, Coord cursor, uint32_t number);
Coord move_right_pure(Editor *editor, Coord cursor, uint32_t number);
void cursor_left(Editor *editor, uint32_t number); void cursor_left(Editor *editor, uint32_t number);
void cursor_right(Editor *editor, uint32_t number); void cursor_right(Editor *editor, uint32_t number);
void scroll_up(Editor *editor, int32_t number); void scroll_up(Editor *editor, int32_t number);
@@ -218,5 +264,6 @@ void apply_line_deletion(Editor *editor, uint32_t removal_start,
uint32_t leading_indent(const char *line, uint32_t len); uint32_t leading_indent(const char *line, uint32_t len);
uint32_t get_indent(Editor *editor, Coord cursor); uint32_t get_indent(Editor *editor, Coord cursor);
bool closing_after_cursor(const char *line, uint32_t len, uint32_t col); bool closing_after_cursor(const char *line, uint32_t len, uint32_t col);
void editor_lsp_handle(Editor *editor, json msg);
#endif #endif

View File

@@ -1,9 +1,8 @@
#ifndef ROPE_H #ifndef ROPE_H
#define ROPE_H #define ROPE_H
#include "./pch.h"
#include "./utils.h" #include "./utils.h"
#include <cstdint>
#include <vector>
#define MIN_CHUNK_SIZE 64 // 64 Bytes #define MIN_CHUNK_SIZE 64 // 64 Bytes
#define MAX_CHUNK_SIZE 1024 * 8 // 8192 Bytes (8 KiB) #define MAX_CHUNK_SIZE 1024 * 8 // 8192 Bytes (8 KiB)

55
include/lsp.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef LSP_H
#define LSP_H
#include "./editor.h"
#include "./pch.h"
#include "utils.h"
struct LSP {
const char *command;
std::vector<const char *> args;
};
struct LSPPending {
std::string method;
Editor *editor = nullptr;
std::function<void(Editor *, std::string, json)> callback;
};
struct LSPOpenRequest {
Language language;
Editor *editor;
};
struct LSPInstance {
std::shared_mutex mtx;
const LSP *lsp;
std::string root_dir;
int pid{-1};
int stdin_fd{-1};
int stdout_fd{-1};
bool initialized = false;
uint32_t last_id = 0;
Queue<json> inbox;
Queue<json> outbox;
std::unordered_map<uint32_t, LSPPending *> pending;
std::vector<Editor *> editors;
};
extern std::shared_mutex active_lsps_mtx;
extern std::unordered_map<uint8_t, LSPInstance *> active_lsps;
void lsp_worker();
void lsp_handle(LSPInstance *lsp, json message);
LSPInstance *get_or_init_lsp(uint8_t lsp_id);
void close_lsp(uint8_t lsp_id);
void request_add_to_lsp(Language language, Editor *editor);
void add_to_lsp(Language language, Editor *editor);
void remove_from_lsp(Editor *editor);
void lsp_send(LSPInstance *lsp, json message, LSPPending *pending);
#endif

View File

@@ -1,8 +1,7 @@
#ifndef MAIN_H #ifndef MAIN_H
#define MAIN_H #define MAIN_H
#include <atomic> #include "./pch.h"
#include <vector>
#define NORMAL 0 #define NORMAL 0
#define INSERT 1 #define INSERT 1

139
include/maps.h Normal file
View File

@@ -0,0 +1,139 @@
#ifndef MAPS_H
#define MAPS_H
#include "./lsp.h"
#include "./pch.h"
#include "./ts_def.h"
static const std::unordered_map<uint8_t, LSP> 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<std::string, Language> kLanguages = {
{"bash", {"bash", LANG(bash)}},
{"c", {"c", LANG(cpp), 1}},
{"cpp", {"cpp", LANG(cpp), 1}},
{"h", {"h", LANG(cpp), 1}},
{"css", {"css", LANG(css)}},
{"fish", {"fish", LANG(fish)}},
{"go", {"go", LANG(go)}},
{"haskell", {"haskell", LANG(haskell)}},
{"html", {"html", LANG(html)}},
{"javascript", {"javascript", LANG(javascript)}},
{"json", {"json", LANG(json)}},
{"lua", {"lua", LANG(lua)}},
{"make", {"make", LANG(make)}},
{"python", {"python", LANG(python)}},
{"ruby", {"ruby", LANG(ruby)}},
{"rust", {"rust", LANG(rust)}},
{"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)}},
{"markdown_inline", {"markdown_inline", LANG(markdown_inline)}},
{"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)}},
};
static const std::unordered_map<std::string, std::string> 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"},
{"jsx", "javascript"},
{"json", "json"},
{"jsonc", "json"},
{"lua", "lua"},
{"mk", "make"},
{"makefile", "make"},
{"py", "python"},
{"rb", "ruby"},
{"rs", "rust"},
{"diff", "diff"},
{"patch", "diff"},
{"erb", "embedded_template"},
{"etlua", "embedded_template"},
{"gd", "gdscript"},
{"gitattributes", "gitattributes"},
{"gitignore", "gitignore"},
{"mod", "gomod"},
{"ini", "ini"},
{"gitmodules", "ini"},
{"md", "markdown"},
{"markdown", "markdown"},
{"conf", "nginx"},
{"php", "php"},
{"scm", "query"},
{"regex", "regex"},
{"sql", "sql"},
{"toml", "toml"},
{"yaml", "yaml"},
{"yml", "yaml"},
};
static const std::unordered_map<std::string, std::string> kMimeToLang = {
{"text/x-c", "c"},
{"text/x-c++", "cpp"},
{"text/x-shellscript", "bash"},
{"application/json", "json"},
{"text/javascript", "javascript"},
{"text/html", "html"},
{"text/css", "css"},
{"text/x-python", "python"},
{"text/x-ruby", "ruby"},
{"text/x-go", "go"},
{"text/x-haskell", "haskell"},
{"text/x-rust", "rust"},
{"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"},
};
#endif

42
include/pch.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef PCH_H
#define PCH_H
#define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h"
#include <algorithm>
#include <atomic>
#include <cctype>
#include <chrono>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <filesystem>
#include <fstream>
#include <functional>
#include <limits.h>
#include <magic.h>
#include <map>
#include <mutex>
#include <nlohmann/json.hpp>
#include <optional>
#include <pcre2.h>
#include <queue>
#include <shared_mutex>
#include <string.h>
#include <string>
#include <sys/ioctl.h>
#include <termios.h>
#include <thread>
#include <unistd.h>
#include <unordered_map>
#include <vector>
using json = nlohmann::json;
using namespace std::chrono_literals;
#endif

View File

@@ -2,14 +2,14 @@
#define TS_H #define TS_H
#include "./editor.h" #include "./editor.h"
#include "./pch.h"
#include "./utils.h" #include "./utils.h"
#include <pcre2.h>
#define HEX(s) (static_cast<uint32_t>(std::stoul(s, nullptr, 16))) #define HEX(s) (static_cast<uint32_t>(std::stoul(s, nullptr, 16)))
extern std::unordered_map<std::string, pcre2_code *> regex_cache; extern std::unordered_map<std::string, pcre2_code *> regex_cache;
TSQuery *load_query(const char *query_path, Editor *editor); TSQuery *load_query(const char *query_path, TSSetBase *set);
void ts_collect_spans(Editor *editor); void ts_collect_spans(Editor *editor);
void clear_regex_cache(); void clear_regex_cache();

View File

@@ -1,24 +1,46 @@
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h" #ifndef TS_DEF_H
#include <string> #define TS_DEF_H
#include "./pch.h"
#define LANG(name) tree_sitter_##name
#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)()
struct Language { struct Language {
std::string name; std::string name;
const TSLanguage *(*fn)(); const TSLanguage *(*fn)();
uint8_t lsp_id = 0;
}; };
extern "C" { TS_DEF(ruby);
const TSLanguage *tree_sitter_bash(); TS_DEF(bash);
const TSLanguage *tree_sitter_c(); TS_DEF(cpp);
const TSLanguage *tree_sitter_cpp(); TS_DEF(css);
const TSLanguage *tree_sitter_css(); TS_DEF(fish);
const TSLanguage *tree_sitter_fish(); TS_DEF(go);
const TSLanguage *tree_sitter_go(); TS_DEF(haskell);
const TSLanguage *tree_sitter_haskell(); TS_DEF(html);
const TSLanguage *tree_sitter_html(); TS_DEF(javascript);
const TSLanguage *tree_sitter_javascript(); TS_DEF(json);
const TSLanguage *tree_sitter_json(); TS_DEF(lua);
const TSLanguage *tree_sitter_lua(); TS_DEF(regex);
const TSLanguage *tree_sitter_make(); TS_DEF(query);
const TSLanguage *tree_sitter_python(); TS_DEF(markdown);
const TSLanguage *tree_sitter_ruby(); TS_DEF(markdown_inline);
} TS_DEF(embedded_template);
TS_DEF(php);
TS_DEF(python);
TS_DEF(rust);
TS_DEF(sql);
TS_DEF(gitattributes);
TS_DEF(gitignore);
TS_DEF(gomod);
TS_DEF(nginx);
TS_DEF(toml);
TS_DEF(yaml);
TS_DEF(ini);
TS_DEF(diff);
TS_DEF(make);
TS_DEF(gdscript);
#endif

View File

@@ -1,16 +1,8 @@
#ifndef UI_H #ifndef UI_H
#define UI_H #define UI_H
#include "./pch.h"
#include "./utils.h" #include "./utils.h"
#include <atomic>
#include <cstdint>
#include <mutex>
#include <string.h>
#include <string>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include <vector>
#define KEY_CHAR 0 #define KEY_CHAR 0
#define KEY_SPECIAL 1 #define KEY_SPECIAL 1
@@ -90,6 +82,8 @@ extern std::mutex screen_mutex;
Coord start_screen(); Coord start_screen();
void end_screen(); void end_screen();
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags);
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg, void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags); uint32_t bg, uint8_t flags);
void set_cursor(int row, int col, int type, bool show_cursor_param); void set_cursor(int row, int col, int type, bool show_cursor_param);

View File

@@ -1,16 +1,8 @@
#ifndef UTILS_H #ifndef UTILS_H
#define UTILS_H #define UTILS_H
#include "./pch.h"
#include "./ts_def.h" #include "./ts_def.h"
#include <chrono>
#include <functional>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512
template <typename T> struct Queue { template <typename T> struct Queue {
std::queue<T> q; std::queue<T> q;
@@ -20,6 +12,10 @@ template <typename T> struct Queue {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
q.push(val); q.push(val);
} }
T front() {
std::lock_guard<std::mutex> lock(m);
return q.front();
}
bool pop(T &val) { bool pop(T &val) {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
if (q.empty()) if (q.empty())
@@ -28,6 +24,10 @@ template <typename T> struct Queue {
q.pop(); q.pop();
return true; return true;
} }
void pop() {
std::lock_guard<std::mutex> lock(m);
q.pop();
}
bool empty() { bool empty() {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
return q.empty(); return q.empty();
@@ -52,6 +52,8 @@ struct Coord {
bool operator>=(const Coord &other) const { return !(*this < other); } 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); int display_width(const char *str, size_t len);
uint32_t get_visual_col_from_bytes(const char *line, uint32_t len, uint32_t get_visual_col_from_bytes(const char *line, uint32_t len,
uint32_t byte_limit); uint32_t byte_limit);
@@ -61,6 +63,7 @@ void log(const char *fmt, ...);
std::string get_exe_dir(); std::string get_exe_dir();
char *load_file(const char *path, uint32_t *out_len); char *load_file(const char *path, uint32_t *out_len);
char *detect_file_type(const char *filename); char *detect_file_type(const char *filename);
int utf8_byte_offset_to_utf16(const char *s, size_t byte_pos);
Language language_for_file(const char *filename); Language language_for_file(const char *filename);
void copy_to_clipboard(const char *text, size_t len); void copy_to_clipboard(const char *text, size_t len);
char *get_from_clipboard(uint32_t *out_len); char *get_from_clipboard(uint32_t *out_len);

1
libs/tree-sitter-diff Submodule

Submodule libs/tree-sitter-diff added at 2520c3f934

1
libs/tree-sitter-ini Submodule

Submodule libs/tree-sitter-ini added at e4018b5176

1
libs/tree-sitter-php Submodule

Submodule libs/tree-sitter-php added at 7d07b41ce2

1
libs/tree-sitter-rust Submodule

Submodule libs/tree-sitter-rust added at 261b20226c

1
libs/tree-sitter-sql Submodule

Submodule libs/tree-sitter-sql added at 2d5dcd16f9

1
libs/tree-sitter-toml Submodule

Submodule libs/tree-sitter-toml added at 64b56832c2

1
libs/tree-sitter-yaml Submodule

Submodule libs/tree-sitter-yaml added at 7708026449

119
samples/Makefile Normal file
View File

@@ -0,0 +1,119 @@
SRC_DIR := src
BIN_DIR := bin
OBJ_DIR := build
INCLUDE_DIR := include
TARGET_DEBUG := $(BIN_DIR)/crib-dbg
TARGET_RELEASE := $(BIN_DIR)/crib
PCH_DEBUG := $(OBJ_DIR)/debug/pch.h.gch
PCH_RELEASE := $(OBJ_DIR)/release/pch.h.gch
CCACHE := ccache
CXX_DEBUG := $(CCACHE) g++
CXX_RELEASE := $(CCACHE) clang++
CFLAGS_DEBUG := -std=c++20 -Wall -Wextra -O0 -fno-inline -gsplit-dwarf -g -fsanitize=address -fno-omit-frame-pointer
CFLAGS_RELEASE := -std=c++20 -O3 -march=native -flto=thin \
-fno-exceptions -fno-rtti -fstrict-aliasing \
-ffast-math -funroll-loops \
-fvisibility=hidden \
-fomit-frame-pointer -DNDEBUG -s \
-mllvm -vectorize-loops \
-fno-unwind-tables -fno-asynchronous-unwind-tables
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
UNICODE_SRC := $(wildcard libs/unicode_width/*.c)
UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_width/%.o,$(UNICODE_SRC))
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
NGINX_OBJ_PARSER := libs/tree-sitter-nginx/build/Release/obj.target/tree_sitter_nginx_binding/src/parser.o
GITIGNORE_OBJ_PARSER := libs/tree-sitter-gitignore/build/Release/obj.target/tree_sitter_ignore_binding/src/parser.o
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
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
MD_I_OBJ_PARSER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown-inline/src/parser.o
MD_I_OBJ_SCANNER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown-inline/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) \
$(FISH_OBJ_SCANNER) \
$(MD_OBJ_PARSER) \
$(MD_OBJ_SCANNER) \
$(MD_I_OBJ_PARSER) \
$(MD_I_OBJ_SCANNER) \
-lpcre2-8 -lmagic
SRC := $(wildcard $(SRC_DIR)/*.cc)
OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC))
OBJ_RELEASE := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/release/%.o,$(SRC))
DEP_DEBUG := $(OBJ_DEBUG:.o=.d)
DEP_RELEASE := $(OBJ_RELEASE:.o=.d)
.PHONY: all test release clean
all: debug
test: $(TARGET_DEBUG)
release: $(TARGET_RELEASE)
$(PCH_DEBUG): $(INCLUDE_DIR)/pch.h
mkdir -p $(dir $@)
$(CXX_DEBUG) $(PCH_CFLAGS_DEBUG) -o $@ $<
$(PCH_RELEASE): $(INCLUDE_DIR)/pch.h
mkdir -p $(dir $@)
$(CXX_RELEASE) $(PCH_CFLAGS_RELEASE) -o $@ $<
$(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG)
mkdir -p $(BIN_DIR)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS)
$(TARGET_RELEASE): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -o $@ $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(LIBS)
$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc $(PCH_DEBUG)
mkdir -p $(dir $@)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE)
mkdir -p $(dir $@)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/debug/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@
DEP_DEBUG += $(UNICODE_OBJ_DEBUG:.o=.d)
DEP_RELEASE += $(UNICODE_OBJ_RELEASE:.o=.d)
-include $(DEP_DEBUG)
-include $(DEP_RELEASE)
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)

View File

@@ -28,12 +28,13 @@ handle_error() {
trap 'handle_error $LINENO' ERR trap 'handle_error $LINENO' ERR
# Multiline string test # Multiline string test
read -r -d '' MULTI <<'EOF' read -r -d '' MULTI <<'CPP'
This is a multi-line
string used to test int main() {
syntax highlighting for
here-documents. }
EOF
CPP
log INFO "Multi-line string loaded" log INFO "Multi-line string loaded"

70
samples/css.css Normal file
View File

@@ -0,0 +1,70 @@
/* === Basic selectors === */
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #121212;
color: #eee;
}
/* Class + ID + attribute */
#main.container[data-theme="dark"] {
padding: 1rem;
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* Pseudo-classes & elements */
a:hover,
a:focus-visible {
color: hsl(210, 80%, 60%);
text-decoration: underline;
}
input::placeholder {
color: #999;
}
/* CSS variables */
:root {
--accent: #4fc3f7;
--spacing: 1rem;
}
.button {
background: var(--accent);
padding: calc(var(--spacing) * 1.5);
}
/* Media query */
@media (max-width: 768px) {
.container {
padding: 0.5rem;
}
}
/* Keyframes */
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Animation usage */
.modal {
animation: fade-in 250ms ease-out;
}
/* Complex selector */
ul > li:not(:last-child)::after {
content: "•";
margin-left: 0.5em;
}
/* Edge cases */
[data-value^="test"]::before {
content: attr(data-value);
}

102
samples/diff.patch Normal file
View File

@@ -0,0 +1,102 @@
--- ./samples/toml.toml 2025-12-26 19:02:50.480936043 +0000
+++ ./samples/yaml.yml 2025-12-26 19:03:27.879765974 +0000
@@ -2,52 +2,65 @@
# Basic types
# ============================================================
-title = "Example TOML Configuration"
-enabled = true
-count = 42
-pi = 3.14159
-empty = ""
+title: "Example YAML Configuration"
+enabled: true
+count: 42
+pi: 3.14159
+empty: ""
# ============================================================
-# Arrays
+# Arrays / Lists
# ============================================================
-fruits = ["apple", "banana", "cherry"]
-numbers = [1, 2, 3, 4, 5]
+fruits:
+ - apple
+ - banana
+ - cherry
-# Nested array
-matrix = [[1, 2], [3, 4]]
+numbers:
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+
+matrix:
+ - [1, 2]
+ - [3, 4]
# ============================================================
-# Tables
+# Nested objects / maps
# ============================================================
-[owner]
-name = "Alice"
-dob = 1979-05-27T07:32:00Z
-
-[database]
-server = "192.168.1.1"
-ports = [ 8001, 8001, 8002 ]
-connection_max = 5000
-enabled = true
+owner:
+ name: Alice
+ dob: 1979-05-27T07:32:00Z
-[servers.alpha]
-ip = "10.0.0.1"
-dc = "east"
+database:
+ server: 192.168.1.1
+ ports:
+ - 8001
+ - 8001
+ - 8002
+ connection_max: 5000
+ enabled: true
-[servers.beta]
-ip = "10.0.0.2"
-dc = "west"
+servers:
+ alpha:
+ ip: 10.0.0.1
+ dc: east
+ beta:
+ ip: 10.0.0.2
+ dc: west
# ============================================================
-# Inline tables
+# Multiline string
# ============================================================
-clients = { name = "Bob", age = 30, active = true }
+description: |
+ This is a YAML file
+ used for testing syntax highlighting.
+ It supports multiple lines.
# ============================================================
-# Multiline strings
+# Special characters
# ============================================================
-description = """
-This is a TOML file
-used for testing syntax highlighting.
-It supports multiple lines.
-"""
+regex_pattern: "^[A-Za-z0-9_]+$"
+path: "C:\\Users\\Alice\\Documents"

View File

@@ -0,0 +1,71 @@
<%# app/views/users/show.html.erb %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= @user.name %> — Profile</title>
<%# Inline Ruby expression %>
<meta name="description" content="<%= @user.bio %>">
<% if @dark_mode %>
<style>
body {
background-color: #111;
color: #eee;
}
</style>
<% end %>
</head>
<body>
<!-- HTML comment -->
<header>
<h1>Welcome, <%= @user.name %></h1>
<p class="subtitle">
Member since <%= @user.created_at.strftime("%Y") %>
</p>
</header>
<% if @user.admin? %>
<section class="admin-panel">
<h2>Admin Tools</h2>
<ul>
<% @tools.each do |tool| %>
<li><%= tool.title %></li>
<% end %>
</ul>
</section>
<% else %>
<p>You do not have admin privileges.</p>
<% end %>
<section class="posts">
<% @posts.each do |post| %>
<article class="post">
<h3><%= post.title %></h3>
<p><%= truncate(post.body, length: 140) %></p>
<%# Conditional rendering %>
<% if post.published? %>
<span class="status published">Published</span>
<% else %>
<span class="status draft">Draft</span>
<% end %>
</article>
<% end %>
</section>
<footer>
<p>&copy; <%= Time.now.year %> Example Corp</p>
<%= link_to "Privacy Policy", "/privacy" %>
</footer>
<script>
// JavaScript inside ERB
const userName = "<%= j @user.name %>";
console.log(`Loaded profile for ${userName}`);
</script>
</body>
</html>

92
samples/fish.fish Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env fish
# Fish highlighting torture test 🐟
# === Variables ===
set normal_var "hello"
set -l local_var 123
set -gx GLOBAL_VAR "world"
set PATH $PATH /usr/local/bin
set --erase OLD_VAR
# Builtin variables
echo $HOME $PWD $USER $FISH_VERSION
# === Strings ===
set single 'single quoted string'
set double "double quoted $normal_var"
set escaped "newline\n tab\t dollar\$"
# === Conditionals ===
if test $normal_var = "hello"
echo "equal"
else if test $normal_var != "world"
echo "not equal"
end
# === Logical operators ===
true and echo "yes"
false or echo "fallback"
not false
# === Arithmetic ===
set x 10
set y 20
math "$x + $y"
if test (math "$x * 2") -gt 15
echo "math works"
end
# === Loops ===
for i in 1 2 3
echo "loop $i"
end
while test $x -gt 0
set x (math "$x - 1")
end
# === Functions ===
function greet --argument name
echo "Hello $name"
end
greet "world"
# === Command substitution ===
set files (ls | grep ".fish")
# === Redirections ===
echo "output" > /tmp/fish_test.txt
cat < /tmp/fish_test.txt >> /tmp/fish_log.txt
# === Process substitution ===
diff (ls /bin) (ls /usr/bin)
# === Case statement ===
switch $argv[1]
case start
echo "Starting"
case stop
echo "Stopping"
case '*'
echo "Unknown"
end
# === Subshell ===
begin
echo "inside begin/end"
end
# === Comments & operators ===
# && || | & ! should all highlight
true && echo "ok" || echo "fail"
# === Regex ===
string match -r '^[a-z]+$' "hello"
# === Test builtin ===
test -f /etc/passwd
test ! -d /does/not/exist
# === Exit ===
exit 0

81
samples/gdscript.gd Normal file
View File

@@ -0,0 +1,81 @@
# Sample GDScript for syntax highlighting
extends Node2D
# ============================================================
# Constants
# ============================================================
const MAX_HEALTH = 100
const PLAYER_SPEED = 200
const PI_APPROX = 3.14159
# ============================================================
# Exported variables
# ============================================================
@export var player_name: String = "Hero"
@export var is_alive: bool = true
# ============================================================
# Signals
# ============================================================
signal health_changed(new_health)
# ============================================================
# Member variables
# ============================================================
var health: int = MAX_HEALTH
var velocity: Vector2 = Vector2.ZERO
var inventory: Array = []
# ============================================================
# Functions
# ============================================================
func _ready() -> void:
print("Player ready:", player_name)
_initialize_inventory()
set_process(true)
func _process(delta: float) -> void:
if is_alive:
_handle_input(delta)
_check_health()
# Private functions
func _initialize_inventory() -> void:
inventory.append("Sword")
inventory.append("Shield")
func _handle_input(delta: float) -> void:
var direction: Vector2 = Vector2.ZERO
if Input.is_action_pressed("ui_right"):
direction.x += 1
if Input.is_action_pressed("ui_left"):
direction.x -= 1
if Input.is_action_pressed("ui_down"):
direction.y += 1
if Input.is_action_pressed("ui_up"):
direction.y -= 1
velocity = direction.normalized() * PLAYER_SPEED
position += velocity * delta
func _check_health() -> void:
if health <= 0:
is_alive = false
print("Player is dead!")
else:
emit_signal("health_changed", health)
# ============================================================
# Example of class definition inside another script
# ============================================================
class Weapon:
var name: String
var damage: int
func _init(name: String, damage: int):
self.name = name
self.damage = damage
func attack():
print(name, "attacks for", damage, "damage")

95
samples/go.go Normal file
View File

@@ -0,0 +1,95 @@
// file: go.go
package example_test
import (
"context"
"fmt"
"math"
"sync"
"testing"
"time"
)
// Simple interface
type Adder interface {
Add(a, b int) int
}
// Concrete implementation
type Calculator struct{}
func (Calculator) Add(a, b int) int {
return a + b
}
// Generic helper
func Max[T ~int | ~float64](a, b T) T {
if a > b {
return a
}
return b
}
// Table-driven test
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -2, -3, -5},
{"mixed", -2, 5, 3},
}
var calc Adder = Calculator{}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := calc.Add(tt.a, tt.b); got != tt.expected {
t.Fatalf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, got, tt.expected)
}
})
}
}
// Concurrency + context test
func TestWorker(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
select {
case ch <- 42:
case <-ctx.Done():
}
}()
select {
case v := <-ch:
if v != 42 {
t.Errorf("unexpected value: %d", v)
}
case <-ctx.Done():
t.Fatal("timed out")
}
wg.Wait()
}
// Raw string + math edge case
func TestRawString(t *testing.T) {
raw := `line 1
line 2
\t not escaped
`
if len(raw) == 0 || math.IsNaN(float64(len(raw))) {
t.Fatal("impossible condition reached")
}
}

32
samples/go.mod Normal file
View File

@@ -0,0 +1,32 @@
module github.com/example/project
go 1.21
// ==============================
// Direct dependencies
// ==============================
require (
github.com/sirupsen/logrus v1.10.0
golang.org/x/net v0.10.0
github.com/pkg/errors v0.9.2 // indirect
)
// ==============================
// Replace dependencies
// ==============================
replace (
github.com/old/dependency v1.2.3 => github.com/new/dependency v1.2.4
golang.org/x/oldnet => golang.org/x/net v0.11.0
)
// ==============================
// Exclude dependencies
// ==============================
exclude github.com/bad/dependency v1.0.0
// ==============================
// Indirect dependencies
// ==============================
require (
github.com/another/pkg v1.3.0 // indirect
)

59
samples/haskell.hs Normal file
View File

@@ -0,0 +1,59 @@
-- File: haskell.hs
{-# LANGUAGE GADTs, TypeFamilies #-}
module SyntaxTest where
import Data.List (sort)
import qualified Data.Map as Map
-- Simple data type
data Person = Person
{ name :: String
, age :: Int
} deriving (Show, Eq)
-- GADT
data Expr a where
I :: Int -> Expr Int
B :: Bool -> Expr Bool
Add :: Expr Int -> Expr Int -> Expr Int
Eq :: Expr Int -> Expr Int -> Expr Bool
-- Type class
class Describable a where
describe :: a -> String
instance Describable Person where
describe (Person n a) = n ++ " is " ++ show a ++ " years old."
-- Function with pattern matching
sumList :: [Int] -> Int
sumList [] = 0
sumList (x:xs) = x + sumList xs
-- Lambda and higher-order functions
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
-- Infix operator
infixl 6 +++
(+++) :: Int -> Int -> Int
a +++ b = a + b
-- IO function
main :: IO ()
main = do
let people = [Person "Alice" 30, Person "Bob" 25]
mapM_ (putStrLn . describe) people
print $ sumList [1..10]
print $ applyTwice (+1) 5
print $ 3 +++ 4
print $ Eq (I 2) (Add (I 1) (I 1))
-- Quasi-quote example
someExpr :: Expr Int
someExpr = [| Add (I 5) (I 7) |]
-- Comments and Haddocks
-- | This is a Haddock comment
-- explaining the module and functions

87
samples/html.html Normal file
View File

@@ -0,0 +1,87 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Injection Test</title>
<!-- Comment -->
<!-- Another comment with spellcheck -->
<!-- CSS block -->
<style>
body {
background-color: #f0f0f0;
}
h1 {
color: blue;
}
.highlight {
font-weight: bold;
}
</style>
<!-- CSS block with type attribute -->
<style type="text/css">
p {
color: green;
}
</style>
<!-- Script block -->
<script>
console.log("Hello, world!");
function greet(name) {
alert(`Hello, ${name}`);
}
</script>
<!-- Script with type="module" -->
<script type="module">
import { something } from "./module.js";
something();
</script>
<!-- Script with type="importmap" -->
<script type="importmap">
{
"imports": {
"lodash": "/node_modules/lodash-es/lodash\n.js",
"key": 2
}
}
</script>
<!-- Script with type attribute custom -->
<script type="text/javascript">
console.log("Custom type");
</script>
</head>
<body>
<h1>Main Heading</h1>
<h2>Subheading H2</h2>
<p style="color: red; font-weight: bold">
This paragraph has an inline style
</p>
<p>
This is <strong>strong text</strong>, <b>bold also</b>,
<em>italic text</em>, <i>emphasized</i>, <u>underlined</u>,
<s>strikethrough</s>, <del>deleted text</del>, <code>inline code</code>,
<kbd>keyboard input</kbd>.
</p>
<a href="https://hello.world"></a>
<!-- Lit-html / template interpolation -->
<button @click="${e => console.log(e)}">Click me</button>
<button @click="${e => console.log(e)}">Click me too</button>
<!-- Input pattern (regex) -->
<input type="text" pattern="[0-9]{3}" placeholder="Enter 3 digits" />
<!-- Event handlers -->
<button onclick="alert('Clicked!')">Event Handler</button>
<input onchange="console.log(this.value)" />
</body>
</html>

41
samples/ini.ini Normal file
View File

@@ -0,0 +1,41 @@
; =====================================================
; Sample INI Configuration
; =====================================================
[general]
app_name = MyApp
version = 1.2.3
debug = true
max_users = 100
[database]
host = localhost
port = 5432
user = admin
password = secret
timeout = 30
[paths]
log_dir = /var/log/myapp
data_dir = ./data
cache_dir = ./cache
[features]
enable_feature_x = true
enable_feature_y = false
feature_list = item1, item2, item3
[servers]
server1 = 192.168.1.10
server2 = 192.168.1.11
server3 = 192.168.1.12
; Nested sections (some parsers support this)
[servers.backup]
server1 = 192.168.2.10
server2 = 192.168.2.11
; Comments and special characters
; This is a comment line
; Values can also contain special characters like !@#$%^&*()
special_value = !@#$%^&*()_+|~=

147
samples/javascript.js Normal file
View File

@@ -0,0 +1,147 @@
/* ===============================
* JavaScript Syntax Torture Test
* =============================== */
'use strict';
// === Imports ===
import fs, { readFileSync as rfs } from "fs";
import * as path from "path";
import defaultExport, { named as alias } from "./module.js";
// === Constants ===
const PI = 3.141592653589793;
const HEX = 0xff;
const BIN = 0b101010;
const OCT = 0o755;
const BIG = 123_456_789n;
// === Variables ===
let x = null;
var y = undefined;
let z = NaN;
// === Strings ===
const s1 = "double quotes";
const s2 = 'single quotes';
const s3 = `template literal ${1 + 2}`;
const s4 = `multi
line
template`;
const s5 = String.raw`raw \n string`;
// === Escapes ===
const esc = "\n\t\r\b\f\\\"\'\u00A9\x41";
// === Arrays & Objects ===
const arr = [1, , 3, ...[4, 5], { a: 1, b: { c: 2 } }];
const obj = {
key: "value",
"weird-key": 123,
['dyn' + 'amic']: true,
method() {},
async asyncMethod() {},
*generator() { yield 1; },
};
// === Destructuring ===
const { a, b: renamed, ...rest } = obj;
const [x1, , x3 = 42] = arr;
// === Functions ===
function normal(a, b = 1, ...rest) {
return a + b + rest.length;
}
const arrow = (x = 0) => x * x;
const asyncArrow = async () => await Promise.resolve(42);
// === Classes ===
class Example extends Array {
static staticField = 123;
#privateField = "secret";
constructor(...args) {
super(...args);
}
get value() {
return this.#privateField;
}
set value(v) {
this.#privateField = v;
}
}
// === Control Flow ===
if (true && !false || null ?? true) {
console.log("truthy");
} else if (false) {
console.warn("nope");
} else {
console.error("never");
}
for (let i = 0; i < 3; i++) {
continue;
}
for (const k in obj) {}
for (const v of arr) {}
while (false) {}
do {} while (false);
switch (Math.random()) {
case 0:
break;
default:
break;
}
// === Try / Catch ===
try {
throw new Error("boom");
} catch (e) {
console.error(e?.message ?? "unknown");
} finally {
// cleanup
}
// === Regex ===
const regex1 = /foo|bar/i;
const regex2 = /^<script\b(?![^>]*\btype\s*=\s*"(?!module|text\/javascript)[^"]*")[^>]*>$/;
// === Tagged template ===
function tag(strings, ...values) {
return strings.raw.join("|") + values.join(",");
}
tag`hello ${42} world`;
// === Optional chaining / nullish ===
const deep = obj?.a?.b ?? "fallback";
// === Bitwise ===
const mask = (1 << 4) | (1 << 8);
// === JSON ===
const json = JSON.stringify({ a: 1, b: [true, false] }, null, 2);
// === Top-level await (if supported) ===
await Promise.resolve("done");
// === JSX-like (should still highlight interestingly) ===
const jsx = (
<Component prop="value">
<Child />
</Component>
);
// === End ===
export default {
PI,
arr,
obj,
Example,
};

51
samples/json.jsonc Normal file
View File

@@ -0,0 +1,51 @@
/* Example configuration file (JSONC)
// Used to test syntax highlighting and comment support
mutiline comment
*/
{
// Application metadata
"name": "example-app",
"version": "1.2.3",
"debug": true,
// Paths and environment
"paths": {
"root": "/usr/local/example",
"cache": "/tmp/example-cache
asa
multiline string",
"logs": null, // optional
},
// Feature flags
"features": {
"experimental": false,
"hotReload": true,
"themes": [
"dark",
"light",
// "solarized" // not ready yet
],
},
// Network configuration
"server": {
"host": "127.0.0.1",
"port": 8080,
"ssl": {
"enabled": false,
"cert": "",
"key": "",
}
},
// Mixed value types
"timeouts": [100, 250, 500, null],
"retryCount": 3,
// Escapes and strings
"banner": "Welcome!\nThis supports \"escaped quotes\" and unicode → ✓",
// Trailing comma allowed in JSONC
}

119
samples/lua.lua Normal file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env lua
-- Lua syntax highlighting test file
-- Constants
PI = 3.14159
MAX_COUNT = 100
-- Variables
local counter = 0
local name = "Lua"
-- Built-in variable
print(self)
-- Functions
function greet(user)
print("Hello, " .. user)
end
local function add(a, b)
return a + b
end
-- Method definitions
local obj = {}
function obj:sayHi()
print("Hi from method!")
end
obj.sayHello = function()
print("Hello from field function!")
end
-- Arrow-style anonymous function (LuaJIT/CFFI style)
local arrow = function(x)
return x * 2
end
-- Table constructors
local t = {
foo = 123,
bar = function()
return "bar"
end,
nested = {
a = 1,
b = 2,
},
}
-- Loops
for i = 1, MAX_COUNT do
counter = counter + i
end
while counter > 0 do
counter = counter - 1
end
repeat
counter = counter + 1
until counter == 10
-- Conditionals
if counter > 5 then
print("Big number")
elseif counter == 5 then
print("Exactly five")
else
print("Small number")
end
-- Operators
local x, y = 10, 20
local z = x + y * 2 - (x / y) ^ 2
local ok = x == y or x ~= y and not false
-- Function calls
greet("World")
obj:sayHi()
obj.sayHello()
add(5, 10)
-- Built-in function calls
assert(x > 0)
pcall(function()
print("safe")
end)
tonumber("123")
-- CFFI injection example
local ffi = require("ffi")
ffi.cdef([[
int printf(const char *fmt, ...);
typedef struct { int x; int y; } point;
]])
-- Boolean and nil
local flag = true
local nothing = nil
-- Comments
-- Single line
--[[
Multi-line
comment
]]
-- Strings
local s1 = "Hello\nWorld"
local s2 = [[Long
multi-line
string]]
-- Template strings (LuaJIT-style)
local tpl = `Value: ${counter}`
-- Regex-like string (for testing injection highlighting)
local re = "/^%a+$/"

41
samples/markdown.md Normal file
View File

@@ -0,0 +1,41 @@
# Heading 1
## Heading 2
### Heading 3
This is a paragraph with **bold text**, *italic text*, ~~strikethrough~~, and `inline code`.
> This is a blockquote.
>
> - Nested list item 1
> - Nested list item 2
> - Sub-item
- Task list:
- [ ] Unchecked task
- [x] Checked task
1. Numbered list item
2. Another item
---
| Name | Age | City |
|------------|-----|---------------|
| Alice | 25 | London |
| Bob | 30 | New York |
| Charlie | 22 | San Francisco |
[Link to OpenAI](https://openai.com)
`Inline code` example and a fenced code block:
```python
def hello_world():
print("Hello, world!")
```
![Image](https://example.com/image.jpg)
> "This is a quote with a link to [OpenAI](https://openai.com)."

87
samples/nginx.conf Normal file
View File

@@ -0,0 +1,87 @@
# ============================================================
# Global Settings
# ============================================================
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
# ============================================================
# Events Block
# ============================================================
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
# ============================================================
# HTTP Block
# ============================================================
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# Gzip Settings
gzip on;
gzip_disable "msie6";
# ========================================================
# Upstream Backend Servers
# ========================================================
upstream backend {
server 127.0.0.1:8080 weight=5;
server 127.0.0.1:8081;
keepalive 32;
}
# ========================================================
# Server Block
# ========================================================
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
root /var/www/html;
index index.html index.htm;
# ====================================================
# Location Blocks
# ====================================================
location / {
try_files $uri $uri/ =404;
}
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
}
}

130
samples/php.php Normal file
View File

@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PHP Syntax Stress Test</title>
<style>
/* CSS section */
body {
font-family: Arial, sans-serif;
background: #1e1e1e;
color: #e0e0e0;
}
.box {
border: 1px solid #444;
padding: 10px;
margin: 10px;
}
</style>
<script>
// JS section
function greet(name) {
console.log("Hello " + name);
}
document.addEventListener("DOMContentLoaded", () => {
greet("World");
});
</script>
</head>
<body>
<?php
// Basic variables
$number = 42;
$text = "Hello PHP";
$truth = true;
$nothing = null;
// Constants
define("APP_NAME", "SyntaxTester");
// Arrays
$list = [1, 2, 3];
$assoc = [
"one" => 1,
"two" => 2
];
// Function
function add(int $a, int $b): int {
return $a + $b;
}
// Class + methods
class User {
private string $name;
public static int $count = 0;
public function __construct(string $name) {
$this->name = $name;
self::$count++;
}
public function greet(): string {
return "Hello {$this->name}";
}
}
// Object usage
$user = new User("Alice");
echo $user->greet();
// Control flow
if ($number > 10) {
echo "Big number";
} elseif ($number === 10) {
echo "Exactly ten";
} else {
echo "Small number";
}
// Loop
foreach ($list as $item) {
echo $item;
}
// Match expression
$result = match ($number) {
1 => "one",
2 => "two",
default => "many"
};
// Try / catch
try {
throw new Exception("Test exception");
} catch (Exception $e) {
echo $e->getMessage();
}
// Anonymous function
$double = fn($x) => $x * 2;
// Nullsafe operator
$len = $user?->name ? strlen($user->name) : 0;
// Ternary
$status = $truth ? "yes" : "no";
// Include / require
require_once "config.php";
// Output
echo "<div class='box'>";
echo htmlspecialchars($text);
echo "</div>";
?>
<script>
// JS interacting with PHP output
const phpValue = <?= json_encode($number) ?>;
console.log("Value from PHP:", phpValue);
</script>
</body>
</html>

163
samples/python.py Normal file
View File

@@ -0,0 +1,163 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Test file for Python Tree-sitter highlighting."""
# ==============================
# Constants / Builtins
# ==============================
PI = 3.14159
MAX_SIZE = 100
NotImplemented
Ellipsis
__name__ # builtin constant
# ==============================
# Imports
# ==============================
import os
import sys as system
from re import compile as re_compile
from __future__ import annotations
from math import *
# ==============================
# Functions
# ==============================
def add(a: int, b: int = 5) -> int:
"""Simple add function"""
return a + b
def variadic(*args, **kwargs):
print(args, kwargs)
lambda_func = lambda x, y=2: x * y
def type_var_example(T: type):
pass
# ==============================
# Classes
# ==============================
class Base:
class_var = 10
def __init__(self, name: str):
self.name = name
self._private = 42
@classmethod
def cls_method(cls):
return cls.class_var
@staticmethod
def static_method():
return "static"
@property
def prop(self):
return self.name
class Derived(Base):
def __init__(self, name, extra):
super().__init__(name)
self.extra = extra
# ==============================
# Variables
# ==============================
normal_var = 1
_local_var = 2
GLOBAL_VAR = 3
# Builtin variable references
self = "something"
cls = "class"
# ==============================
# Control flow
# ==============================
if True:
x = 10
elif False:
x = 20
else:
x = 0
for i in range(3):
print(i)
while x > 0:
x -= 1
if x == 1:
break
else:
continue
try:
1 / 0
except ZeroDivisionError as e:
raise
finally:
pass
# ==============================
# Operators
# ==============================
a, b = 5, 10
c = a + b * 2 // 3 % 4 ** 2
d = (a << 2) & b | c ^ ~a
e = not a or b and c
# ==============================
# f-strings / interpolation
# ==============================
name = "Alice"
greeting = f"Hello {name.upper()}!"
formatted = f"{a + b} is sum"
# ==============================
# Regex
# ==============================
pattern1 = re_compile(r"\d+")
pattern2 = re_compile(r"\w{2,}")
# ==============================
# Decorators usage
# ==============================
@staticmethod
def static_func():
return True
@classmethod
def cls_func(cls):
return cls
@custom_decorator
def decorated_func():
return None
# ==============================
# Misc / Type conversions / literals
# ==============================
flag: bool = True
nothing: None = None
num: float = float("3.14")
text: str = str(123)
lst = [1, 2, 3]
tpl = (4, 5)
dct = {"a": 1, "b": 2}
# ==============================
# Type hints / TypeVar / TypeAlias
# ==============================
from typing import TypeVar, NewType
T = TypeVar("T")
UserId = NewType("UserId", int)
TypeAliasExample: type = int
# ==============================
# Function calls / constructors
# ==============================
result = add(1, 2)
obj = Derived("Alice", "extra")
variadic(1, 2, 3, key="value")
instance_check = isinstance(obj, Base)

18
samples/regex.regex Normal file
View File

@@ -0,0 +1,18 @@
# Match email addresses with optional names
(?P<name>[a-zA-Z0-9._%+-]+)?\s*<(?P<email>[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})>
# Match dates in YYYY-MM-DD or DD/MM/YYYY
(\d{4}-\d{2}-\d{2})|(\d{2}/\d{2}/\d{4})
# Match hexadecimal colors
# e.g., #FFF, #FFFFFF
# Optional leading #
# Case-insensitive
# Flags inline
(?i)#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})
# Match words starting with vowels
\b[aeiouAEIOU]\w*\b
# Match simple URL
https?://(?:www\.)?\w+\.\w+(?:/\S*)?

View File

@@ -43,11 +43,21 @@ end
puts "Emoji count: #{emojis.length}" puts "Emoji count: #{emojis.length}"
# Multi-line string with unicode # Multi-line string with unicode
multi = <<~EOF multi = <<~BASH
# Function recursion demo
Emojis inside heredoc: 🎉🔥💀🧡💛💚💙💜🖤🤍🤎 factorial() {
End of block. local n="$1"
EOF if ((n <= 1)); then
echo 1
else
local prev
prev=$(factorial $((n - 1)))
echo $((n * prev))
fi
}
log INFO "factorial(5) = $(factorial 5)"
BASH
puts multi puts multi

406
samples/rust.rs Normal file
View File

@@ -0,0 +1,406 @@
#![allow(dead_code)]
use std::collections::{BTreeMap, HashMap};
use std::fmt;
use std::time::Duration;
//! Examples to exercise the Rust regex injection queries in the highlights.scm.
//! These cover Regex::new, regex::Regex::new, regex::bytes::Regex::new,
//! RegexSet::new, regex::RegexSet::new, RegexSetBuilder::new, and byte variants.
//!
//! Injection patterns in the query file trigger on:
//! - call to (Regex|ByteRegexBuilder)::new with a raw string literal
//! - call to (RegexSet|RegexSetBuilder)::new with an array of raw string literals
use regex::{Regex, RegexSet, RegexSetBuilder};
use regex::bytes::Regex as ByteRegex;
use regex::bytes::RegexSet as ByteRegexSet;
use regex::bytes::RegexSetBuilder as ByteRegexSetBuilder;
fn main() {
// --- Should inject (Regex::new with raw string) ---
let _simple = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
// --- Should inject (fully qualified regex::Regex::new with raw string) ---
let _fq = regex::Regex::new(r"(?m)^\w+\s*=\s*.+$").unwrap();
// --- Should inject (bytes::Regex::new with raw string) ---
let _bytes = ByteRegex::new(r"(?-u)\xFF[\x00-\x7F]+").unwrap();
// --- Should inject (RegexSet::new with array of raw strings) ---
let _set = RegexSet::new([
r"^INFO:",
r"^WARN:",
r"^ERROR:",
]).unwrap();
// --- Should inject (regex::RegexSet::new fully qualified) ---
let _set_fq = regex::RegexSet::new([
r"foo\d+",
r"bar\d+",
]).unwrap();
// --- Should inject (RegexSetBuilder::new with array of raw strings) ---
let _set_builder = RegexSetBuilder::new([
r"\bcat\b",
r"\bdog\b",
])
.case_insensitive(true)
.build()
.unwrap();
// --- Should inject (bytes set builder) ---
let _byte_set_builder = ByteRegexSetBuilder::new([
r"(?-u)\x01\x02",
r"(?-u)\xFF.+",
])
.build()
.unwrap();
// --- Should inject (bytes set) ---
let _byte_set = ByteRegexSet::new([
r"(?-u)\x00+\xFF",
r"(?-u)[\x10-\x20]+",
]).unwrap();
// --- NEGATIVE examples (should NOT inject) ---
// Not raw string literal (plain string): the query expects raw_string_literal.
let _no_inject_plain = Regex::new("plain-string-no-raw").unwrap();
// Function name is not `new`, so should not inject.
let _builder = Regex::new(r"\d+").map(|re| re.replace("123", "x"));
// Different type name, should not inject.
let _other = Some(r"not a regex call");
// Raw string but different function, should not inject.
let _format = format!(r"literal: {}", 42);
}
// Keep a simple test to ensure this compiles and runs.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn smoke() {
let re = Regex::new(r"^\d+$").unwrap();
assert!(re.is_match("12345"));
let set = RegexSet::new([r"cat", r"dog"]).unwrap();
assert!(set.is_match("hotdog"));
}
}
/// A simple data type to exercise traits, pattern matching, and methods.
#[derive(Debug, Clone, PartialEq)]
pub struct Point {
pub x: i64,
pub y: i64,
}
impl Point {
pub fn manhattan(&self) -> i64 {
self.x.abs() + self.y.abs()
}
pub fn translate(&self, dx: i64, dy: i64) -> Self {
Self {
x: self.x + dx,
y: self.y + dy,
}
}
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
Empty,
InvalidDigit,
TooLarge,
}
pub fn parse_u8(input: &str) -> Result<u8, ParseError> {
if input.trim().is_empty() {
return Err(ParseError::Empty);
}
let mut value: u16 = 0;
for ch in input.bytes() {
if !(b'0'..=b'9').contains(&ch) {
return Err(ParseError::InvalidDigit);
}
value = value * 10 + u16::from(ch - b'0');
if value > u8::MAX as u16 {
return Err(ParseError::TooLarge);
}
}
Ok(value as u8)
}
pub fn sum_iter<I: IntoIterator<Item = i64>>(iter: I) -> i64 {
iter.into_iter().fold(0, |acc, n| acc + n)
}
pub fn split_once<'a>(input: &'a str, needle: char) -> Option<(&'a str, &'a str)> {
let idx = input.find(needle)?;
Some((&input[..idx], &input[idx + needle.len_utf8()..]))
}
pub fn join_with<I: IntoIterator<Item = String>>(iter: I, sep: &str) -> String {
let mut it = iter.into_iter().peekable();
let mut out = String::new();
while let Some(item) = it.next() {
out.push_str(&item);
if it.peek().is_some() {
out.push_str(sep);
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
use std::sync::mpsc;
use std::thread;
macro_rules! assert_contains {
($haystack:expr, $needle:expr) => {
if !$haystack.contains($needle) {
panic!("expected {:?} to contain {:?}", $haystack, $needle);
}
};
}
#[test]
fn point_manhattan_and_display() {
let p = Point { x: -3, y: 4 };
assert_eq!(p.manhattan(), 7);
assert_eq!(p.to_string(), "(-3, 4)");
}
#[test]
fn point_translate_is_pure() {
let p = Point { x: 1, y: 2 };
let q = p.translate(3, -1);
assert_eq!(p, Point { x: 1, y: 2 });
assert_eq!(q, Point { x: 4, y: 1 });
}
#[test]
fn parse_u8_success_and_errors() {
assert_eq!(parse_u8("0"), Ok(0));
assert_eq!(parse_u8("255"), Ok(255));
assert_eq!(parse_u8(" 17 "), Ok(17)); // leading/trailing spaces are rejected as Empty? we trimmed only emptiness, digits still parsed.
assert_eq!(parse_u8(""), Err(ParseError::Empty));
assert_eq!(parse_u8(" "), Err(ParseError::Empty));
assert_eq!(parse_u8("12a"), Err(ParseError::InvalidDigit));
assert_eq!(parse_u8("256"), Err(ParseError::TooLarge));
}
#[test]
fn sum_iter_works_for_various_iterators() {
let v = vec![1, 2, 3, 4, -5];
assert_eq!(sum_iter(&v), 5);
let arr = [10i64; 4];
assert_eq!(sum_iter(arr), 40);
assert_eq!(sum_iter(0..5), 10);
}
#[test]
fn split_once_basic_and_unicode() {
assert_eq!(split_once("a,b,c", ','), Some(("a", "b,c")));
assert_eq!(split_once("no-sep", '/'), None);
// UTF-8 needle
let s = "fooλbar";
assert_eq!(split_once(s, 'λ'), Some(("foo", "bar")));
}
#[test]
fn join_with_various_lengths() {
let empty: Vec<String> = vec![];
assert_eq!(join_with(empty, ", "), "");
assert_eq!(join_with(vec!["a".into()], ", "), "a");
assert_eq!(
join_with(vec!["a".into(), "b".into(), "c".into()], "|"),
"a|b|c"
);
}
#[test]
fn hash_map_grouping_example() {
let words = ["ant", "bat", "apple", "boat"];
let mut by_initial: HashMap<char, Vec<&str>> = HashMap::new();
for w in &words {
let key = w.chars().next().unwrap();
by_initial.entry(key).or_default().push(*w);
}
assert_eq!(by_initial.get(&'a').unwrap(), &vec!["ant", "apple"]);
assert_eq!(by_initial.get(&'b').unwrap(), &vec!["bat", "boat"]);
}
#[test]
fn btree_map_sorted_iteration() {
let mut map = BTreeMap::new();
map.insert("c", 3);
map.insert("a", 1);
map.insert("b", 2);
let keys: Vec<_> = map.keys().copied().collect();
assert_eq!(keys, vec!["a", "b", "c"]);
}
#[test]
fn channels_and_threads() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
for i in 0..5 {
tx.send(i * i).unwrap();
}
});
let received: Vec<_> = (0..5).map(|_| rx.recv().unwrap()).collect();
assert_eq!(received, vec![0, 1, 4, 9, 16]);
}
#[test]
fn interior_mutability_with_refcell() {
#[derive(Debug)]
struct Counter {
inner: RefCell<u32>,
}
impl Counter {
fn inc(&self) {
*self.inner.borrow_mut() += 1;
}
fn get(&self) -> u32 {
*self.inner.borrow()
}
}
let c = Counter {
inner: RefCell::new(0),
};
c.inc();
c.inc();
assert_eq!(c.get(), 2);
}
#[test]
fn should_panic_on_too_large_parse() {
#[should_panic(expected = "TooLarge")]
fn check() {
parse_u8("999").unwrap();
}
check();
}
#[test]
fn result_based_test() -> Result<(), String> {
let p = Point { x: 2, y: 3 };
if p.manhattan() == 5 {
Ok(())
} else {
Err("manhattan distance mismatch".into())
}
}
#[test]
fn iterator_combinators_cover_common_paths() {
let data = vec![Some(1), None, Some(3), Some(4)];
let sum: i32 = data.iter().flatten().sum();
assert_eq!(sum, 8);
let doubled: Vec<_> = (1..=5).map(|n| n * 2).filter(|n| n % 4 == 0).collect();
assert_eq!(doubled, vec![4, 8]);
}
#[test]
fn pattern_matching_with_guards() {
let numbers = [-2, -1, 0, 1, 2];
let labels: Vec<_> = numbers
.iter()
.map(|n| match n {
n if *n < 0 => "neg",
0 => "zero",
n if *n % 2 == 0 => "even-pos",
_ => "odd-pos",
})
.collect();
assert_eq!(labels, vec!["neg", "neg", "zero", "odd-pos", "even-pos"]);
}
#[test]
fn custom_macro_assert_contains() {
assert_contains!("hello world", "world");
}
#[test]
fn ownership_and_borrowing_examples() {
fn takes_and_gives_back(mut v: Vec<i32>) -> Vec<i32> {
v.push(42);
v
}
let v = vec![1, 2, 3];
let v = takes_and_gives_back(v);
assert_eq!(v, vec![1, 2, 3, 42]);
let s = String::from("hi");
let len = length_of_str(&s);
assert_eq!(len, 2);
}
fn length_of_str(s: &str) -> usize {
s.len()
}
#[test]
fn lifetimes_and_slices() {
fn first<'a>(xs: &'a [i32]) -> Option<&'a i32> {
xs.first()
}
let data = [10, 20, 30];
assert_eq!(first(&data), Some(&10));
}
#[test]
fn const_generics_array_sum() {
fn sum_array<const N: usize>(arr: [i32; N]) -> i32 {
arr.iter().sum()
}
assert_eq!(sum_array::<3>([1, 2, 3]), 6);
assert_eq!(sum_array([0; 5]), 0);
}
#[test]
fn duration_and_instant_arithmetic() {
use std::time::Instant;
let start = Instant::now();
std::thread::sleep(Duration::from_millis(5));
let elapsed = start.elapsed();
assert!(elapsed >= Duration::from_millis(5));
}
#[test]
fn string_builder_patterns() {
let parts = ["a", "b", "c"];
let mut s = String::with_capacity(3);
for p in parts {
s.push_str(p);
}
assert_eq!(s, "abc");
assert!(s.capacity() >= 3);
}
#[test]
fn equality_and_ordering_on_point() {
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 1, y: 2 };
assert_eq!(p1, p2);
assert!(p1.manhattan() <= p2.manhattan());
}
}

View File

@@ -0,0 +1,5 @@
# Sample .gitattributes file for syntax highlighting tests
*.c syntax=c
*.h syntax=c
*.py syntax=python

12
samples/sample.gitignore Normal file
View File

@@ -0,0 +1,12 @@
# Test gitignore file (to check syntax)
*
./!
*.log
!.gitignore[2]
**/*.lo[s]g
### Comment

83
samples/sql.sql Normal file
View File

@@ -0,0 +1,83 @@
-- Sample SQL to exercise the highlight rules
-- DDL
CREATE TEMPORARY TABLE IF NOT EXISTS public.users (
user_id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
profile JSONB,
balance DECIMAL(12,2) DEFAULT 0.00,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ,
CONSTRAINT email_chk CHECK (email LIKE '%@%')
);
-- Indexes
CREATE INDEX CONCURRENTLY IF NOT EXISTS users_email_idx ON public.users USING btree (email);
CREATE INDEX IF NOT EXISTS users_profile_gin_idx ON public.users USING gin (profile);
-- Insert & returning
INSERT INTO public.users (email, profile, balance)
VALUES
('alice@example.com', '{"plan":"pro","tags":["a","b"]}'::jsonb, 25.50),
('bob@example.com', '{"plan":"free","tags":["c"]}'::jsonb, 0.00)
RETURNING user_id, email, profile;
-- Update with CASE and CAST
UPDATE public.users u
SET balance = balance + CAST(5 AS DECIMAL),
updated_at = CURRENT_TIMESTAMP,
profile = jsonb_set(profile, '{last_seen}', to_jsonb(CURRENT_TIMESTAMP)),
email = CASE
WHEN email LIKE '%@example.com' THEN replace(email, '@example.com', '@example.org')
ELSE email
END
WHERE u.balance >= 0
RETURNING user_id, email, balance;
-- Delete with USING
DELETE FROM public.users AS u
USING public.users AS t
WHERE u.user_id = t.user_id
AND u.email LIKE 'bob@%';
-- Window, CTE, aggregates
WITH recent AS (
SELECT *
FROM public.users
WHERE created_at > NOW() - INTERVAL '30 days'
)
SELECT
user_id,
email,
balance,
SUM(balance) OVER (PARTITION BY 1 ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total,
ROW_NUMBER() OVER (ORDER BY created_at DESC) AS rn
FROM recent
ORDER BY created_at DESC
LIMIT 50 OFFSET 0;
-- Joins and JSON
CREATE TEMP TABLE events (
event_id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES public.users(user_id),
payload JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
INSERT INTO events (user_id, payload) VALUES
(1, '{"type":"login","ip":"127.0.0.1"}'),
(1, '{"type":"purchase","amount":9.99,"items":[{"sku":"A1","qty":1}]}' ),
(2, '{"type":"login","ip":"10.0.0.2"}');
SELECT u.email, e.payload->>'type' AS event_type, e.payload
FROM public.users u
LEFT JOIN events e ON e.user_id = u.user_id
WHERE e.payload ? 'type'
ORDER BY e.created_at DESC;
-- Transaction control
BEGIN;
UPDATE public.users SET balance = balance - 5 WHERE email LIKE 'alice%';
INSERT INTO events (user_id, payload)
SELECT user_id, jsonb_build_object('type','adjust','delta',-5) FROM public.users WHERE email LIKE 'alice%';
COMMIT;

53
samples/toml.toml Normal file
View File

@@ -0,0 +1,53 @@
# ============================================================
# Basic types
# ============================================================
title = "Example TOML Configuration"
enabled = true
count = 42
pi = 3.14159
empty = ""
# ============================================================
# Arrays
# ============================================================
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
# Nested array
matrix = [[1, 2], [3, 4]]
# ============================================================
# Tables
# ============================================================
[owner]
name = "Alice"
dob = 1979-05-27T07:32:00Z
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers.alpha]
ip = "10.0.0.1"
dc = "east"
[servers.beta]
ip = "10.0.0.2"
dc = "west"
# ============================================================
# Inline tables
# ============================================================
clients = { name = "Bob", age = 30, active = true }
# ============================================================
# Multiline strings
# ============================================================
description = """
This is a TOML file
used for testing syntax highlighting.
It supports multiple lines.
"""

View File

@@ -2,48 +2,73 @@ extern "C" {
#include "../libs/libgrapheme/grapheme.h" #include "../libs/libgrapheme/grapheme.h"
} }
#include "../include/editor.h" #include "../include/editor.h"
#include "../include/lsp.h"
#include "../include/main.h" #include "../include/main.h"
#include "../include/ts.h"
#include "../include/utils.h" #include "../include/utils.h"
#include <cmath>
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(); Editor *editor = new Editor();
if (!editor) if (!editor)
return nullptr; return nullptr;
uint32_t len = 0; 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) { if (!str) {
free_editor(editor); free_editor(editor);
return nullptr; return nullptr;
} }
editor->filename = filename; editor->filename = filename;
editor->uri = path_to_file_uri(filename);
editor->position = position; editor->position = position;
editor->size = size; editor->size = size;
editor->cursor_preffered = UINT32_MAX; editor->cursor_preffered = UINT32_MAX;
editor->root = load(str, len, optimal_chunk_size(len)); editor->root = load(str, len, optimal_chunk_size(len));
free(str); free(str);
if (len <= (1024 * 128)) { Language language = language_for_file(filename.c_str());
editor->parser = ts_parser_new(); if (language.name != "unknown" && len <= (1024 * 128)) {
Language language = language_for_file(filename); editor->ts.parser = ts_parser_new();
editor->language = language.fn(); editor->ts.language = language.fn();
ts_parser_set_language(editor->parser, editor->language); ts_parser_set_language(editor->ts.parser, editor->ts.language);
std::string query = get_exe_dir() + "/../grammar/" + language.name + ".scm"; editor->ts.query_file =
editor->query = load_query(query.c_str(), editor); get_exe_dir() + "/../grammar/" + language.name + ".scm";
request_add_to_lsp(language, editor);
} }
return editor; return editor;
} }
void free_tsset(TSSetMain *set) {
if (set->parser)
ts_parser_delete(set->parser);
if (set->tree)
ts_tree_delete(set->tree);
if (set->query)
ts_query_delete(set->query);
for (auto &inj : set->injections) {
if (inj.second.parser)
ts_parser_delete(inj.second.parser);
if (inj.second.query)
ts_query_delete(inj.second.query);
}
}
void free_editor(Editor *editor) { void free_editor(Editor *editor) {
ts_parser_delete(editor->parser); remove_from_lsp(editor);
if (editor->tree) free_tsset(&editor->ts);
ts_tree_delete(editor->tree);
if (editor->query)
ts_query_delete(editor->query);
free_rope(editor->root); free_rope(editor->root);
delete 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) { void render_editor(Editor *editor) {
uint32_t sel_start = 0, sel_end = 0; uint32_t sel_start = 0, sel_end = 0;
uint32_t numlen = uint32_t numlen =
@@ -56,6 +81,12 @@ void render_editor(Editor *editor) {
v.push_back({editor->hooks[i], '!' + i}); v.push_back({editor->hooks[i], '!' + i});
std::sort(v.begin(), v.end()); std::sort(v.begin(), v.end());
auto hook_it = v.begin(); auto hook_it = v.begin();
while (hook_it != v.end() && hook_it->first <= editor->scroll.row)
++hook_it;
auto warn_it = editor->warnings.begin();
while (warn_it != editor->warnings.end() &&
warn_it->line < editor->scroll.row)
++warn_it;
std::shared_lock knot_lock(editor->knot_mtx); std::shared_lock knot_lock(editor->knot_mtx);
if (editor->selection_active) { if (editor->selection_active) {
Coord start, end; Coord start, end;
@@ -116,6 +147,7 @@ void render_editor(Editor *editor) {
uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr); uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr);
span_cursor.sync(global_byte_offset); span_cursor.sync(global_byte_offset);
def_span_cursor.sync(global_byte_offset); def_span_cursor.sync(global_byte_offset);
std::shared_lock v_lock(editor->v_mtx);
while (rendered_rows < editor->size.row) { while (rendered_rows < editor->size.row) {
const Fold *fold = fold_for_line(editor->folds, line_index); const Fold *fold = fold_for_line(editor->folds, line_index);
if (fold) { if (fold) {
@@ -137,9 +169,12 @@ void render_editor(Editor *editor) {
for (; i < render_width; i++) for (; i < render_width; i++)
update(rendered_rows, i + render_x, " ", 0xc6c6c6, 0, 0); update(rendered_rows, i + render_x, " ", 0xc6c6c6, 0, 0);
rendered_rows++; rendered_rows++;
uint32_t skip_until = fold->end; uint32_t skip_until = fold->end;
while (line_index <= skip_until) { while (line_index <= skip_until) {
if (hook_it != v.end() && hook_it->first == line_index + 1)
hook_it++;
while (warn_it != editor->warnings.end() && warn_it->line == line_index)
++warn_it;
uint32_t line_len; uint32_t line_len;
char *line = next_line(it, &line_len); char *line = next_line(it, &line_len);
if (!line) if (!line)
@@ -158,6 +193,11 @@ void render_editor(Editor *editor) {
break; break;
if (line_len > 0 && line[line_len - 1] == '\n') if (line_len > 0 && line[line_len - 1] == '\n')
line_len--; line_len--;
std::vector<VWarn> line_warnings;
while (warn_it != editor->warnings.end() && warn_it->line == line_index) {
line_warnings.push_back(*warn_it);
++warn_it;
}
uint32_t current_byte_offset = 0; uint32_t current_byte_offset = 0;
if (rendered_rows == 0) if (rendered_rows == 0)
current_byte_offset += editor->scroll.col; current_byte_offset += editor->scroll.col;
@@ -166,14 +206,10 @@ void render_editor(Editor *editor) {
if (current_byte_offset == 0 || rendered_rows == 0) { if (current_byte_offset == 0 || rendered_rows == 0) {
const char *hook = nullptr; const char *hook = nullptr;
char h[2] = {0, 0}; char h[2] = {0, 0};
auto it2 = hook_it; if (hook_it != v.end() && hook_it->first == line_index + 1) {
for (; it2 != v.end(); ++it2) { h[0] = hook_it->second;
if (it2->first == line_index + 1) {
h[0] = it2->second;
hook = h; hook = h;
hook_it = it2; hook_it++;
break;
}
} }
update(editor->position.row + rendered_rows, editor->position.col, hook, update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0); 0xAAAAAA, 0, 0);
@@ -245,6 +281,78 @@ void render_editor(Editor *editor) {
0x555555 | color, 0); 0x555555 | color, 0);
col++; col++;
} }
if (!line_warnings.empty() && line_left == 0) {
VWarn warn = line_warnings.front();
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
color, 0);
col++;
for (size_t i = 0; i < line_warnings.size(); i++) {
if (line_warnings[i].type < warn.type)
warn = line_warnings[i];
std::string err_sym = " ";
uint32_t fg_color = 0;
switch (line_warnings[i].type) {
case 1:
err_sym = "";
fg_color = 0xFF0000;
goto final;
case 2:
err_sym = "";
fg_color = 0xFFFF00;
goto final;
case 3:
err_sym = "";
fg_color = 0xFF00FF;
goto final;
case 4:
err_sym = "";
fg_color = 0xAAAAAA;
goto final;
final:
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col,
err_sym, fg_color, color, 0);
col++;
update(editor->position.row + rendered_rows, render_x + col, " ",
fg_color, color, 0);
col++;
}
}
}
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
col++;
}
size_t warn_idx = 0;
uint32_t fg_color = 0;
switch (warn.type) {
case 1:
fg_color = 0xFF0000;
break;
case 2:
fg_color = 0xFFFF00;
break;
case 3:
fg_color = 0xFF00FF;
break;
case 4:
fg_color = 0xAAAAAA;
break;
}
while (col < render_width && warn_idx < warn.text.length()) {
uint32_t cluster_len = grapheme_next_character_break_utf8(
warn.text.c_str() + warn_idx, warn.text.length() - warn_idx);
std::string cluster = warn.text.substr(warn_idx, cluster_len);
int width = display_width(cluster.c_str(), cluster_len);
if (col + width > render_width)
break;
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg_color, color, 0);
col += width;
warn_idx += cluster_len;
}
}
while (col < render_width) { while (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0, update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0); 0 | color, 0);
@@ -258,14 +366,10 @@ void render_editor(Editor *editor) {
uint32_t color = editor->cursor.row == line_index ? 0x222222 : 0; uint32_t color = editor->cursor.row == line_index ? 0x222222 : 0;
const char *hook = nullptr; const char *hook = nullptr;
char h[2] = {0, 0}; char h[2] = {0, 0};
auto it2 = hook_it; if (hook_it != v.end() && hook_it->first == line_index + 1) {
for (; it2 != v.end(); ++it2) { h[0] = hook_it->second;
if (it2->first == line_index + 1) {
h[0] = it2->second;
hook = h; hook = h;
hook_it = it2; hook_it++;
break;
}
} }
update(editor->position.row + rendered_rows, editor->position.col, hook, update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0); 0xAAAAAA, 0, 0);

View File

@@ -2,9 +2,9 @@ extern "C" {
#include "../libs/libgrapheme/grapheme.h" #include "../libs/libgrapheme/grapheme.h"
} }
#include "../include/editor.h" #include "../include/editor.h"
#include "../include/lsp.h"
#include "../include/main.h" #include "../include/main.h"
#include "../include/utils.h" #include "../include/utils.h"
#include <cmath>
uint32_t scan_left(const char *line, uint32_t len, uint32_t off) { uint32_t scan_left(const char *line, uint32_t len, uint32_t off) {
if (off > len) if (off > len)
@@ -214,328 +214,6 @@ Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y) {
return {last_line_index, last_col}; return {last_line_index, last_col};
} }
Coord move_right_pure(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t line_len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return result;
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
while (number > 0) {
if (col >= line_len) {
uint32_t next_row = row + 1;
if (next_row >= editor->root->line_count) {
col = line_len;
break;
}
row = next_row;
col = 0;
line = next_line(it, &line_len);
if (!line)
break;
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
} else {
uint32_t inc =
grapheme_next_character_break_utf8(line + col, line_len - col);
if (inc == 0)
break;
col += inc;
}
number--;
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
Coord move_left_pure(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (len > 0 && line[len - 1] == '\n')
--len;
bool iterator_ahead = true;
while (number > 0) {
if (col == 0) {
if (row == 0)
break;
if (iterator_ahead) {
prev_line(it, nullptr);
iterator_ahead = false;
}
line = nullptr;
row--;
line = prev_line(it, &len);
if (!line)
break;
if (len > 0 && line[len - 1] == '\n')
--len;
col = len;
} else {
uint32_t new_col = 0;
while (new_col < col) {
uint32_t inc =
grapheme_next_character_break_utf8(line + new_col, len - new_col);
if (new_col + inc >= col)
break;
new_col += inc;
}
col = new_col;
}
number--;
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t line_len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return result;
uint32_t target_row = next_unfolded_row(editor, row);
while (row < target_row) {
if (!next_line(it, &line_len)) {
free(it->buffer);
free(it);
return result;
}
++row;
}
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
while (number > 0) {
if (col >= line_len) {
uint32_t next_row = next_unfolded_row(editor, row + 1);
if (next_row >= editor->root->line_count) {
col = line_len;
break;
}
while (row < next_row) {
line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
++row;
}
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
col = 0;
--number;
continue;
} else {
uint32_t inc =
grapheme_next_character_break_utf8(line + col, line_len - col);
if (inc == 0)
break;
col += inc;
--number;
}
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
Coord move_left(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (len > 0 && line[len - 1] == '\n')
--len;
bool iterator_ahead = true;
while (number > 0) {
if (col == 0) {
if (row == 0)
break;
if (iterator_ahead) {
prev_line(it, nullptr);
iterator_ahead = false;
}
line = nullptr;
while (row > 0) {
row--;
line = prev_line(it, &len);
if (!line)
break;
const Fold *fold = fold_for_line(editor->folds, row);
if (fold) {
while (line && row > fold->start) {
line = prev_line(it, &len);
row--;
}
line = nullptr;
continue;
}
break;
}
if (!line)
break;
if (len > 0 && line[len - 1] == '\n')
--len;
col = len;
} else {
uint32_t new_col = 0;
while (new_col < col) {
uint32_t inc =
grapheme_next_character_break_utf8(line + new_col, len - new_col);
if (new_col + inc >= col)
break;
new_col += inc;
}
col = new_col;
}
number--;
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
void cursor_down(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
return;
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
char *line_content = next_line(it, &len);
if (line_content == nullptr)
return;
if (editor->cursor_preffered == UINT32_MAX)
editor->cursor_preffered =
get_visual_col_from_bytes(line_content, len, editor->cursor.col);
uint32_t visual_col = editor->cursor_preffered;
free(it->buffer);
free(it);
uint32_t target_row = editor->cursor.row;
while (number > 0 && target_row < editor->root->line_count - 1) {
target_row = next_unfolded_row(editor, target_row + 1);
if (target_row >= editor->root->line_count) {
target_row = editor->root->line_count - 1;
break;
}
number--;
}
it = begin_l_iter(editor->root, target_row);
line_content = next_line(it, &len);
if (!line_content)
return;
if (len > 0 && line_content[len - 1] == '\n')
--len;
editor->cursor.row = target_row;
editor->cursor.col = get_bytes_from_visual_col(line_content, len, visual_col);
free(it->buffer);
free(it);
}
void cursor_up(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0 || editor->cursor.row == 0)
return;
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
char *line_content = next_line(it, &len);
if (!line_content)
return;
if (editor->cursor_preffered == UINT32_MAX)
editor->cursor_preffered =
get_visual_col_from_bytes(line_content, len, editor->cursor.col);
uint32_t visual_col = editor->cursor_preffered;
free(it->buffer);
free(it);
uint32_t target_row = editor->cursor.row;
while (number > 0 && target_row > 0) {
target_row = prev_unfolded_row(editor, target_row - 1);
if (target_row == 0) {
number--;
break;
}
number--;
}
it = begin_l_iter(editor->root, target_row);
line_content = next_line(it, &len);
if (line_content) {
if (len > 0 && line_content[len - 1] == '\n')
--len;
editor->cursor.row = target_row;
editor->cursor.col =
get_bytes_from_visual_col(line_content, len, visual_col);
} else {
editor->cursor.row = 0;
editor->cursor.col = 0;
}
free(it->buffer);
free(it);
}
void cursor_right(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
return;
editor->cursor = move_right(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
}
void cursor_left(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
return;
editor->cursor = move_left(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
}
void move_line_up(Editor *editor) { void move_line_up(Editor *editor) {
if (!editor || !editor->root || editor->cursor.row == 0) if (!editor || !editor->root || editor->cursor.row == 0)
return; return;
@@ -665,6 +343,26 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
TSPoint old_point = {pos.row, pos.col}; TSPoint old_point = {pos.row, pos.col};
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col; uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
Coord point = move_left_pure(editor, pos, -len); Coord point = move_left_pure(editor, pos, -len);
json lsp_range;
bool do_lsp = (editor->lsp != nullptr);
if (do_lsp) {
LineIterator *it = begin_l_iter(editor->root, point.row);
char *line = next_line(it, nullptr);
int utf16_start = 0;
if (line)
utf16_start = utf8_byte_offset_to_utf16(line, point.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, pos.row);
line = next_line(it, nullptr);
int utf16_end = 0;
if (line)
utf16_end = utf8_byte_offset_to_utf16(line, pos.col);
free(it->buffer);
free(it);
lsp_range = {{"start", {{"line", point.row}, {"character", utf16_start}}},
{"end", {{"line", pos.row}, {"character", utf16_end}}}};
}
uint32_t start = line_to_byte(editor->root, point.row, nullptr) + point.col; uint32_t start = line_to_byte(editor->root, point.row, nullptr) + point.col;
if (cursor_original > start && cursor_original <= byte_pos) { if (cursor_original > start && cursor_original <= byte_pos) {
editor->cursor = point; editor->cursor = point;
@@ -684,7 +382,7 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
std::unique_lock lock_2(editor->knot_mtx); std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, start, byte_pos - start); editor->root = erase(editor->root, start, byte_pos - start);
lock_2.unlock(); lock_2.unlock();
if (editor->tree) { if (editor->ts.tree) {
TSInputEdit edit = { TSInputEdit edit = {
.start_byte = start, .start_byte = start,
.old_end_byte = byte_pos, .old_end_byte = byte_pos,
@@ -695,6 +393,17 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
}; };
editor->edit_queue.push(edit); editor->edit_queue.push(edit);
} }
if (do_lsp) {
json message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{"contentChanges",
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
lsp_send(editor->lsp, message, nullptr);
}
std::unique_lock lock_3(editor->spans.mtx); std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, start, start - byte_pos); apply_edit(editor->spans.spans, start, start - byte_pos);
if (editor->spans.mid_parse) if (editor->spans.mid_parse)
@@ -709,6 +418,26 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
TSPoint old_point = {pos.row, pos.col}; TSPoint old_point = {pos.row, pos.col};
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col; uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
Coord point = move_right_pure(editor, pos, len); Coord point = move_right_pure(editor, pos, len);
json lsp_range;
bool do_lsp = (editor->lsp != nullptr);
if (do_lsp) {
LineIterator *it = begin_l_iter(editor->root, pos.row);
char *line = next_line(it, nullptr);
int utf16_start = 0;
if (line)
utf16_start = utf8_byte_offset_to_utf16(line, pos.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, point.row);
line = next_line(it, nullptr);
int utf16_end = 0;
if (line)
utf16_end = utf8_byte_offset_to_utf16(line, point.col);
free(it->buffer);
free(it);
lsp_range = {{"start", {{"line", pos.row}, {"character", utf16_start}}},
{"end", {{"line", point.row}, {"character", utf16_end}}}};
}
uint32_t end = line_to_byte(editor->root, point.row, nullptr) + point.col; uint32_t end = line_to_byte(editor->root, point.row, nullptr) + point.col;
if (cursor_original > byte_pos && cursor_original <= end) { if (cursor_original > byte_pos && cursor_original <= end) {
editor->cursor = pos; editor->cursor = pos;
@@ -728,7 +457,7 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
std::unique_lock lock_2(editor->knot_mtx); std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, byte_pos, end - byte_pos); editor->root = erase(editor->root, byte_pos, end - byte_pos);
lock_2.unlock(); lock_2.unlock();
if (editor->tree) { if (editor->ts.tree) {
TSInputEdit edit = { TSInputEdit edit = {
.start_byte = byte_pos, .start_byte = byte_pos,
.old_end_byte = end, .old_end_byte = end,
@@ -739,6 +468,17 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
}; };
editor->edit_queue.push(edit); editor->edit_queue.push(edit);
} }
if (do_lsp) {
json message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{"contentChanges",
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
lsp_send(editor->lsp, message, nullptr);
}
std::unique_lock lock_3(editor->spans.mtx); std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, byte_pos, byte_pos - end); apply_edit(editor->spans.spans, byte_pos, byte_pos - end);
if (editor->spans.mid_parse) if (editor->spans.mid_parse)
@@ -777,7 +517,7 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
} }
apply_line_insertion(editor, pos.row, rows); apply_line_insertion(editor, pos.row, rows);
apply_hook_insertion(editor, pos.row, rows); apply_hook_insertion(editor, pos.row, rows);
if (editor->tree) { if (editor->ts.tree) {
TSInputEdit edit = { TSInputEdit edit = {
.start_byte = byte_pos, .start_byte = byte_pos,
.old_end_byte = byte_pos, .old_end_byte = byte_pos,
@@ -789,6 +529,30 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
}; };
editor->edit_queue.push(edit); editor->edit_queue.push(edit);
} }
if (editor->lsp) {
lock_1.lock();
LineIterator *it = begin_l_iter(editor->root, pos.row);
char *line = next_line(it, nullptr);
int utf16_col = 0;
if (line)
utf16_col = utf8_byte_offset_to_utf16(line, pos.col);
free(it->buffer);
free(it);
lock_1.unlock();
json message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{"contentChanges",
json::array(
{{{"range",
{{"start", {{"line", pos.row}, {"character", utf16_col}}},
{"end", {{"line", pos.row}, {"character", utf16_col}}}}},
{"text", std::string(data, len)}}})}}}};
lsp_send(editor->lsp, message, nullptr);
}
std::unique_lock lock_3(editor->spans.mtx); std::unique_lock lock_3(editor->spans.mtx);
apply_edit(editor->spans.spans, byte_pos, len); apply_edit(editor->spans.spans, byte_pos, len);
if (editor->spans.mid_parse) if (editor->spans.mid_parse)

327
src/editor_cursor.cc Normal file
View File

@@ -0,0 +1,327 @@
extern "C" {
#include "../libs/libgrapheme/grapheme.h"
}
#include "../include/editor.h"
#include "../include/utils.h"
Coord move_right_pure(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t line_len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return result;
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
while (number > 0) {
if (col >= line_len) {
uint32_t next_row = row + 1;
if (next_row >= editor->root->line_count) {
col = line_len;
break;
}
row = next_row;
col = 0;
line = next_line(it, &line_len);
if (!line)
break;
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
} else {
uint32_t inc =
grapheme_next_character_break_utf8(line + col, line_len - col);
if (inc == 0)
break;
col += inc;
}
number--;
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
Coord move_left_pure(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (len > 0 && line[len - 1] == '\n')
--len;
bool iterator_ahead = true;
while (number > 0) {
if (col == 0) {
if (row == 0)
break;
if (iterator_ahead) {
prev_line(it, nullptr);
iterator_ahead = false;
}
line = nullptr;
row--;
line = prev_line(it, &len);
if (!line)
break;
if (len > 0 && line[len - 1] == '\n')
--len;
col = len;
} else {
uint32_t new_col = 0;
while (new_col < col) {
uint32_t inc =
grapheme_next_character_break_utf8(line + new_col, len - new_col);
if (new_col + inc >= col)
break;
new_col += inc;
}
col = new_col;
}
number--;
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t line_len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return result;
uint32_t target_row = next_unfolded_row(editor, row);
while (row < target_row) {
if (!next_line(it, &line_len)) {
free(it->buffer);
free(it);
return result;
}
++row;
}
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
while (number > 0) {
if (col >= line_len) {
uint32_t next_row = next_unfolded_row(editor, row + 1);
if (next_row >= editor->root->line_count) {
col = line_len;
break;
}
while (row < next_row) {
line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
++row;
}
if (line_len > 0 && line[line_len - 1] == '\n')
--line_len;
col = 0;
--number;
continue;
} else {
uint32_t inc =
grapheme_next_character_break_utf8(line + col, line_len - col);
if (inc == 0)
break;
col += inc;
--number;
}
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
Coord move_left(Editor *editor, Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return result;
}
if (len > 0 && line[len - 1] == '\n')
--len;
bool iterator_ahead = true;
while (number > 0) {
if (col == 0) {
if (row == 0)
break;
if (iterator_ahead) {
prev_line(it, nullptr);
iterator_ahead = false;
}
line = nullptr;
while (row > 0) {
row--;
line = prev_line(it, &len);
if (!line)
break;
const Fold *fold = fold_for_line(editor->folds, row);
if (fold) {
while (line && row > fold->start) {
line = prev_line(it, &len);
row--;
}
line = nullptr;
continue;
}
break;
}
if (!line)
break;
if (len > 0 && line[len - 1] == '\n')
--len;
col = len;
} else {
uint32_t new_col = 0;
while (new_col < col) {
uint32_t inc =
grapheme_next_character_break_utf8(line + new_col, len - new_col);
if (new_col + inc >= col)
break;
new_col += inc;
}
col = new_col;
}
number--;
}
free(it->buffer);
free(it);
result.row = row;
result.col = col;
return result;
}
void cursor_down(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
return;
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
char *line_content = next_line(it, &len);
if (line_content == nullptr)
return;
if (editor->cursor_preffered == UINT32_MAX)
editor->cursor_preffered =
get_visual_col_from_bytes(line_content, len, editor->cursor.col);
uint32_t visual_col = editor->cursor_preffered;
free(it->buffer);
free(it);
uint32_t target_row = editor->cursor.row;
while (number > 0 && target_row < editor->root->line_count - 1) {
target_row = next_unfolded_row(editor, target_row + 1);
if (target_row >= editor->root->line_count) {
target_row = editor->root->line_count - 1;
break;
}
number--;
}
it = begin_l_iter(editor->root, target_row);
line_content = next_line(it, &len);
if (!line_content)
return;
if (len > 0 && line_content[len - 1] == '\n')
--len;
editor->cursor.row = target_row;
editor->cursor.col = get_bytes_from_visual_col(line_content, len, visual_col);
free(it->buffer);
free(it);
}
void cursor_up(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0 || editor->cursor.row == 0)
return;
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
char *line_content = next_line(it, &len);
if (!line_content)
return;
if (editor->cursor_preffered == UINT32_MAX)
editor->cursor_preffered =
get_visual_col_from_bytes(line_content, len, editor->cursor.col);
uint32_t visual_col = editor->cursor_preffered;
free(it->buffer);
free(it);
uint32_t target_row = editor->cursor.row;
while (number > 0 && target_row > 0) {
target_row = prev_unfolded_row(editor, target_row - 1);
if (target_row == 0) {
number--;
break;
}
number--;
}
it = begin_l_iter(editor->root, target_row);
line_content = next_line(it, &len);
if (line_content) {
if (len > 0 && line_content[len - 1] == '\n')
--len;
editor->cursor.row = target_row;
editor->cursor.col =
get_bytes_from_visual_col(line_content, len, visual_col);
} else {
editor->cursor.row = 0;
editor->cursor.col = 0;
}
free(it->buffer);
free(it);
}
void cursor_right(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
return;
editor->cursor = move_right(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
}
void cursor_left(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
return;
editor->cursor = move_left(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
}

View File

@@ -2,6 +2,7 @@
#include "../include/main.h" #include "../include/main.h"
#include "../include/ts.h" #include "../include/ts.h"
#include <cstdint> #include <cstdint>
#include <sys/ioctl.h>
void handle_editor_event(Editor *editor, KeyEvent event) { void handle_editor_event(Editor *editor, KeyEvent event) {
static std::chrono::steady_clock::time_point last_click_time = static std::chrono::steady_clock::time_point last_click_time =
@@ -294,6 +295,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
case ',': case ',':
dedent_line(editor, editor->cursor.row); dedent_line(editor, editor->cursor.row);
break; break;
case CTRL('s'):
save_file(editor);
break;
case 'p': case 'p':
uint32_t len; uint32_t len;
char *text = get_from_clipboard(&len); char *text = get_from_clipboard(&len);
@@ -351,25 +355,50 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
edit_erase(editor, editor->cursor, -(int64_t)prev_col_cluster); edit_erase(editor, editor->cursor, -(int64_t)prev_col_cluster);
} else if (isprint((unsigned char)(event.c[0]))) { } else if (isprint((unsigned char)(event.c[0]))) {
char c = event.c[0]; char c = event.c[0];
uint32_t col = editor->cursor.col;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
uint32_t len;
char *line = next_line(it, &len);
bool skip_insert = false;
if (line && col < len) {
char next = line[col];
if ((c == '}' && next == '}') || (c == ')' && next == ')') ||
(c == ']' && next == ']') || (c == '"' && next == '"') ||
(c == '\'' && next == '\'')) {
cursor_right(editor, 1);
skip_insert = true;
}
}
free(it->buffer);
free(it);
if (!skip_insert) {
char closing = 0; char closing = 0;
if (c == '{') switch (c) {
case '{':
closing = '}'; closing = '}';
else if (c == '(') break;
case '(':
closing = ')'; closing = ')';
else if (c == '[') break;
case '[':
closing = ']'; closing = ']';
else if (c == '"') break;
case '"':
closing = '"'; closing = '"';
else if (c == '\'') break;
case '\'':
closing = '\''; closing = '\'';
break;
}
if (closing) { if (closing) {
char pair[2] = {c, closing}; char pair[2] = {c, closing};
edit_insert(editor, editor->cursor, pair, 2); edit_insert(editor, editor->cursor, pair, 2);
cursor_right(editor, 1); cursor_right(editor, 1);
} else { } else {
edit_insert(editor, editor->cursor, event.c, 1); edit_insert(editor, editor->cursor, &c, 1);
cursor_right(editor, 1); cursor_right(editor, 1);
} }
}
} else if (event.c[0] == 0x7F || event.c[0] == 0x08) { } else if (event.c[0] == 0x7F || event.c[0] == 0x08) {
Coord prev_pos = editor->cursor; Coord prev_pos = editor->cursor;
if (prev_pos.col > 0) if (prev_pos.col > 0)
@@ -535,7 +564,11 @@ static Highlight HL_UNDERLINE = {0, 0, 1 << 2, 100};
void editor_worker(Editor *editor) { void editor_worker(Editor *editor) {
if (!editor || !editor->root) if (!editor || !editor->root)
return; return;
if (editor->parser && editor->query) if (editor->root->char_count > (1024 * 200))
return;
if (editor->ts.query_file != "" && !editor->ts.query)
editor->ts.query = load_query(editor->ts.query_file.c_str(), &editor->ts);
if (editor->ts.parser && editor->ts.query)
ts_collect_spans(editor); ts_collect_spans(editor);
uint32_t prev_col, next_col; uint32_t prev_col, next_col;
word_boundaries_exclusive(editor, editor->cursor, &prev_col, &next_col); word_boundaries_exclusive(editor, editor->cursor, &prev_col, &next_col);
@@ -567,3 +600,23 @@ void editor_worker(Editor *editor) {
lock.unlock(); lock.unlock();
} }
} }
void editor_lsp_handle(Editor *editor, json msg) {
if (msg.contains("method") &&
msg["method"] == "textDocument/publishDiagnostics") {
std::unique_lock lock(editor->v_mtx);
editor->warnings.clear();
json diagnostics = msg["params"]["diagnostics"];
for (size_t i = 0; i < diagnostics.size(); i++) {
json d = diagnostics[i];
VWarn w;
w.line = d["range"]["start"]["line"];
std::string text = d["message"].get<std::string>();
auto pos = text.find('\n');
w.text = (pos == std::string::npos) ? text : text.substr(0, pos);
w.type = d["severity"].get<int>();
editor->warnings.push_back(w);
}
std::sort(editor->warnings.begin(), editor->warnings.end());
}
}

View File

@@ -17,6 +17,7 @@ uint32_t get_indent(Editor *editor, Coord cursor) {
if (!editor) if (!editor)
return 0; return 0;
LineIterator *it = begin_l_iter(editor->root, cursor.row); LineIterator *it = begin_l_iter(editor->root, cursor.row);
next_line(it, nullptr);
uint32_t line_len; uint32_t line_len;
char *line; char *line;
while ((line = prev_line(it, &line_len)) != nullptr) { while ((line = prev_line(it, &line_len)) != nullptr) {

326
src/lsp.cc Normal file
View File

@@ -0,0 +1,326 @@
#include "../include/lsp.h"
#include "../include/maps.h"
#include <fcntl.h>
#include <signal.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
std::shared_mutex active_lsps_mtx;
std::unordered_map<uint8_t, LSPInstance *> active_lsps;
Queue<LSPOpenRequest> lsp_open_queue;
static bool init_lsp(LSPInstance *lsp) {
int in_pipe[2];
int out_pipe[2];
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
perror("pipe");
return false;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return false;
}
if (pid == 0) {
dup2(in_pipe[0], STDIN_FILENO);
dup2(out_pipe[1], STDOUT_FILENO);
int devnull = open("/dev/null", O_WRONLY);
if (devnull >= 0) {
dup2(devnull, STDERR_FILENO);
close(devnull);
}
close(in_pipe[1]);
close(out_pipe[0]);
execvp(lsp->lsp->command, (char *const *)(lsp->lsp->args.data()));
perror("execvp");
return false;
}
lsp->pid = pid;
lsp->stdin_fd = in_pipe[1];
lsp->stdout_fd = out_pipe[0];
close(in_pipe[0]);
close(out_pipe[1]);
return true;
}
LSPInstance *get_or_init_lsp(uint8_t lsp_id) {
std::unique_lock lock(active_lsps_mtx);
auto it = active_lsps.find(lsp_id);
if (it == active_lsps.end()) {
auto map_it = kLsps.find(lsp_id);
if (map_it == kLsps.end())
return nullptr;
LSPInstance *lsp = new LSPInstance();
lsp->lsp = &map_it->second;
if (!init_lsp(lsp)) {
delete lsp;
return nullptr;
}
LSPPending *pending = new LSPPending();
pending->method = "initialize";
pending->editor = nullptr;
pending->callback = [lsp](Editor *, std::string, json) {
lsp->initialized = true;
json initialized = {{"jsonrpc", "2.0"},
{"method", "initialized"},
{"params", json::object()}};
lsp_send(lsp, initialized, nullptr);
};
json init_message = {
{"jsonrpc", "2.0"},
{"method", "initialize"},
{"params",
{{"processId", getpid()},
{"rootUri", "file://" + std::filesystem::current_path().string()},
{"capabilities", json::object()}}}};
lsp_send(lsp, init_message, pending);
active_lsps[lsp_id] = lsp;
return lsp;
}
return it->second;
}
void lsp_send(LSPInstance *lsp, json message, LSPPending *pending) {
if (!lsp || lsp->stdin_fd == -1)
return;
std::unique_lock lock(lsp->mtx);
if (pending) {
message["id"] = lsp->last_id++;
uint32_t id = message["id"].get<uint32_t>();
lsp->pending[id] = pending;
}
lsp->outbox.push(message);
}
void close_lsp(uint8_t lsp_id) {
std::shared_lock active_lsps_lock(active_lsps_mtx);
auto it = active_lsps.find(lsp_id);
if (it == active_lsps.end())
return;
LSPInstance *lsp = it->second;
active_lsps_lock.unlock();
LSPPending *shutdown_pending = new LSPPending();
shutdown_pending->method = "shutdown";
shutdown_pending->callback = [lsp, lsp_id](Editor *, std::string, json) {
json exit = {{"jsonrpc", "2.0"}, {"method", "exit"}};
lsp_send(lsp, exit, nullptr);
};
json shutdown = {{"jsonrpc", "2.0"}, {"method", "shutdown"}};
lsp_send(lsp, shutdown, shutdown_pending);
std::thread t([lsp, lsp_id] {
std::this_thread::sleep_for(100ms);
std::unique_lock active_lsps_lock(active_lsps_mtx);
std::unique_lock lock(lsp->mtx);
if (kill(lsp->pid, 0) == 0)
kill(lsp->pid, SIGKILL);
waitpid(lsp->pid, nullptr, 0);
close(lsp->stdin_fd);
close(lsp->stdout_fd);
while (!lsp->outbox.empty())
lsp->outbox.pop();
while (!lsp->inbox.empty())
lsp->inbox.pop();
for (auto &kv : lsp->pending)
delete kv.second;
delete lsp;
active_lsps.erase(lsp_id);
});
t.detach();
}
static std::optional<json> read_lsp_message(int fd) {
std::string header;
char c;
while (true) {
ssize_t n = read(fd, &c, 1);
if (n <= 0)
return std::nullopt;
header.push_back(c);
if (header.size() >= 4 && header.substr(header.size() - 4) == "\r\n\r\n")
break;
}
size_t pos = header.find("Content-Length:");
if (pos == std::string::npos)
return std::nullopt;
pos += strlen("Content-Length:");
while (pos < header.size() && std::isspace(header[pos]))
pos++;
size_t end = pos;
while (end < header.size() && std::isdigit(header[end]))
end++;
size_t len = std::stoul(header.substr(pos, end - pos));
std::string body(len, '\0');
size_t got = 0;
while (got < len) {
ssize_t n = read(fd, &body[got], len - got);
if (n <= 0)
return std::nullopt;
got += n;
}
return json::parse(body);
}
static Editor *editor_for_uri(LSPInstance *lsp, std::string uri) {
if (uri.empty())
return nullptr;
for (auto &editor : lsp->editors)
if (editor->uri == uri)
return editor;
return nullptr;
}
void lsp_worker() {
LSPOpenRequest request;
while (lsp_open_queue.pop(request))
add_to_lsp(request.language, request.editor);
std::shared_lock active_lsps_lock(active_lsps_mtx);
for (auto &kv : active_lsps) {
LSPInstance *lsp = kv.second;
std::unique_lock lock(lsp->mtx);
while (!lsp->outbox.empty()) {
json message;
message = lsp->outbox.front();
if (!lsp->initialized) {
std::string m = message.value("method", "");
if (m != "initialize")
break;
}
lsp->outbox.pop(message);
std::string payload = message.dump();
std::string header =
"Content-Length: " + std::to_string(payload.size()) + "\r\n\r\n";
std::string out = header + payload;
const char *ptr = out.data();
size_t remaining = out.size();
while (remaining > 0) {
ssize_t written = write(lsp->stdin_fd, ptr, remaining);
if (written == 0)
break;
else if (written == -1) {
if (errno == EINTR)
continue;
perror("write");
break;
} else {
ptr += written;
remaining -= written;
}
}
}
pollfd pfd{lsp->stdout_fd, POLLIN, 0};
while (poll(&pfd, 1, 0) > 0) {
auto msg = read_lsp_message(lsp->stdout_fd);
if (!msg)
break;
if (msg->contains("id")) {
uint32_t id = msg->at("id").get<uint32_t>();
auto it = lsp->pending.find(id);
if (it != lsp->pending.end()) {
LSPPending *pend = it->second;
lock.unlock();
if (pend->callback)
pend->callback(pend->editor, pend->method, *msg);
delete pend;
lock.lock();
lsp->pending.erase(it);
}
} else if (msg->contains("method")) {
std::string uri;
if (msg->contains("params")) {
auto &p = (*msg)["params"];
if (p.contains("textDocument") && p["textDocument"].contains("uri"))
uri = p["textDocument"]["uri"].get<std::string>();
else if (p.contains("uri"))
uri = p["uri"].get<std::string>();
}
Editor *ed = editor_for_uri(lsp, uri);
lock.unlock();
if (ed)
editor_lsp_handle(ed, *msg);
else
lsp_handle(lsp, *msg);
lock.lock();
}
}
}
}
void request_add_to_lsp(Language language, Editor *editor) {
lsp_open_queue.push({language, editor});
}
void add_to_lsp(Language language, Editor *editor) {
LSPInstance *lsp = get_or_init_lsp(language.lsp_id);
if (!lsp)
return;
std::unique_lock lock(lsp->mtx);
if (editor->lsp == lsp)
return;
lsp->editors.push_back(editor);
lock.unlock();
std::unique_lock lock2(editor->lsp_mtx);
editor->lsp = lsp;
lock2.unlock();
std::unique_lock lock3(editor->knot_mtx);
char *buf = read(editor->root, 0, editor->root->char_count);
std::string text(buf);
free(buf);
json message = {{"jsonrpc", "2.0"},
{"method", "textDocument/didOpen"},
{"params",
{{"textDocument",
{{"uri", editor->uri},
{"languageId", language.name},
{"version", 1},
{"text", text}}}}}};
lock3.unlock();
lsp_send(lsp, message, nullptr);
}
static uint8_t find_lsp_id(LSPInstance *needle) {
for (const auto &[id, lsp] : active_lsps)
if (lsp == needle)
return id;
return 0;
}
void remove_from_lsp(Editor *editor) {
auto lsp = editor->lsp;
if (!lsp)
return;
std::unique_lock lock1(lsp->mtx);
lsp->editors.erase(
std::remove(lsp->editors.begin(), lsp->editors.end(), editor),
lsp->editors.end());
lock1.unlock();
std::unique_lock lock2(editor->lsp_mtx);
editor->lsp = nullptr;
lock2.unlock();
json message = {{"jsonrpc", "2.0"},
{"method", "textDocument/didClose"},
{"params", {{"textDocument", {{"uri", editor->uri}}}}}};
lsp_send(lsp, message, nullptr);
uint8_t lsp_id = find_lsp_id(lsp);
if (lsp_id && lsp->editors.empty())
close_lsp(lsp_id);
}
void lsp_handle(LSPInstance *, json message) {
std::string method = message.value("method", "");
if (method == "window/showMessage") {
if (message.contains("params")) {
auto &p = message["params"];
if (p.contains("message"))
log("%s\n", p["message"].get<std::string>().c_str());
}
} else if (method == "window/logMessage") {
if (message.contains("params")) {
auto &p = message["params"];
if (p.contains("message"))
log("%s\n", p["message"].get<std::string>().c_str());
}
}
}

View File

@@ -1,5 +1,6 @@
#include "../include/main.h" #include "../include/main.h"
#include "../include/editor.h" #include "../include/editor.h"
#include "../include/lsp.h"
#include "../include/ts.h" #include "../include/ts.h"
#include "../include/ui.h" #include "../include/ui.h"
#include <atomic> #include <atomic>
@@ -7,8 +8,6 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <thread> #include <thread>
using namespace std::chrono_literals;
std::atomic<bool> running{true}; std::atomic<bool> running{true};
Queue<KeyEvent> event_queue; Queue<KeyEvent> event_queue;
std::vector<Editor *> editors; std::vector<Editor *> editors;
@@ -18,7 +17,12 @@ uint8_t mode = NORMAL;
void background_worker() { void background_worker() {
while (running) while (running)
throttle(16ms, editor_worker, editors[current_editor]); throttle(8ms, editor_worker, editors[current_editor]);
}
void background_lsp() {
while (running)
throttle(8ms, lsp_worker);
} }
void input_listener() { void input_listener() {
@@ -71,6 +75,7 @@ int main(int argc, char *argv[]) {
std::thread input_thread(input_listener); std::thread input_thread(input_listener);
std::thread work_thread(background_worker); std::thread work_thread(background_worker);
std::thread lsp_thread(background_lsp);
while (running) { while (running) {
KeyEvent event; KeyEvent event;
@@ -98,9 +103,22 @@ int main(int argc, char *argv[]) {
if (work_thread.joinable()) if (work_thread.joinable())
work_thread.join(); work_thread.join();
if (lsp_thread.joinable())
lsp_thread.join();
end_screen(); end_screen();
for (auto editor : editors)
free_editor(editor); free_editor(editor);
while (true) {
std::unique_lock lk(active_lsps_mtx);
if (active_lsps.empty())
break;
lk.unlock();
throttle(16ms, lsp_worker);
}
clear_regex_cache(); clear_regex_cache();
return 0; return 0;
} }

View File

@@ -1,4 +1,3 @@
// includes
#include "../include/ui.h" #include "../include/ui.h"
uint32_t rows, cols; uint32_t rows, cols;
@@ -49,14 +48,24 @@ void end_screen() { disable_raw_mode(); }
Coord get_size() { return {rows, cols}; } Coord get_size() { return {rows, cols}; }
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags) {
if (row >= rows || col >= cols)
return;
uint32_t idx = row * cols + col;
std::lock_guard<std::mutex> lock(screen_mutex);
screen[idx].utf8 = utf8 != "" ? utf8 : "";
screen[idx].fg = fg;
screen[idx].bg = bg;
screen[idx].flags = flags;
}
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg, void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags) { uint32_t bg, uint8_t flags) {
if (row >= rows || col >= cols) if (row >= rows || col >= cols)
return; return;
uint32_t idx = row * cols + col; uint32_t idx = row * cols + col;
std::lock_guard<std::mutex> lock(screen_mutex); std::lock_guard<std::mutex> lock(screen_mutex);
screen[idx].utf8 = utf8 ? utf8 : ""; screen[idx].utf8 = utf8 ? utf8 : "";
screen[idx].fg = fg; screen[idx].fg = fg;
screen[idx].bg = bg; screen[idx].bg = bg;

158
src/ts.cc
View File

@@ -1,6 +1,7 @@
#include "../include/ts.h" #include "../include/ts.h"
#include "../include/editor.h" #include "../include/editor.h"
#include "../include/knot.h" #include "../include/knot.h"
#include "../include/maps.h"
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
@@ -28,8 +29,8 @@ pcre2_code *get_re(const std::string &pattern) {
return re; return re;
} }
TSQuery *load_query(const char *query_path, Editor *editor) { TSQuery *load_query(const char *query_path, TSSetBase *set) {
const TSLanguage *lang = editor->language; const TSLanguage *lang = set->language;
std::ifstream file(query_path, std::ios::in | std::ios::binary); std::ifstream file(query_path, std::ios::in | std::ios::binary);
if (!file.is_open()) if (!file.is_open())
return nullptr; return nullptr;
@@ -38,7 +39,7 @@ TSQuery *load_query(const char *query_path, Editor *editor) {
int errornumber = 0; int errornumber = 0;
PCRE2_SIZE erroroffset = 0; PCRE2_SIZE erroroffset = 0;
pcre2_code *re = pcre2_compile( pcre2_code *re = pcre2_compile(
(PCRE2_SPTR) R"((@[A-Za-z0-9_.]+)|(;; \#[0-9a-fA-F]{6} \#[0-9a-fA-F]{6} [01] [01] [01] \d+))", (PCRE2_SPTR) R"((@[A-Za-z0-9_.]+)|(;; \#[0-9a-fA-F]{6} \#[0-9a-fA-F]{6} [01] [01] [01] \d+)|(;; !(\w+)))",
PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, nullptr); PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, nullptr);
if (!re) if (!re)
return nullptr; return nullptr;
@@ -46,9 +47,8 @@ TSQuery *load_query(const char *query_path, Editor *editor) {
pcre2_match_data_create_from_pattern(re, nullptr); pcre2_match_data_create_from_pattern(re, nullptr);
std::map<std::string, int> capture_name_cache; std::map<std::string, int> capture_name_cache;
Highlight *c_hl = nullptr; Highlight *c_hl = nullptr;
Language c_lang = {"unknown", nullptr, 0};
int i = 0; int i = 0;
int limit = 20;
editor->query_map.resize(limit);
PCRE2_SIZE offset = 0; PCRE2_SIZE offset = 0;
PCRE2_SIZE subject_length = highlight_query.size(); PCRE2_SIZE subject_length = highlight_query.size();
while (offset < subject_length) { while (offset < subject_length) {
@@ -63,18 +63,18 @@ TSQuery *load_query(const char *query_path, Editor *editor) {
std::string capture_name = mct; std::string capture_name = mct;
if (!capture_name_cache.count(capture_name)) { if (!capture_name_cache.count(capture_name)) {
if (c_hl) { if (c_hl) {
if (i >= limit) { set->query_map[i] = *c_hl;
limit += 20;
editor->query_map.resize(limit);
}
editor->query_map[i] = *c_hl;
delete c_hl; delete c_hl;
c_hl = nullptr; c_hl = nullptr;
} }
if (c_lang.fn != nullptr) {
set->injection_map[i] = c_lang;
c_lang = {"unknown", nullptr, 0};
}
capture_name_cache[capture_name] = i; capture_name_cache[capture_name] = i;
i++; i++;
} }
} else if (mct.size() >= 2 && mct[0] == ';' && mct[1] == ';') { } else if (mct.substr(0, 4) == ";; #") {
if (c_hl) if (c_hl)
delete c_hl; delete c_hl;
c_hl = new Highlight(); c_hl = new Highlight();
@@ -86,6 +86,12 @@ TSQuery *load_query(const char *query_path, Editor *editor) {
c_hl->priority = std::stoi(mct.substr(25)); c_hl->priority = std::stoi(mct.substr(25));
c_hl->flags = (bold ? CF_BOLD : 0) | (italic ? CF_ITALIC : 0) | c_hl->flags = (bold ? CF_BOLD : 0) | (italic ? CF_ITALIC : 0) |
(underline ? CF_UNDERLINE : 0); (underline ? CF_UNDERLINE : 0);
} else if (mct.substr(0, 4) == ";; !") {
auto it = kLanguages.find(mct.substr(4));
if (it != kLanguages.end())
c_lang = it->second;
else
c_lang = {"unknown", nullptr, 0};
} }
offset = ovector[1]; offset = ovector[1];
} }
@@ -98,6 +104,9 @@ TSQuery *load_query(const char *query_path, Editor *editor) {
TSQuery *q = ts_query_new(lang, highlight_query.c_str(), TSQuery *q = ts_query_new(lang, highlight_query.c_str(),
(uint32_t)highlight_query.length(), &error_offset, (uint32_t)highlight_query.length(), &error_offset,
&error_type); &error_type);
if (!q)
log("Failed to create TSQuery at offset %u, error type %d", error_offset,
(int)error_type);
return q; return q;
} }
@@ -174,26 +183,32 @@ const char *read_ts(void *payload, uint32_t byte_index, TSPoint,
return leaf_from_offset(editor->root, byte_index, bytes_read); return leaf_from_offset(editor->root, byte_index, bytes_read);
} }
static inline Highlight *safe_get(std::vector<Highlight> &vec, size_t index) { template <typename T>
if (index >= vec.size()) static inline T *safe_get(std::map<uint16_t, T> &m, uint16_t key) {
auto it = m.find(key);
if (it == m.end())
return nullptr; return nullptr;
return &vec[index]; return &it->second;
} }
void ts_collect_spans(Editor *editor) { void ts_collect_spans(Editor *editor) {
static int parse_counter = 0; static int parse_counter = 0;
if (!editor->parser || !editor->root || !editor->query) if (!editor->ts.parser || !editor->root || !editor->ts.query)
return; return;
TSInput tsinput = { const bool injections_enabled = editor->root->char_count < (1024 * 32);
for (auto &inj : editor->ts.injections)
inj.second.ranges.clear();
TSInput tsinput{
.payload = editor, .payload = editor,
.read = read_ts, .read = read_ts,
.encoding = TSInputEncodingUTF8, .encoding = TSInputEncodingUTF8,
.decode = nullptr, .decode = nullptr,
}; };
TSTree *tree, *copy = nullptr; TSTree *tree = nullptr;
TSTree *copy = nullptr;
std::unique_lock knot_mtx(editor->knot_mtx); std::unique_lock knot_mtx(editor->knot_mtx);
if (editor->tree) if (editor->ts.tree)
copy = ts_tree_copy(editor->tree); copy = ts_tree_copy(editor->ts.tree);
knot_mtx.unlock(); knot_mtx.unlock();
std::vector<TSInputEdit> edits; std::vector<TSInputEdit> edits;
TSInputEdit edit; TSInputEdit edit;
@@ -201,7 +216,7 @@ void ts_collect_spans(Editor *editor) {
while (editor->edit_queue.pop(edit)) { while (editor->edit_queue.pop(edit)) {
edits.push_back(edit); edits.push_back(edit);
ts_tree_edit(copy, &edits.back()); ts_tree_edit(copy, &edits.back());
}; }
if (copy && edits.empty() && parse_counter < 64) { if (copy && edits.empty() && parse_counter < 64) {
parse_counter++; parse_counter++;
ts_tree_delete(copy); ts_tree_delete(copy);
@@ -210,41 +225,116 @@ void ts_collect_spans(Editor *editor) {
parse_counter = 0; parse_counter = 0;
editor->spans.mid_parse = true; editor->spans.mid_parse = true;
std::shared_lock lock(editor->knot_mtx); std::shared_lock lock(editor->knot_mtx);
tree = ts_parser_parse(editor->parser, copy, tsinput); tree = ts_parser_parse(editor->ts.parser, copy, tsinput);
lock.unlock(); lock.unlock();
if (copy) if (copy)
ts_tree_delete(copy); ts_tree_delete(copy);
knot_mtx.lock(); if (editor->ts.tree)
if (editor->tree) ts_tree_delete(editor->ts.tree);
ts_tree_delete(editor->tree); editor->ts.tree = tree;
editor->tree = tree;
copy = ts_tree_copy(tree); copy = ts_tree_copy(tree);
knot_mtx.unlock();
TSQueryCursor *cursor = ts_query_cursor_new();
ts_query_cursor_exec(cursor, editor->query, ts_tree_root_node(copy));
std::vector<Span> new_spans; std::vector<Span> new_spans;
new_spans.reserve(4096); new_spans.reserve(4096);
struct PendingRanges {
std::vector<TSRange> ranges;
TSSet *tsset = nullptr;
};
struct WorkItem {
TSSetBase *tsset;
TSTree *tree;
int depth;
TSSet *as_injection;
};
const int kMaxInjectionDepth = 4;
std::vector<WorkItem> work;
work.push_back(
{reinterpret_cast<TSSetBase *>(&editor->ts), copy, 0, nullptr});
auto overlaps = [](const Span &s, const TSRange &r) {
return !(s.end <= r.start_byte || s.start >= r.end_byte);
};
auto remove_overlapping_spans = [&](const std::vector<TSRange> &ranges) {
if (ranges.empty())
return;
new_spans.erase(
std::remove_if(new_spans.begin(), new_spans.end(),
[&](const Span &sp) {
return std::any_of(
ranges.begin(), ranges.end(),
[&](const TSRange &r) { return overlaps(sp, r); });
}),
new_spans.end());
};
while (!work.empty()) {
WorkItem item = work.back();
work.pop_back();
TSQuery *q = item.tsset->query;
if (!q) {
ts_tree_delete(item.tree);
continue;
}
TSQueryCursor *cursor = ts_query_cursor_new();
ts_query_cursor_exec(cursor, q, ts_tree_root_node(item.tree));
std::unordered_map<std::string, PendingRanges> pending_injections;
TSQueryMatch match; TSQueryMatch match;
while (ts_query_cursor_next_match(cursor, &match)) { while (ts_query_cursor_next_match(cursor, &match)) {
if (!ts_predicate(editor->query, match, editor->root)) if (!ts_predicate(q, match, editor->root))
continue; continue;
for (uint32_t i = 0; i < match.capture_count; i++) { for (uint32_t i = 0; i < match.capture_count; i++) {
TSQueryCapture cap = match.captures[i]; TSQueryCapture cap = match.captures[i];
uint32_t start = ts_node_start_byte(cap.node); uint32_t start = ts_node_start_byte(cap.node);
uint32_t end = ts_node_end_byte(cap.node); uint32_t end = ts_node_end_byte(cap.node);
Highlight *hl = safe_get(editor->query_map, cap.index); if (Highlight *hl = safe_get(item.tsset->query_map, cap.index))
if (hl)
new_spans.push_back({start, end, hl}); new_spans.push_back({start, end, hl});
if (!injections_enabled)
continue;
if (Language *inj_lang =
safe_get(item.tsset->injection_map, cap.index)) {
auto &pending = pending_injections[inj_lang->name];
TSSet &tsset =
editor->ts.injections.try_emplace(inj_lang->name).first->second;
if (!tsset.parser) {
tsset.lang = inj_lang->name;
tsset.parser = ts_parser_new();
ts_parser_set_language(tsset.parser, inj_lang->fn());
tsset.language = inj_lang->fn();
tsset.query_file =
get_exe_dir() + "/../grammar/" + inj_lang->name + ".scm";
tsset.query = load_query(tsset.query_file.c_str(), &tsset);
}
pending.tsset = &tsset;
pending.ranges.push_back(TSRange{
ts_node_start_point(cap.node),
ts_node_end_point(cap.node),
start,
end,
});
}
} }
} }
ts_query_cursor_delete(cursor); ts_query_cursor_delete(cursor);
ts_tree_delete(copy); if (injections_enabled && item.depth < kMaxInjectionDepth) {
std::sort(new_spans.begin(), new_spans.end()); for (auto &[lang_name, pending] : pending_injections) {
TSSet *tsset = pending.tsset;
if (!tsset || pending.ranges.empty() || !tsset->parser || !tsset->query)
continue;
tsset->ranges = std::move(pending.ranges);
remove_overlapping_spans(tsset->ranges);
ts_parser_set_included_ranges(tsset->parser, tsset->ranges.data(),
tsset->ranges.size());
lock.lock();
TSTree *inj_tree = ts_parser_parse(tsset->parser, nullptr, tsinput);
lock.unlock();
work.push_back({reinterpret_cast<TSSetBase *>(tsset), inj_tree,
item.depth + 1, tsset});
}
}
ts_tree_delete(item.tree);
}
std::pair<uint32_t, int64_t> span_edit; std::pair<uint32_t, int64_t> span_edit;
while (editor->spans.edits.pop(span_edit)) while (editor->spans.edits.pop(span_edit))
apply_edit(new_spans, span_edit.first, span_edit.second); apply_edit(new_spans, span_edit.first, span_edit.second);
std::sort(new_spans.begin(), new_spans.end());
std::unique_lock span_mtx(editor->spans.mtx); std::unique_lock span_mtx(editor->spans.mtx);
editor->spans.mid_parse = false; editor->spans.mid_parse = false;
editor->spans.spans.swap(new_spans); editor->spans.spans.swap(new_spans);
span_mtx.unlock();
} }

View File

@@ -2,20 +2,34 @@ extern "C" {
#include "../libs/libgrapheme/grapheme.h" #include "../libs/libgrapheme/grapheme.h"
#include "../libs/unicode_width/unicode_width.h" #include "../libs/unicode_width/unicode_width.h"
} }
#include "../include/maps.h"
#include "../include/utils.h" #include "../include/utils.h"
#include <algorithm>
#include <cstdarg> static std::string percent_encode(const std::string &s) {
#include <cstdint> static const char *hex = "0123456789ABCDEF";
#include <cstdio> std::string out;
#include <cstdlib> for (unsigned char c : s) {
#include <cstring> if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' ||
#include <fstream> c == '/') {
#include <limits.h> out.push_back(c);
#include <magic.h> } else {
#include <string.h> out.push_back('%');
#include <string> out.push_back(hex[c >> 4]);
#include <unistd.h> out.push_back(hex[c & 0xF]);
#include <unordered_map> }
}
return out;
}
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)));
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) { uint64_t fnv1a_64(const char *s, size_t len) {
uint64_t hash = 1469598103934665603ull; uint64_t hash = 1469598103934665603ull;
@@ -206,8 +220,13 @@ char *load_file(const char *path, uint32_t *out_len) {
static std::string file_extension(const char *filename) { static std::string file_extension(const char *filename) {
std::string name(filename); std::string name(filename);
auto pos = name.find_last_of('.'); auto pos = name.find_last_of('.');
if (pos == std::string::npos) if (pos == std::string::npos) {
auto pos2 = name.find_last_of('/');
if (pos2 != std::string::npos)
pos = pos2;
else
return ""; return "";
}
std::string ext = name.substr(pos + 1); std::string ext = name.substr(pos + 1);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
return ext; return ext;
@@ -231,61 +250,43 @@ char *detect_file_type(const char *filename) {
return result; return result;
} }
static const std::unordered_map<std::string, Language> ext_map = {
{"sh", {"bash", tree_sitter_bash}},
{"bash", {"bash", tree_sitter_bash}},
{"c", {"c", tree_sitter_c}},
{"cpp", {"cpp", tree_sitter_cpp}},
{"cxx", {"cpp", tree_sitter_cpp}},
{"cc", {"cpp", tree_sitter_cpp}},
{"hpp", {"cpp", tree_sitter_cpp}},
{"hh", {"cpp", tree_sitter_cpp}},
{"hxx", {"cpp", tree_sitter_cpp}},
{"h", {"cpp", tree_sitter_cpp}},
{"css", {"css", tree_sitter_css}},
{"fish", {"fish", tree_sitter_fish}},
{"go", {"go", tree_sitter_go}},
{"hs", {"haskell", tree_sitter_haskell}},
{"html", {"html", tree_sitter_html}},
{"htm", {"html", tree_sitter_html}},
{"js", {"javascript", tree_sitter_javascript}},
{"json", {"json", tree_sitter_json}},
{"lua", {"lua", tree_sitter_lua}},
{"mk", {"make", tree_sitter_make}},
{"makefile", {"make", tree_sitter_make}},
{"py", {"python", tree_sitter_python}},
{"rb", {"ruby", tree_sitter_ruby}},
};
static const std::unordered_map<std::string, Language> mime_map = {
{"text/x-c", {"c", tree_sitter_c}},
{"text/x-c++", {"cpp", tree_sitter_cpp}},
{"text/x-shellscript", {"bash", tree_sitter_bash}},
{"application/json", {"json", tree_sitter_json}},
{"text/javascript", {"javascript", tree_sitter_javascript}},
{"text/html", {"html", tree_sitter_html}},
{"text/css", {"css", tree_sitter_css}},
{"text/x-python", {"python", tree_sitter_python}},
{"text/x-ruby", {"ruby", tree_sitter_ruby}},
{"text/x-go", {"go", tree_sitter_go}},
{"text/x-haskell", {"haskell", tree_sitter_haskell}},
{"text/x-lua", {"lua", tree_sitter_lua}},
};
Language language_for_file(const char *filename) { Language language_for_file(const char *filename) {
std::string ext = file_extension(filename); std::string ext = file_extension(filename);
std::string lang_name;
if (!ext.empty()) { if (!ext.empty()) {
auto it = ext_map.find(ext); auto it = kExtToLang.find(ext);
if (it != ext_map.end()) if (it != kExtToLang.end())
return it->second; return kLanguages.find(it->second)->second;
} }
char *mime = detect_file_type(filename); char *mime = detect_file_type(filename);
if (mime) { if (mime) {
std::string mime_type(mime); std::string mime_type(mime);
free(mime); free(mime);
auto it = mime_map.find(mime_type); auto it = kMimeToLang.find(mime_type);
if (it != mime_map.end()) if (it != kMimeToLang.end())
return it->second; return kLanguages.find(it->second)->second;
} }
return {"unknown", nullptr}; return {"unknown", nullptr};
} }
int utf8_byte_offset_to_utf16(const char *s, size_t byte_pos) {
int utf16_units = 0;
size_t i = 0;
while (i < byte_pos) {
unsigned char c = s[i];
if ((c & 0x80) == 0x00) {
i += 1;
utf16_units += 1;
} else if ((c & 0xE0) == 0xC0) {
i += 2;
utf16_units += 1;
} else if ((c & 0xF0) == 0xE0) {
i += 3;
utf16_units += 1;
} else {
i += 4;
utf16_units += 2;
}
}
return utf16_units;
}