diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..06596fe11 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Output of `:checkhealth nvim_treesitter` *** +``` +Paste the output here +``` + +**Output of `nvim --version`** +``` +Paste your output here +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..11fc491ef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/language-request.md b/.github/ISSUE_TEMPLATE/language-request.md new file mode 100644 index 000000000..b10287ea6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/language-request.md @@ -0,0 +1,12 @@ +--- +name: Language request +about: Request for a new language to be supported +title: '' +labels: enhancement, good first issue, help wanted +assignees: '' + +--- + +**Language informations** + +Please paste any useful informations here ! diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a8c74ee6..af48cdc62 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,6 +29,7 @@ Here are some global advices : - If not, you should consider installing the [tree-sitter cli](https://github.com/tree-sitter/tree-sitter/tree/master/cli), you should then be able to open a local playground using `tree-sitter build-wasm && tree-sitter web-ui` within the parsers repo. + - An Example of somewhat complex highlight queries can be found in queries/ruby/highlights.scm (Maintained by @TravonteD) ### Highlights @@ -36,65 +37,75 @@ As languages differ quite a lot, here is a set of captures available to you when One important thing to note is that many of these capture groups are not supported by `neovim` for now, and will not have any effect on highlighting. We will work on improving highlighting in the near future though. + #### Misc -`@comment` -`@error` for error `(ERROR)` nodes. -`@punctuation.delimiter` for `;` `.` `,` -`@punctuation.bracket` for `()` or `{}` +``` +@comment +@error for error (ERROR` nodes. +@punctuation.delimiter for `;` `.` `,` +@punctuation.bracket for `()` or `{}` +``` Some captures are related to language injection (like markdown code blocks). As this is not supported by neovim yet, these are optional and will not have any effect for now. -`@embedded` -`@injection` - `language` - `content` - +``` +@embedded +@injection + language + content +``` #### Constants -`@constant` - `builtin` - `macro` -`@string` - `regex` - `escape` -`@character` -`@number` -`@boolean` -`@float` +``` +@constant + builtin + macro +@string + regex + escape +@character +@number +@boolean +@float +``` #### Functions -`@function` - `builtin` - `macro` -`@parameter` +``` +@function + builtin + macro +@parameter -`@method` -`@field` or `@property` +@method +@field or @property -`@constructor` +@constructor +``` #### Keywords -`@conditional` -`@repeat` -`@label` for C/Lua-like labels -`@operator` -`@keyword` -`@exception` -`@include` keywords for including modules (e.g. import/from in Python) - -`@type` - `builtin` -`@structure` +``` +@conditional +@repeat +@label for C/Lua-like labels +@operator +@keyword +@exception +@include keywords for including modules (e.g. import/from in Python) +@type + builtin +@structure +``` ### Locals - -`@definition` for various definitions - `function` - `method` - `var` - `macro` - `type` - `field` - `doc` for documentation adjecent to a definition. E.g. +``` +@definition for various definitions + function + method + var + macro + type + field + doc for documentation adjecent to a definition. E.g. +``` ```scheme (comment)* @definition.doc @@ -102,7 +113,8 @@ are optional and will not have any effect for now. name: (field_identifier) @definition.method) ``` -`@scope` - -`@reference` +``` +@scope +@reference +``` diff --git a/README.md b/README.md index 139214b44..54d17abce 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ # nvim-treesitter Treesitter configurations and abstraction layer for Neovim. +**Warning: Treesitter and Treesitter highlighting are an experimental feature of nightly versions of Neovim. +Please consider the experience with this plug-in as experimental until Neovim 0.5 is released!** + # Quickstart ## Requirements @@ -33,7 +36,7 @@ $ git clone https://github.com/nvim-treesitter/nvim-treesitter.git Treesitter is using a different _parser_ for every language. It can be quite a pain to install, but fortunately `nvim-treesitter` provides two command to tackle this issue: - - `TSInstall` to install a given parser. + - `TSInstall` to install one or more parser. You can use `TSInstall all` to download all parsers. - `TSInstallInfo` to know which parser is installed. Let's say you need parsers for `lua`, `c`, and `python`, this is how you do with these commands: @@ -131,19 +134,13 @@ Some of these features are : You can find the roadmap [here](https://github.com/nvim-treesitter/nvim-treesitter/projects/1). The roadmap and all features of this plugin are open to change, and any suggestion will be highly appreciated! -## Api +## Utils -Nvim-treesitter exposes an api to extend node capabilites. You can retrieve the api like this: +you can get some utility functions with ```lua -local ts_node_api = require 'nvim-treesitter'.get_node_api() +local ts_utils = require 'nvim-treesitter.ts_utils' ``` - -You can also retrieve the current state of the current buffer with: -```lua -local buf_state = require'nvim-treesitter'.get_buf_state() -``` - -More information is available in neovim documentation (`:help nvim-treesitter-api`). +More information is available in the help file (`:help nvim-treesitter-utils`). ## Supported Languages @@ -156,13 +153,13 @@ List of currently supported languages: - [x] ruby (maintained by @TravonteD) - [x] c (maintained by @vigoux) - [x] go (maintained by @theHamsta) -- [ ] cpp +- [x] cpp (maintained by @theHamsta, extends C queries) - [ ] rust - [x] python (maintained by @theHamsta) -- [ ] javascript -- [ ] typescript +- [x] javascript (maintained by @steelsojka) +- [x] typescript (maintained by @steelsojka) - [ ] tsx -- [ ] json +- [x] json (maintained by @steelsojka) - [x] html (maintained by @TravonteD) - [ ] csharp - [ ] swift @@ -171,7 +168,7 @@ List of currently supported languages: - [x] css (maintained by @TravonteD) - [ ] julia - [ ] php -- [ ] bash +- [x] bash (maintained by @TravonteD) - [ ] scala - [ ] haskell - [ ] toml @@ -180,6 +177,14 @@ List of currently supported languages: - [ ] yaml - [ ] nix - [ ] markdown +- [x] regex (maintained by @theHamsta) + +## User Query Extensions + +You can add your own query files by placing a query file in vim's runtime path after `nvim-treesitter` is sourced. +If the language has a built in query file, that file will be appended to or it will be used (useful for languages not yet supported). +For example, you can add files to `/after/queries/lua/highlights.scm` to add more queries to lua highlights. +You can also manually add query paths to the runtime path by adding this to your vim config `set rtp+='path/to/queries'`. ## Troubleshooting Before doing anything run `:checkhealth nvim_treesitter`. This will help you find where the bug might come from. diff --git a/doc/nvim-treesitter.txt b/doc/nvim-treesitter.txt index f1c278427..c9adf93b2 100644 --- a/doc/nvim-treesitter.txt +++ b/doc/nvim-treesitter.txt @@ -52,9 +52,10 @@ By default, everything is disabled. To enable support for features, in your `ini ============================================================================== COMMANDS *nvim-treesitter-commands* -|:TSInstall| {language} *:TSInstall* +|:TSInstall| {language} ... *:TSInstall* -Download, compile and install a parser for {language} +Install one or more treesitter parsers. +You can use |:TSInstall| `all` to install all parsers. |:TSInstallInfo| *:TSInstallInfo* @@ -91,26 +92,29 @@ A list of languages can be found at |:TSInstallInfo| List modules state for the current session. ============================================================================== -API *nvim-treesitter-api* +UTILS *nvim-treesitter-utils* -Nvim treesitter exposes extended functions to use on nodes and scopes. -you can retrieve the api with: +Nvim treesitter has some wrapper functions that you can retrieve with: > - local ts_node_api = require 'nvim-treesitter'.get_node_api() + local ts_utils = require 'nvim-treesitter.ts_utils' < Methods -get_node_text(node, bufnr) *ts_api.get_node_text* +get_node_at_cursor(winnr) *ts_utils.get_node_at_cursor* + winnr will be 0 if nil + returns the node under the cursor + +get_node_text(node, bufnr) *ts_utils.get_node_text* return the text content of a node -is_parent(dest, source) *ts_api.is_parent* +is_parent(dest, source) *ts_utils.is_parent* determines wether `dest` is a parent of `source` return a boolean -get_named_children(node) *ts_api.get_named_children* +get_named_children(node) *ts_utils.get_named_children* return a table of named children of `node` -get_next_node(node, allow_switch_parent, allow_next_parent) *ts_api.get_next_node* +get_next_node(node, allow_switch_parent, allow_next_parent) *ts_utils.get_next_node* return the next node within the same parent. if no node is found, returns `nil`. if `allow_switch_parent` is true, it will allow switching parent @@ -118,42 +122,28 @@ get_next_node(node, allow_switch_parent, allow_next_parent) *ts_api.get_next_nod if `allow_next_parent` is true, it will allow next parent if the node is the last node and the next parent doesn't have children. -get_previous_node(node, allow_switch_parents, allow_prev_parent) *ts_api.get_previous_node* +get_previous_node(node, allow_switch_parents, allow_prev_parent) *ts_utils.get_previous_node* return the previous node within the same parent. `allow_switch_parent` and `allow_prev_parent` follow the same rule - as |ts_api.get_next_node| but if the node is the first node. + as |ts_utils.get_next_node| but if the node is the first node. -containing_scope(node) *ts_api.containing_scope* +containing_scope(node) *ts_utils.containing_scope* return the smallest scope containing the node -parent_scope(node, cursor_pos) *ts_api.parent_scope* +parent_scope(node, cursor_pos) *ts_utils.parent_scope* return the parent scope of the current scope that contains the node. `cursor_pos` should be `{ row = number, col = number }` - you can retrieve the cursor_pos with the buffer state -nested_scope(node, cursor_pos) *ts_api.nested_scope* +nested_scope(node, cursor_pos) *ts_utils.nested_scope* return the first scope within current scope that contains the node. `cursor_pos` should be `{ row = number, col = number }` - you can retrieve the cursor_pos with the buffer state -next_scope(node) *ts_api.next_scope* +next_scope(node) *ts_utils.next_scope* return the neighbour scope of the current node -previous_scope(node) *ts_api.previous_scope* +previous_scope(node) *ts_utils.previous_scope* return the previous neighbour scope of the current node -Nvim-treesitter also provides access to the state of the current buffer: -> - local cur_buf_state = require'nvim-treesitter'.get_buf_state() - print(vim.inspect(cur_buf_state)) - --[[ - { - cursor_pos = { row = number, col = number }, (current cursor pos in the buffer) - current_node = tsnode (smallest node the cursor is on) - } - ]]-- -< - ============================================================================== FUNCTIONS *nvim-treesitter-functions* @@ -177,4 +167,141 @@ Note: This is highly experimental, and folding can break on some types of edits. If you encounter such breakage, hiting `zx` should fix folding. In any case, feel free to open an issue with the reproducing steps. +============================================================================== +HIGHLIGHTS *nvim-treesitter-highlights* + +`TSError` + *hl-TSError* +For syntax/parser errors. + +You can deactivate highlighting of syntax errors by adding this to your +init.vim: > + highlight link TSError Normal + +`TSPunctDelimiter` + *hl-TSPunctDelimiter* +For delimiters ie: `.` + +`TSPunctBracket` + *hl-TSPunctBracket* +For brackets and parens. + +`TSPunctSpecial` + *hl-TSPunctSpecial* +For special punctutation that does not fall in the catagories before. + +`TSConstant` + *hl-TSConstant* +For constants + +`TSConstBuiltin` + *hl-TSConstBuiltin* +For constant that are built in the language: `nil` in Lua. + +`TSConstMacro` + *hl-TSConstMacro* +For constants that are defined by macros: `NULL` in C. + +`TSString` + *hl-TSString* +For strings. + +`TSStringRegex` + *hl-TSStringRegex* +For regexes. + +`TSStringEscape` + *hl-TSStringEscape* +For escape characters within a string. + +`TSCharacter` + *hl-TSCharacter* +For characters. + +`TSNumber` + *hl-TSNumber* +For integers. + +`TSBoolean` + *hl-TSBoolean* +For booleans. + +`TSFloat` + *hl-TSFloat* +For floats. + +`TSFunction` + *hl-TSFunction* +For function (calls and definitions). + +`TSFuncBuiltin` + *hl-TSFuncBuiltin* +For builtin functions: `table.insert` in Lua. + +`TSFuncMacro` + *hl-TSFuncMacro* +For macro defined fuctions (calls and definitions): each `macro_rules` in +Rust. + +`TSParameter` + *hl-TSParameter* +For parameters of a function. + +`TSMethod` + *hl-TSMethod* +For method calls and definitions. + +`TSField` + *hl-TSField* +For fields. + +`TSProperty` + *hl-TSProperty* +Same as `TSField`. + +`TSConstructor` + *hl-TSConstructor* +For constructor calls and definitions: `{}` in Lua, and Java constructors. + +`TSConditional` + *hl-TSConditional* +For keywords related to conditionnals. + +`TSRepeat` + *hl-TSRepeat* +For keywords related to loops. + +`TSLabel` + *hl-TSLabel* +For labels: `label:` in C and `:label:` in Lua. + +`TSOperator` + *hl-TSOperator* +For any operator: `+`, but also `->` and `*` in C. + +`TSKeyword` + *hl-TSKeyword* +For keywords that don't fall in previous categories. + +`TSException` + *hl-TSException* +For exception related keywords. + +`TSType` + *hl-TSType* +For types. + +`TSTypeBuiltin` + *hl-TSTypeBuiltin* +For builtin types (you guessed it, right ?). + +`TSStructure` + *hl-TSStructure* +This is left as an exercise for the reader. + +`TSInclude` + *hl-TSInclude* +For includes: `#include` in C, `use` or `extern crate` in Rust, or `require` +in Lua + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/doc/tags b/doc/tags index 0a12b18d5..7cab44634 100644 --- a/doc/tags +++ b/doc/tags @@ -5,21 +5,54 @@ :TSInstall nvim-treesitter.txt /*:TSInstall* :TSInstallInfo nvim-treesitter.txt /*:TSInstallInfo* :TSModuleInfo nvim-treesitter.txt /*:TSModuleInfo* +hl-TSBoolean nvim-treesitter.txt /*hl-TSBoolean* +hl-TSCharacter nvim-treesitter.txt /*hl-TSCharacter* +hl-TSConditional nvim-treesitter.txt /*hl-TSConditional* +hl-TSConstBuiltin nvim-treesitter.txt /*hl-TSConstBuiltin* +hl-TSConstMacro nvim-treesitter.txt /*hl-TSConstMacro* +hl-TSConstant nvim-treesitter.txt /*hl-TSConstant* +hl-TSConstructor nvim-treesitter.txt /*hl-TSConstructor* +hl-TSException nvim-treesitter.txt /*hl-TSException* +hl-TSField nvim-treesitter.txt /*hl-TSField* +hl-TSFloat nvim-treesitter.txt /*hl-TSFloat* +hl-TSFuncBuiltin nvim-treesitter.txt /*hl-TSFuncBuiltin* +hl-TSFuncMacro nvim-treesitter.txt /*hl-TSFuncMacro* +hl-TSFunction nvim-treesitter.txt /*hl-TSFunction* +hl-TSInclude nvim-treesitter.txt /*hl-TSInclude* +hl-TSKeyword nvim-treesitter.txt /*hl-TSKeyword* +hl-TSLabel nvim-treesitter.txt /*hl-TSLabel* +hl-TSMethod nvim-treesitter.txt /*hl-TSMethod* +hl-TSNumber nvim-treesitter.txt /*hl-TSNumber* +hl-TSOperator nvim-treesitter.txt /*hl-TSOperator* +hl-TSParameter nvim-treesitter.txt /*hl-TSParameter* +hl-TSProperty nvim-treesitter.txt /*hl-TSProperty* +hl-TSPunctBracket nvim-treesitter.txt /*hl-TSPunctBracket* +hl-TSPunctDelimiter nvim-treesitter.txt /*hl-TSPunctDelimiter* +hl-TSPunctSpecial nvim-treesitter.txt /*hl-TSPunctSpecial* +hl-TSRepeat nvim-treesitter.txt /*hl-TSRepeat* +hl-TSString nvim-treesitter.txt /*hl-TSString* +hl-TSStringEscape nvim-treesitter.txt /*hl-TSStringEscape* +hl-TSStringRegex nvim-treesitter.txt /*hl-TSStringRegex* +hl-TSStructure nvim-treesitter.txt /*hl-TSStructure* +hl-TSType nvim-treesitter.txt /*hl-TSType* +hl-TSTypeBuiltin nvim-treesitter.txt /*hl-TSTypeBuiltin* nvim-treesitter nvim-treesitter.txt /*nvim-treesitter* -nvim-treesitter-api nvim-treesitter.txt /*nvim-treesitter-api* nvim-treesitter-commands nvim-treesitter.txt /*nvim-treesitter-commands* nvim-treesitter-functions nvim-treesitter.txt /*nvim-treesitter-functions* +nvim-treesitter-highlights nvim-treesitter.txt /*nvim-treesitter-highlights* nvim-treesitter-intro nvim-treesitter.txt /*nvim-treesitter-intro* nvim-treesitter-quickstart nvim-treesitter.txt /*nvim-treesitter-quickstart* +nvim-treesitter-utils nvim-treesitter.txt /*nvim-treesitter-utils* nvim_treesitter#foldexpr() nvim-treesitter.txt /*nvim_treesitter#foldexpr()* nvim_treesitter#statusline() nvim-treesitter.txt /*nvim_treesitter#statusline()* -ts_api.containing_scope nvim-treesitter.txt /*ts_api.containing_scope* -ts_api.get_named_children nvim-treesitter.txt /*ts_api.get_named_children* -ts_api.get_next_node nvim-treesitter.txt /*ts_api.get_next_node* -ts_api.get_node_text nvim-treesitter.txt /*ts_api.get_node_text* -ts_api.get_previous_node nvim-treesitter.txt /*ts_api.get_previous_node* -ts_api.is_parent nvim-treesitter.txt /*ts_api.is_parent* -ts_api.nested_scope nvim-treesitter.txt /*ts_api.nested_scope* -ts_api.next_scope nvim-treesitter.txt /*ts_api.next_scope* -ts_api.parent_scope nvim-treesitter.txt /*ts_api.parent_scope* -ts_api.previous_scope nvim-treesitter.txt /*ts_api.previous_scope* +ts_utils.containing_scope nvim-treesitter.txt /*ts_utils.containing_scope* +ts_utils.get_named_children nvim-treesitter.txt /*ts_utils.get_named_children* +ts_utils.get_next_node nvim-treesitter.txt /*ts_utils.get_next_node* +ts_utils.get_node_at_cursor nvim-treesitter.txt /*ts_utils.get_node_at_cursor* +ts_utils.get_node_text nvim-treesitter.txt /*ts_utils.get_node_text* +ts_utils.get_previous_node nvim-treesitter.txt /*ts_utils.get_previous_node* +ts_utils.is_parent nvim-treesitter.txt /*ts_utils.is_parent* +ts_utils.nested_scope nvim-treesitter.txt /*ts_utils.nested_scope* +ts_utils.next_scope nvim-treesitter.txt /*ts_utils.next_scope* +ts_utils.parent_scope nvim-treesitter.txt /*ts_utils.parent_scope* +ts_utils.previous_scope nvim-treesitter.txt /*ts_utils.previous_scope* diff --git a/lua/nvim-treesitter.lua b/lua/nvim-treesitter.lua index 100324e36..9b3ddce89 100644 --- a/lua/nvim-treesitter.lua +++ b/lua/nvim-treesitter.lua @@ -2,10 +2,10 @@ local api = vim.api local install = require'nvim-treesitter.install' local utils = require'nvim-treesitter.utils' +local ts_utils = require'nvim-treesitter.ts_utils' local info = require'nvim-treesitter.info' local configs = require'nvim-treesitter.configs' -local state = require'nvim-treesitter.state' -local ts_utils = require'nvim-treesitter.ts_utils' +local parsers = require'nvim-treesitter.parsers' local M = {} @@ -14,27 +14,22 @@ function M.setup() utils.setup_commands('info', info.commands) utils.setup_commands('configs', configs.commands) - for _, ft in pairs(configs.available_parsers()) do + for _, lang in pairs(parsers.available_parsers()) do for _, mod in pairs(configs.available_modules()) do - if configs.is_enabled(mod, ft) then + if configs.is_enabled(mod, lang) then + local ft = parsers.lang_to_ft(lang) local cmd = string.format("lua require'nvim-treesitter.%s'.attach()", mod) api.nvim_command(string.format("autocmd NvimTreesitter FileType %s %s", ft, cmd)) end end - local cmd = string.format("lua require'nvim-treesitter.state'.attach_to_buffer(%s)", ft) - api.nvim_command(string.format('autocmd NvimTreesitter FileType %s %s', ft, cmd)) end - - state.run_update() end function M.statusline(indicator_size) + if not parsers.has_parser() then return end local indicator_size = indicator_size or 100 - local bufnr = api.nvim_get_current_buf() - local buf_state = state.get_buf_state(bufnr) - if not buf_state then return "" end - local current_node = buf_state.current_node + local current_node = ts_utils.get_node_at_cursor() if not current_node then return "" end local expr = current_node:parent() @@ -56,13 +51,4 @@ function M.statusline(indicator_size) end end -function M.get_buf_state() - local bufnr = api.nvim_get_current_buf() - return state.exposed_state(bufnr) -end - -function M.get_node_api() - return ts_utils -end - return M diff --git a/lua/nvim-treesitter/configs.lua b/lua/nvim-treesitter/configs.lua index f79fed00c..f542e2609 100644 --- a/lua/nvim-treesitter/configs.lua +++ b/lua/nvim-treesitter/configs.lua @@ -1,207 +1,7 @@ local api = vim.api local queries = require'nvim-treesitter.query' -local utils = require'nvim-treesitter.utils' - -local parsers = {} - -parsers.javascript = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-javascript", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.c = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-c", - files = { "src/parser.c" } - } -} - -parsers.cpp = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-cpp", - files = { "src/parser.c", "src/scanner.cc" } - } -} - -parsers.rust = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-rust", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.lua = { - install_info = { - url = "https://github.com/nvim-treesitter/tree-sitter-lua", - files = { "src/parser.c", "src/scanner.cc" } - } -} - -parsers.python = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-python", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.go = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-go", - files = { "src/parser.c" }, - } -} - -parsers.ruby = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-ruby", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.bash = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-bash", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.php = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-php", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.java = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-java", - files = { "src/parser.c" }, - } -} - -parsers.html = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-html", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.julia = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-julia", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.json = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-json", - files = { "src/parser.c" }, - } -} - -parsers.css = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-css", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.ocaml = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-ocaml", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.swift = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-swift", - files = { "src/parser.c" }, - } -} - -parsers.csharp = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-c-sharp", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.typescript = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-typescript", - files = { "src/parser.c", "src/scanner.c" }, - location = "tree-sitter-typescript/typescript" - } -} - -parsers.tsx = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-typescript", - files = { "src/parser.c", "src/scanner.c" }, - location = "tree-sitter-tsx/tsx" - } -} - -parsers.scala = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-scala", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.haskell = { - install_info = { - url = "https://github.com/tree-sitter/tree-sitter-haskell", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.markdown = { - install_info = { - url = "https://github.com/ikatyang/tree-sitter-markdown", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.toml = { - install_info = { - url = "https://github.com/ikatyang/tree-sitter-toml", - files = { "src/parser.c", "src/scanner.c" }, - } -} - -parsers.vue = { - install_info = { - url = "https://github.com/ikatyang/tree-sitter-vue", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.elm = { - install_info = { - url = "https://github.com//razzeee/tree-sitter-elm", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.yaml = { - install_info = { - url = "https://github.com/ikatyang/tree-sitter-yaml", - files = { "src/parser.c", "src/scanner.cc" }, - } -} - -parsers.nix = { - install_info = { - url = "https://github.com/cstrahan/tree-sitter-nix", - files = { "src/parser.c", "src/scanner.cc" }, - } -} +local parsers = require'nvim-treesitter.parsers' -- @enable can be true or false -- @disable is a list of languages, only relevant if enable is true @@ -212,8 +12,8 @@ local config = { highlight = { enable = false, disable = {}, - is_supported = function(ft) - return queries.get_query(ft, 'highlights') ~= nil + is_supported = function(lang) + return queries.get_query(lang, 'highlights') ~= nil end }, incremental_selection = { @@ -225,8 +25,8 @@ local config = { scope_incremental="grc", node_decremental="grm" }, - is_supported = function(ft) - return queries.get_query(ft, 'locals') + is_supported = function(lang) + return queries.get_query(lang, 'locals') end } }, @@ -235,81 +35,89 @@ local config = { local M = {} -local function enable_module(mod, bufnr, ft) +local function enable_module(mod, bufnr, lang) local bufnr = bufnr or api.nvim_get_current_buf() - local ft = ft or api.nvim_buf_get_option(bufnr, 'ft') - if not parsers[ft] or not config.modules[mod] then + local lang = lang or parsers.ft_to_lang(api.nvim_buf_get_option(bufnr, 'ft')) + if not parsers.list[lang] or not config.modules[mod] then return end local loaded_mod = require(string.format("nvim-treesitter.%s", mod)) - loaded_mod.attach(bufnr, ft) + loaded_mod.attach(bufnr, lang) end -local function enable_mod_conf_autocmd(mod, ft) - if not config.modules[mod] or M.is_enabled(mod, ft) then return end +local function enable_mod_conf_autocmd(mod, lang) + if not config.modules[mod] or M.is_enabled(mod, lang) then return end + local ft = parsers.lang_to_ft(lang) local cmd = string.format("lua require'nvim-treesitter.%s'.attach()", mod) api.nvim_command(string.format("autocmd FileType %s %s", ft, cmd)) for i, parser in pairs(config.modules[mod].disable) do - if parser == ft then + if parser == lang then table.remove(config.modules[mod].disable, i) break end end end -local function enable_all(mod, ft) +local function enable_all(mod, lang) if not config.modules[mod] then return end for _, bufnr in pairs(api.nvim_list_bufs()) do - if not ft or api.nvim_buf_get_option(bufnr, 'ft') == ft then - enable_module(mod, bufnr, ft) + local ft = api.nvim_buf_get_option(bufnr, 'ft') + if not lang or ft == parsers.lang_to_ft(lang) then + enable_module(mod, bufnr, lang) end end - if ft then - if utils.has_parser(ft) then - enable_mod_conf_autocmd(mod, ft) + if lang then + if parsers.has_parser(lang) then + enable_mod_conf_autocmd(mod, lang) end else - for _, ft in pairs(M.available_parsers()) do - if utils.has_parser(ft) then - enable_mod_conf_autocmd(mod, ft) + for _, lang in pairs(parsers.available_parsers()) do + if parsers.has_parser(lang) then + enable_mod_conf_autocmd(mod, lang) end end end config.modules[mod].enable = true end -local function disable_module(mod, bufnr, ft) +local function disable_module(mod, bufnr, lang) local bufnr = bufnr or api.nvim_get_current_buf() - local ft = ft or api.nvim_buf_get_option(bufnr, 'ft') - if not parsers[ft] or not config.modules[mod] then + local lang = lang or parsers.ft_to_lang(api.nvim_buf_get_option(bufnr, 'ft')) + if not lang then + return + end + + if not parsers.list[lang] or not config.modules[mod] then return end local loaded_mod = require(string.format("nvim-treesitter.%s", mod)) - loaded_mod.detach(bufnr, ft) + loaded_mod.detach(bufnr) end -local function disable_mod_conf_autocmd(mod, ft) - if not config.modules[mod] or not M.is_enabled(mod, ft) then return end +local function disable_mod_conf_autocmd(mod, lang) + if not config.modules[mod] or not M.is_enabled(mod, lang) then return end + local ft = parsers.lang_to_ft(lang) api.nvim_command(string.format("autocmd! FileType %s", ft)) - table.insert(config.modules[mod].disable, ft) + table.insert(config.modules[mod].disable, lang) end -local function disable_all(mod, ft) +local function disable_all(mod, lang) for _, bufnr in pairs(api.nvim_list_bufs()) do - if not ft or api.nvim_buf_get_option(bufnr, 'ft') == ft then - disable_module(mod, bufnr, ft) + local ft = api.nvim_buf_get_option(bufnr, 'ft') + if not lang or ft == parsers.lang_to_ft(lang) then + disable_module(mod, bufnr, lang) end end - if ft then - disable_mod_conf_autocmd(mod, ft) + if lang then + disable_mod_conf_autocmd(mod, lang) else - for _, ft in pairs(M.available_parsers()) do - disable_mod_conf_autocmd(mod, ft) + for _, lang in pairs(parsers.available_parsers()) do + disable_mod_conf_autocmd(mod, lang) end config.modules[mod].enable = false end @@ -352,20 +160,20 @@ M.commands = { -- @param mod: module (string) -- @param ft: filetype (string) -function M.is_enabled(mod, ft) - if not M.get_parser_configs()[ft] or not utils.has_parser(ft) then +function M.is_enabled(mod, lang) + if not parsers.list[lang] or not parsers.has_parser(lang) then return false end local module_config = config.modules[mod] if not module_config then return false end - if not module_config.enable or not module_config.is_supported(ft) then + if not module_config.enable or not module_config.is_supported(lang) then return false end for _, parser in pairs(module_config.disable) do - if ft == parser then return false end + if lang == parser then return false end end return true @@ -396,14 +204,6 @@ function M.setup(user_data) end end -function M.get_parser_configs() - return parsers -end - -function M.available_parsers() - return vim.tbl_keys(parsers) -end - function M.available_modules() return vim.tbl_keys(config.modules) end diff --git a/lua/nvim-treesitter/health.lua b/lua/nvim-treesitter/health.lua index ca1e765c7..e73ce7fb5 100644 --- a/lua/nvim-treesitter/health.lua +++ b/lua/nvim-treesitter/health.lua @@ -4,7 +4,7 @@ local fn = vim.fn local queries = require'nvim-treesitter.query' local locals = require'nvim-treesitter.locals' local highlight = require'nvim-treesitter.highlight' -local configs = require'nvim-treesitter.configs' +local parsers = require'nvim-treesitter.parsers' local health_start = vim.fn["health#report_start"] local health_ok = vim.fn['health#report_ok'] @@ -62,7 +62,7 @@ function M.checkhealth() local missing_parsers = {} -- Parser installation checks - for _, parser_name in pairs(configs.available_parsers()) do + for _, parser_name in pairs(parsers.available_parsers()) do local installed = #api.nvim_get_runtime_file('parser/'..parser_name..'.so', false) -- Only print informations about installed parsers diff --git a/lua/nvim-treesitter/highlight.lua b/lua/nvim-treesitter/highlight.lua index ac46010bb..1b4722435 100644 --- a/lua/nvim-treesitter/highlight.lua +++ b/lua/nvim-treesitter/highlight.lua @@ -2,6 +2,7 @@ local api = vim.api local ts = vim.treesitter local queries = require'nvim-treesitter.query' +local parsers = require'nvim-treesitter.parsers' local M = { highlighters = {} @@ -10,53 +11,54 @@ local M = { local hlmap = vim.treesitter.TSHighlighter.hl_map -- Misc -hlmap.error = "Error" -hlmap["punctuation.delimiter"] = "Delimiter" -hlmap["punctuation.bracket"] = "Delimiter" +hlmap.error = "TSError" +hlmap["punctuation.delimiter"] = "TSPunctDelimiter" +hlmap["punctuation.bracket"] = "TSPunctBracket" +hlmap["punctuation.special"] = "TSPunctSpecial" -- Constants -hlmap["constant"] = "Constant" -hlmap["constant.builtin"] = "Special" -hlmap["constant.macro"] = "Define" -hlmap["string"] = "String" -hlmap["string.regex"] = "String" -hlmap["string.escape"] = "SpecialChar" -hlmap["character"] = "Character" -hlmap["number"] = "Number" -hlmap["boolean"] = "Boolean" -hlmap["float"] = "Float" +hlmap["constant"] = "TSConstant" +hlmap["constant.builtin"] = "TSConstBuiltin" +hlmap["constant.macro"] = "TSConstMacro" +hlmap["string"] = "TSString" +hlmap["string.regex"] = "TSStringRegex" +hlmap["string.escape"] = "TSStringEscape" +hlmap["character"] = "TSCharacter" +hlmap["number"] = "TSNumber" +hlmap["boolean"] = "TSBoolean" +hlmap["float"] = "TSFloat" -- Functions -hlmap["function"] = "Function" -hlmap["function.builtin"] = "Special" -hlmap["function.macro"] = "Macro" -hlmap["parameter"] = "Identifier" -hlmap["method"] = "Function" -hlmap["field"] = "Identifier" -hlmap["property"] = "Identifier" -hlmap["constructor"] = "Special" +hlmap["function"] = "TSFunction" +hlmap["function.builtin"] = "TSFuncBuiltin" +hlmap["function.macro"] = "TSFuncMacro" +hlmap["parameter"] = "TSIdentifier" +hlmap["method"] = "TSMethod" +hlmap["field"] = "TSField" +hlmap["property"] = "TSProperty" +hlmap["constructor"] = "TSConstructor" -- Keywords -hlmap["conditional"] = "Conditional" -hlmap["repeat"] = "Repeat" -hlmap["label"] = "Label" -hlmap["operator"] = "Operator" -hlmap["keyword"] = "Keyword" -hlmap["exception"] = "Exception" +hlmap["conditional"] = "TSConditional" +hlmap["repeat"] = "TSRepeat" +hlmap["label"] = "TSLabel" +hlmap["operator"] = "TSOperator" +hlmap["keyword"] = "TSKeyword" +hlmap["exception"] = "TSException" -hlmap["type"] = "Type" -hlmap["type.builtin"] = "Type" -hlmap["structure"] = "Structure" -hlmap["include"] = "Include" +hlmap["type"] = "TSType" +hlmap["type.builtin"] = "TSTypeBuiltin" +hlmap["structure"] = "TSStructure" +hlmap["include"] = "TSInclude" -function M.attach(bufnr, ft) - local buf = bufnr or api.nvim_get_current_buf() - local ft = ft or api.nvim_buf_get_option(buf, 'ft') +function M.attach(bufnr, lang) + local bufnr = bufnr or api.nvim_get_current_buf() + local lang = lang or parsers.ft_to_lang(api.nvim_buf_get_option(bufnr, 'ft')) - local query = queries.get_query(ft, "highlights") + local query = queries.get_query(lang, "highlights") if not query then return end - M.highlighters[buf] = ts.TSHighlighter.new(query, buf, ft) + M.highlighters[bufnr] = ts.TSHighlighter.new(query, bufnr, lang) end function M.detach(bufnr) diff --git a/lua/nvim-treesitter/incremental_selection.lua b/lua/nvim-treesitter/incremental_selection.lua index 9876f2e01..6a9999303 100644 --- a/lua/nvim-treesitter/incremental_selection.lua +++ b/lua/nvim-treesitter/incremental_selection.lua @@ -1,11 +1,13 @@ local api = vim.api -local state = require'nvim-treesitter.state' local configs = require'nvim-treesitter.configs' local ts_utils = require'nvim-treesitter.ts_utils' +local parsers = require'nvim-treesitter.parsers' local M = {} +local selections = {} + local function update_selection(buf, node) local start_row, start_col, end_row, end_col = node:range() @@ -18,32 +20,49 @@ local function update_selection(buf, node) vim.fn.setpos(".", { buf, end_row+1, end_col+1, 0 }) end +function M.init_selection() + local buf = api.nvim_get_current_buf() + local node = ts_utils.get_node_at_cursor() + selections[buf] = { [1] = node } + update_selection(buf, node) +end + +local function visual_selection_range() + local _, csrow, cscol, _ = unpack(vim.fn.getpos("'<")) + local _, cerow, cecol, _ = unpack(vim.fn.getpos("'>")) + if csrow < cerow then + return csrow-1, cscol-1, cerow-1, cecol-1 + else + return cerow-1, cecol-1, csrow-1, cscol-1 + end +end + +local function range_matches(node) + local csrow, cscol, cerow, cecol = visual_selection_range() + local srow, scol, erow, ecol = node:range() + return srow == csrow and scol == cscol and erow == cerow and ecol == cecol +end + local function select_incremental(get_parent) return function() local buf = api.nvim_get_current_buf() - local buf_state = state.get_buf_state(buf) + local nodes = selections[buf] - local node - -- initialize incremental selection with current range - if #buf_state.selection.nodes == 0 then - local cur_range = buf_state.selection.range - if not cur_range then - local _, cursor_row, cursor_col, _ = unpack(vim.fn.getpos(".")) - cur_range = { cursor_row, cursor_col, cursor_row, cursor_col + 1 } - end - - local root = buf_state.parser.tree:root() - if not root then return end - - node = root:named_descendant_for_range(cur_range[1]-1, cur_range[2]-1, cur_range[3]-1, cur_range[4]-1) - else - node = get_parent(buf_state.selection.nodes[#buf_state.selection.nodes]) + -- initialize incremental selection with current selection + if not nodes or #nodes == 0 or not range_matches(nodes[#nodes]) then + local csrow, cscol, cerow, cecol = visual_selection_range() + local root = parsers.get_parser().tree:root() + local node = root:named_descendant_for_range(csrow, cscol, cerow, cecol) + update_selection(buf, node) + selections[buf] = { [1] = node } + return end + node = get_parent(nodes[#nodes]) if not node then return end - if node ~= buf_state.selection.nodes[#buf_state.selection.nodes] then - state.insert_selection_node(buf, node) + if node ~= nodes[#nodes] then + table.insert(nodes, node) end update_selection(buf, node) @@ -60,13 +79,10 @@ end) function M.node_decremental() local buf = api.nvim_get_current_buf() - local buf_state = state.get_buf_state(buf) - - local nodes = buf_state.selection.nodes - if #nodes < 2 then return end - - state.pop_selection_node(buf) + local nodes = selections[buf] + if not nodes or #nodes < 2 then return end + table.remove(selections[buf]) local node = nodes[#nodes] update_selection(buf, node) end @@ -76,14 +92,14 @@ function M.attach(bufnr) local config = configs.get_module('incremental_selection') for funcname, mapping in pairs(config.keymaps) do - + local mode if funcname == "init_selection" then - local cmd = ":lua require'nvim-treesitter.incremental_selection'.node_incremental()" - api.nvim_buf_set_keymap(buf, 'n', mapping, cmd, { silent = true }) + mode = 'n' else - local cmd = string.format(":lua require'nvim-treesitter.incremental_selection'.%s()", funcname) - api.nvim_buf_set_keymap(buf, 'v', mapping, cmd, { silent = true }) + mode = 'v' end + local cmd = string.format(":lua require'nvim-treesitter.incremental_selection'.%s()", funcname) + api.nvim_buf_set_keymap(buf, mode, mapping, cmd, { silent = true }) end end diff --git a/lua/nvim-treesitter/info.lua b/lua/nvim-treesitter/info.lua index 18b1b611f..c768595c4 100644 --- a/lua/nvim-treesitter/info.lua +++ b/lua/nvim-treesitter/info.lua @@ -1,15 +1,16 @@ local api = vim.api local configs = require'nvim-treesitter.configs' +local parsers = require'nvim-treesitter.parsers' local M = {} local function install_info() local max_len = 0 - for _, ft in pairs(configs.available_parsers()) do + for _, ft in pairs(parsers.available_parsers()) do if #ft > max_len then max_len = #ft end end - for _, ft in pairs(configs.available_parsers()) do + for _, ft in pairs(parsers.available_parsers()) do local is_installed = #api.nvim_get_runtime_file('parser/'..ft..'.so', false) > 0 api.nvim_out_write(ft..string.rep(' ', max_len - #ft + 1)) if is_installed then @@ -20,14 +21,14 @@ local function install_info() end end -local function print_info_module(sorted_filetypes, mod) - local max_str_len = #sorted_filetypes[1] +local function print_info_module(sorted_languages, mod) + local max_str_len = #sorted_languages[1] local header = string.format('%s%s', string.rep(' ', max_str_len + 2), mod) api.nvim_out_write(header..'\n') - for _, ft in pairs(sorted_filetypes) do - local padding = string.rep(' ', max_str_len - #ft + #mod / 2 + 1) - api.nvim_out_write(ft..":"..padding) - if configs.is_enabled(mod, ft) then + for _, lang in pairs(sorted_languages) do + local padding = string.rep(' ', max_str_len - #lang + #mod / 2 + 1) + api.nvim_out_write(lang..":"..padding) + if configs.is_enabled(mod, lang) then api.nvim_out_write('✓') else api.nvim_out_write('✗') @@ -36,23 +37,23 @@ local function print_info_module(sorted_filetypes, mod) end end -local function print_info_modules(sorted_filetypes) - local max_str_len = #sorted_filetypes[1] +local function print_info_modules(sorted_languages) + local max_str_len = #sorted_languages[1] local header = string.rep(' ', max_str_len + 2) for _, mod in pairs(configs.available_modules()) do header = string.format('%s%s ', header, mod) end api.nvim_out_write(header..'\n') - for _, ft in pairs(sorted_filetypes) do - local padding = string.rep(' ', max_str_len - #ft) - api.nvim_out_write(ft..":"..padding) + for _, lang in pairs(sorted_languages) do + local padding = string.rep(' ', max_str_len - #lang) + api.nvim_out_write(lang..":"..padding) for _, mod in pairs(configs.available_modules()) do local pad_len = #mod / 2 + 1 api.nvim_out_write(string.rep(' ', pad_len)) - if configs.is_enabled(mod, ft) then + if configs.is_enabled(mod, lang) then api.nvim_out_write('✓') else api.nvim_out_write('✗') @@ -66,12 +67,12 @@ end local function module_info(mod) if mod and not configs.get_config()[mod] then return end - local ft_by_len = configs.available_parsers() - table.sort(ft_by_len, function(a, b) return #a > #b end) + local parserlist = parsers.available_parsers() + table.sort(parserlist, function(a, b) return #a > #b end) if mod then - print_info_module(ft_by_len, mod) + print_info_module(parserlist, mod) else - print_info_modules(ft_by_len) + print_info_modules(parserlist) end end diff --git a/lua/nvim-treesitter/install.lua b/lua/nvim-treesitter/install.lua index 637f1dedb..686688bf7 100644 --- a/lua/nvim-treesitter/install.lua +++ b/lua/nvim-treesitter/install.lua @@ -2,13 +2,13 @@ local api = vim.api local fn = vim.fn local luv = vim.loop -local configs = require'nvim-treesitter.configs' local utils = require'nvim-treesitter.utils' +local parsers = require'nvim-treesitter.parsers' local M = {} -local function iter_cmd(cmd_list, i, ft) - if i == #cmd_list + 1 then return print('Treesitter parser for '..ft..' has been installed') end +local function iter_cmd(cmd_list, i, lang) + if i == #cmd_list + 1 then return print('Treesitter parser for '..lang..' has been installed') end local attr = cmd_list[i] if attr.info then print(attr.info) end @@ -18,16 +18,16 @@ local function iter_cmd(cmd_list, i, ft) handle = luv.spawn(attr.cmd, attr.opts, vim.schedule_wrap(function(code) handle:close() if code ~= 0 then return api.nvim_err_writeln(attr.err) end - iter_cmd(cmd_list, i + 1, ft) + iter_cmd(cmd_list, i + 1, lang) end)) end -local function run_install(cache_folder, package_path, ft, repo) - local project_name = 'tree-sitter-'..ft +local function run_install(cache_folder, package_path, lang, repo) + local project_name = 'tree-sitter-'..lang local project_repo = cache_folder..'/'..project_name -- compile_location only needed for typescript installs. local compile_location = cache_folder..'/'..(repo.location or project_name) - local parser_lib_name = package_path.."/parser/"..ft..".so" + local parser_lib_name = package_path.."/parser/"..lang..".so" local command_list = { { cmd = 'rm', @@ -76,7 +76,7 @@ local function run_install(cache_folder, package_path, ft, repo) } } - iter_cmd(command_list, 1, ft) + iter_cmd(command_list, 1, lang) end -- TODO(kyazdani): this should work on windows too @@ -95,16 +95,25 @@ local function install(...) local cache_folder, err = utils.get_cache_dir() if err then return api.nvim_err_writeln(err) end - for _, ft in ipairs({ ... }) do - if #api.nvim_get_runtime_file('parser/'..ft..'.so', false) > 0 then - local yesno = fn.input(ft .. ' parser already available: would you like to reinstall ? y/n: ') - print('\n ') -- mandatory to avoid messing up command line - if not string.match(yesno, '^y.*') then return end + local languages = { ... } + local check_installed = true + if ... == 'all' then + languages = parsers.available_parsers() + check_installed = false + end + + for _, lang in ipairs(languages) do + if check_installed then + if #api.nvim_get_runtime_file('parser/'..lang..'.so', false) > 0 then + local yesno = fn.input(lang .. ' parser already available: would you like to reinstall ? y/n: ') + print('\n ') -- mandatory to avoid messing up command line + if not string.match(yesno, '^y.*') then goto continue end + end end - local parser_config = configs.get_parser_configs()[ft] + local parser_config = parsers.get_parser_configs()[lang] if not parser_config then - return api.nvim_err_writeln('Parser not available for language '..ft) + return api.nvim_err_writeln('Parser not available for language '..lang) end local install_info = parser_config.install_info @@ -113,7 +122,8 @@ local function install(...) files={ install_info.files, 'table' } } - run_install(cache_folder, package_path, ft, install_info) + run_install(cache_folder, package_path, lang, install_info) + ::continue:: end end @@ -121,15 +131,15 @@ end M.ensure_installed = function(languages) if type(languages) == 'string' then if languages == 'all' then - languages = configs.available_parsers() + languages = parsers.available_parsers() else languages = {languages} end end - for _, ft in ipairs(languages) do - if not utils.has_parser(ft) then - install(ft) + for _, lang in ipairs(languages) do + if not parsers.has_parser(lang) then + install(lang) end end end @@ -142,7 +152,7 @@ M.commands = { "-nargs=+", "-complete=custom,v:lua.ts_installable_parsers" }, - description = '`:TSInstall {ft}` installs a parser under nvim-treesitter/parser/{name}.so' + description = '`:TSInstall {lang}` installs a parser under nvim-treesitter/parser/{lang}.so' } } diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua index 313d7655d..8c7d400eb 100644 --- a/lua/nvim-treesitter/locals.lua +++ b/lua/nvim-treesitter/locals.lua @@ -5,20 +5,20 @@ local api = vim.api local ts = vim.treesitter local queries = require'nvim-treesitter.query' -local utils = require'nvim-treesitter.utils' +local parsers = require'nvim-treesitter.parsers' local M = { locals = {} } function M.collect_locals(bufnr) - local ft = api.nvim_buf_get_option(bufnr, "ft") - if not ft then return end + local lang = parsers.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft")) + if not lang then return end - local query = queries.get_query(ft, 'locals') + local query = queries.get_query(lang, 'locals') if not query then return end - local parser = utils.get_parser(bufnr, ft) + local parser = parsers.get_parser(bufnr, lang) if not parser then return end local root = parser:parse():root() @@ -40,7 +40,7 @@ end function M.get_locals(bufnr) local bufnr = bufnr or api.nvim_get_current_buf() local cached_local = M.locals[bufnr] - if not cached_local or api.nvim_buf_get_changedtick(bufnr) < cached_local.tick then + if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then update_cached_locals(bufnr,api.nvim_buf_get_changedtick(bufnr)) end diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index 07f3e9d34..9097d335d 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -1,18 +1,257 @@ local api = vim.api local ts = vim.treesitter -local M = {} +local list = {} + +list.javascript = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-javascript", + files = { "src/parser.c", "src/scanner.c" }, + } +} + +list.c = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-c", + files = { "src/parser.c" } + } +} + +list.cpp = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-cpp", + files = { "src/parser.c", "src/scanner.cc" } + } +} + +list.rust = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-rust", + files = { "src/parser.c", "src/scanner.c" }, + } +} + +list.lua = { + install_info = { + url = "https://github.com/nvim-treesitter/tree-sitter-lua", + files = { "src/parser.c", "src/scanner.cc" } + } +} + +list.python = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-python", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.go = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-go", + files = { "src/parser.c" }, + } +} + +list.ruby = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ruby", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.bash = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-bash", + files = { "src/parser.c", "src/scanner.cc" }, + }, + filetype = 'sh' +} + +list.php = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-php", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.java = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-java", + files = { "src/parser.c" }, + } +} + +list.html = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-html", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.julia = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-julia", + files = { "src/parser.c", "src/scanner.c" }, + } +} + +list.json = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-json", + files = { "src/parser.c" }, + } +} + +list.css = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-css", + files = { "src/parser.c", "src/scanner.c" }, + } +} + +list.ocaml = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ocaml", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.swift = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-swift", + files = { "src/parser.c" }, + } +} + +list.c_sharp = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-c-sharp", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = 'cs' +} + +list.typescript = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-typescript", + files = { "src/parser.c", "src/scanner.c" }, + location = "tree-sitter-typescript/typescript" + } +} + +list.tsx = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-typescript", + files = { "src/parser.c", "src/scanner.c" }, + location = "tree-sitter-tsx/tsx" + }, + filetype = 'typescriptreact' +} + +list.scala = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-scala", + files = { "src/parser.c", "src/scanner.c" }, + } +} + +list.haskell = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-haskell", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.markdown = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-markdown", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.toml = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-toml", + files = { "src/parser.c", "src/scanner.c" }, + } +} + +list.vue = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-vue", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.elm = { + install_info = { + url = "https://github.com//razzeee/tree-sitter-elm", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.yaml = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-yaml", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.nix = { + install_info = { + url = "https://github.com/cstrahan/tree-sitter-nix", + files = { "src/parser.c", "src/scanner.cc" }, + } +} + +list.regex = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-regex", + files = { "src/parser.c" } + } +} + +local M = { + list = list +} + +local ft_to_parsername = {} +for name, obj in pairs(M.list) do + if obj.filetype then + ft_to_parsername[obj.filetype] = name + else + ft_to_parsername[name] = name + end +end + +function M.ft_to_lang(ft) + return ft_to_parsername[ft] +end + +function M.lang_to_ft(lang) + return M.list[lang].filetype or lang +end + +function M.available_parsers() + return vim.tbl_keys(M.list) +end + +function M.get_parser_configs() + return M.list +end function M.has_parser(lang) - local lang = lang or api.nvim_buf_get_option(0, 'filetype') + local buf = api.nvim_get_current_buf() + local lang = lang or M.ft_to_lang(api.nvim_buf_get_option(buf, 'ft')) if not lang or #lang == 0 then return false end return #api.nvim_get_runtime_file('parser/' .. lang .. '.*', false) > 0 end function M.get_parser(bufnr, lang) + local buf = bufnr or api.nvim_get_current_buf() + local lang = lang or M.ft_to_lang(api.nvim_buf_get_option(buf, 'ft')) + if M.has_parser(lang) then - local buf = bufnr or api.nvim_get_current_buf() - local lang = lang or api.nvim_buf_get_option(buf, 'ft') if not M[buf] then M[buf] = {} end diff --git a/lua/nvim-treesitter/query.lua b/lua/nvim-treesitter/query.lua index 644c33933..42e835824 100644 --- a/lua/nvim-treesitter/query.lua +++ b/lua/nvim-treesitter/query.lua @@ -3,14 +3,41 @@ local ts = vim.treesitter local M = {} -local function read_query_file(fname) - return table.concat(vim.fn.readfile(fname), '\n') +local function read_query_files(filenames) + local contents = {} + + for _,filename in ipairs(filenames) do + vim.list_extend(contents, vim.fn.readfile(filename)) + end + + return table.concat(contents, '\n') end -function M.get_query(ft, query_name) - local query_files = api.nvim_get_runtime_file(string.format('queries/%s/%s.scm', ft, query_name), false) +-- Some treesitter grammars extend others. +-- We can use that to import the queries of the base language +M.base_language_map = { + cpp = {'c'}, + typescript = {'javascript'}, + tsx = {'typescript', 'javascript'}, +} + +function M.get_query(lang, query_name) + local query_files = api.nvim_get_runtime_file(string.format('queries/%s/%s.scm', lang, query_name), true) + local query_string = '' + if #query_files > 0 then - return ts.parse_query(ft, read_query_file(query_files[1])) + query_string = read_query_files(query_files) .. "\n" .. query_string + end + + for _, base_lang in ipairs(M.base_language_map[lang] or {}) do + local base_files = api.nvim_get_runtime_file(string.format('queries/%s/%s.scm', base_lang, query_name), true) + if base_files and #base_files > 0 then + query_string = read_query_files(base_files) .. "\n" .. query_string + end + end + + if #query_string > 0 then + return ts.parse_query(lang, query_string) end end diff --git a/lua/nvim-treesitter/state.lua b/lua/nvim-treesitter/state.lua deleted file mode 100644 index adff7eeaf..000000000 --- a/lua/nvim-treesitter/state.lua +++ /dev/null @@ -1,122 +0,0 @@ -local api = vim.api - -local utils = require'nvim-treesitter.utils' - -local M = {} - -local buffers = {} - -local g_mode = api.nvim_get_mode().mode - -local function get_selection_range() - local _, vstart_row, vstart_col, _ = unpack(vim.fn.getpos("v")) - local _, cursor_row, cursor_col, _ = unpack(vim.fn.getpos(".")) - if vstart_row < cursor_row then - return vstart_row, vstart_col, cursor_row, cursor_col - else - return cursor_row, cursor_col, vstart_row, vstart_col - end -end - -function M.update() - local bufnr = api.nvim_get_current_buf() - local buf_config = buffers[bufnr] - if not buf_config then return end - - local mode = api.nvim_get_mode().mode - local cursor = api.nvim_win_get_cursor(0) - local row = cursor[1] - local col = cursor[2] - if row == buf_config.cursor_pos.row - and col == buf_config.cursor_pos.col - and mode == g_mode - then - return - end - - local root = buf_config.parser.tree:root() - if not root then return end - - local new_node = root:named_descendant_for_range(row - 1, col, row - 1, col) - - if new_node ~= buf_config.current_node then - buf_config.current_node = new_node - end - - -- We only want to update the range when the incremental selection has not started yet - if mode == "v" and #buf_config.selection.nodes == 0 then - local row_start, col_start, row_end, col_end = get_selection_range() - buf_config.selection.range = { row_start, col_start, row_end, col_end } - elseif mode ~= "v" then - buf_config.selection.nodes = {} - buf_config.selection.range = nil - end - - g_mode = mode - buf_config.cursor_pos.row = row - buf_config.cursor_pos.col = col -end - -function M.insert_selection_node(bufnr, range) - local buf_config = buffers[bufnr] - if not buf_config then return end - - table.insert(buffers[bufnr].selection.nodes, range) -end - -function M.pop_selection_node(bufnr) - local buf_config = buffers[bufnr] - if not buf_config then return end - - table.remove( - buffers[bufnr].selection.nodes, - #buffers[bufnr].selection.nodes - ) -end - -function M.run_update() - local cmd = "lua require'nvim-treesitter.state'.update()" - api.nvim_command('autocmd NvimTreesitter CursorMoved * '..cmd) -end - -function M.attach_to_buffer(ft) - local bufnr = api.nvim_get_current_buf() - local ft = ft or api.nvim_buf_get_option(bufnr, 'ft') - - if buffers[bufnr] then return end - - local parser = utils.get_parser(bufnr, ft) - if not parser then return end - - buffers[bufnr] = { - cursor_pos = {}, - current_node = nil, - selection = { - range = nil, - nodes = {} - }, - parser = parser, - } - - M.update() - api.nvim_buf_attach(bufnr, false, { - -- TODO(kyazdani): on lines should only parse the changed content - -- TODO(kyazdani): add a timer to avoid too frequent updates - on_lines = function(_, buf) buffers[buf].parser:parse() end, - on_detach = function(bufnr) buffers[bufnr] = nil end, - }) -end - -function M.get_buf_state(bufnr) - return buffers[bufnr] -end - -function M.exposed_state(bufnr) - local buf_state = buffers[bufnr] - return { - cursor_pos = buf_state.cursor_pos, - current_node = buf_state.current_node - } -end - -return M diff --git a/lua/nvim-treesitter/ts_utils.lua b/lua/nvim-treesitter/ts_utils.lua index 1445418e0..687a3c539 100644 --- a/lua/nvim-treesitter/ts_utils.lua +++ b/lua/nvim-treesitter/ts_utils.lua @@ -1,6 +1,7 @@ local api = vim.api local locals = require'nvim-treesitter.locals' +local parsers = require'nvim-treesitter.parsers' local M = {} @@ -205,4 +206,10 @@ function M.previous_scope(node) end end +function M.get_node_at_cursor(winnr) + local cursor = api.nvim_win_get_cursor(winnr or 0) + local root = parsers.get_parser().tree:root() + return root:named_descendant_for_range(cursor[1]-1,cursor[2],cursor[1]-1,cursor[2]) +end + return M diff --git a/lua/nvim-treesitter/utils.lua b/lua/nvim-treesitter/utils.lua index 9dc5d17bd..6fa159817 100644 --- a/lua/nvim-treesitter/utils.lua +++ b/lua/nvim-treesitter/utils.lua @@ -45,23 +45,4 @@ function M.get_cache_dir() return nil, 'Invalid cache rights, $XDG_CACHE_HOME or /tmp should be read/write' end -function M.has_parser(lang) - local lang = lang or api.nvim_buf_get_option(0, 'filetype') - return #api.nvim_get_runtime_file('parser/' .. lang .. '.so', false) > 0 -end - -function M.get_parser(bufnr, lang) - if M.has_parser() then - local buf = bufnr or api.nvim_get_current_buf() - local lang = lang or api.nvim_buf_get_option(buf, 'ft') - if not M[buf] then - M[buf] = {} - end - if not M[buf][lang] then - M[buf][lang] = ts.get_parser(buf, lang) - end - return M[buf][lang] - end -end - return M diff --git a/plugin/nvim-treesitter.vim b/plugin/nvim-treesitter.vim index 30ee3241d..24a8eceb6 100644 --- a/plugin/nvim-treesitter.vim +++ b/plugin/nvim-treesitter.vim @@ -1,4 +1,4 @@ -" Last Change: 2020 avril 25 +" Last Change: 2020 Jun 29 if exists('g:loaded_nvim_treesitter') finish @@ -11,10 +11,49 @@ let g:loaded_nvim_treesitter = 1 lua << EOF ts_installable_parsers = function() - return table.concat(require'nvim-treesitter.configs'.available_parsers(), '\n') + return table.concat(require'nvim-treesitter.parsers'.available_parsers(), '\n') end ts_available_modules = function() return table.concat(require'nvim-treesitter.configs'.available_modules(), '\n') end require'nvim-treesitter'.setup() EOF + +highlight default link TSError Error + +highlight default link TSPunctDelimiter Delimiter +highlight default link TSPunctBracket Delimiter +highlight default link TSPunctSpecial Delimiter + +highlight default link TSConstant Constant +highlight default link TSConstBuiltin Special +highlight default link TSConstMacro Define +highlight default link TSString String +highlight default link TSStringRegex String +highlight default link TSStringEscape SpecialChar +highlight default link TSCharacter Character +highlight default link TSNumber Number +highlight default link TSBoolean Boolean +highlight default link TSFloat TSFloat + +highlight default link TSFunction Function +highlight default link TSFuncBuiltin Special +highlight default link TSFuncMacro Macro +highlight default link TSParameter Identifier +highlight default link TSMethod Function +highlight default link TSField Identifier +highlight default link TSProperty Identifier +highlight default link TSConstructor Special + +highlight default link TSConditional Conditional +highlight default link TSRepeat Repeat +highlight default link TSLabel Label +highlight default link TSOperator Operator +highlight default link TSKeyword Keyword +highlight default link TSException Exception + +highlight default link TSType Type +highlight default link TSTypeBuiltin Type +highlight default link TSStructure Structure +highlight default link TSInclude Include + diff --git a/queries/bash/highlights.scm b/queries/bash/highlights.scm new file mode 100644 index 000000000..c0ec8d698 --- /dev/null +++ b/queries/bash/highlights.scm @@ -0,0 +1,110 @@ +[ + "(" + ")" + "{" + "}" + "[" + "]" + ] @punctuation.bracket + +[ + ";" + ";;" + (heredoc_start) + ] @punctuation.delimiter + +[ + ">" + "<" + "&" + "&&" + "|" + "||" + "=" + "==" + "!=" + ] @operator + +[ + (string) + (raw_string) + (heredoc_body) +] @string + +[ + "if" + "then" + "else" + "elif" + "fi" + "case" + "in" + "esac" + ] @conditional + +[ + "for" + "do" + "done" + "while" + ] @repeat + +[ + "declare" + "export" + "local" + "readonly" + "unset" + ] @keyword + +[ + (special_variable_name) + ("$" (special_variable_name)) + ] @constant + +((word) @constant + (#match? @constant "SIG(INT|TERM|QUIT|TIN|TOU|STP|HUP)")) + +((word) @boolean + (#match? @boolean "true|false")) + +((word) @number + (#match? @number "^\d*$")) + +(comment) @comment +(test_operator) @string. + +(command_substitution + [ "$(" ")" ] @punctuation.bracket) + + +(function_definition + name: (word) @function) + +(command_name (word)) @function + +(command + argument: [ + (word) @parameter + ((word) @number + (#match? @number "^\d*$")) + (concatenation (word) @parameter) + ]) + +(file_redirect + descriptor: (file_descriptor) @operator + destination: (word) @parameter) + + +("$" (variable_name)) @identifier + +(expansion + [ "${" "}" ] @punctuation.bracket) + +(variable_name) @identifier + +(case_item + value: (word) @parameter) + +(concatenation (word) @parameter) + diff --git a/queries/c/highlights.scm b/queries/c/highlights.scm index 4cfb042cc..b3889dbd8 100644 --- a/queries/c/highlights.scm +++ b/queries/c/highlights.scm @@ -21,32 +21,55 @@ "while" @repeat "#define" @constant.macro -"#else" @keyword -"#endif" @keyword -"#if" @keyword -"#ifdef" @keyword -"#ifndef" @keyword -"#include" @keyword -(preproc_directive) @keyword +[ + "#if" + "#ifdef" + "#ifndef" + "#else" + "#elif" + "#endif" + "#include" + (preproc_directive) +] @keyword "--" @operator "-" @operator -"-=" @operator "->" @operator "!=" @operator "*" @operator +"/" @operator "&" @operator "&&" @operator "+" @operator "++" @operator -"+=" @operator "<" @operator +"<=" @operator "==" @operator +"=" @operator +"~" @operator ">" @operator +">=" @operator +"!" @operator "||" @operator -"." @delimiter -";" @delimiter +"-=" @operator +"+=" @operator +"*=" @operator +"/=" @operator +"|=" @operator +"&=" @operator + +"." @punctuation.delimiter +";" @punctuation.delimiter +":" @punctuation.delimiter +"," @punctuation.delimiter + +"(" @punctuation.bracket +")" @punctuation.bracket +"[" @punctuation.bracket +"]" @punctuation.bracket +"{" @punctuation.bracket +"}" @punctuation.bracket (string_literal) @string (system_lib_string) @string @@ -64,6 +87,8 @@ declarator: (identifier) @function) (preproc_function_def name: (identifier) @function.macro) +(preproc_arg) @function.macro +; TODO (preproc_arg) @embedded (field_identifier) @property (statement_identifier) @label @@ -71,7 +96,20 @@ (primitive_type) @type (sized_type_specifier) @type +((identifier) @type + (#match? @type "^[A-Z]")) + ((identifier) @constant - (match? @constant "^[A-Z][A-Z\\d_]+$")) + (#match? @constant "^[A-Z][A-Z0-9_]+$")) (comment) @comment + +;; Parameters +(parameter_list + (parameter_declaration) @parameter) + +(preproc_params + (identifier)) @parameter + +(ERROR) @error + diff --git a/queries/c/locals.scm b/queries/c/locals.scm index b08d706ee..505db5b57 100644 --- a/queries/c/locals.scm +++ b/queries/c/locals.scm @@ -17,7 +17,7 @@ (declaration declarator: (identifier) @definition.var) (enum_specifier - name: (*) @definition.type + name: (_) @definition.type (enumerator_list (enumerator name: (identifier) @definition.var))) @@ -36,3 +36,4 @@ (while_statement) @scope (translation_unit) @scope (function_definition) @scope +(compound_statement) @scope ; a block in curly braces diff --git a/queries/cpp/highlights.scm b/queries/cpp/highlights.scm new file mode 100644 index 000000000..0d8295a1d --- /dev/null +++ b/queries/cpp/highlights.scm @@ -0,0 +1,96 @@ +((identifier) @field + (#match? @field "^_")) + +((identifier) @field + (#match? @field "^m_")) + +((identifier) @field + (#match? @field "_$")) + +;(field_expression) @parameter ;; How to highlight this? +(template_function + name: (identifier) @function) + +(template_method + name: (field_identifier) @method) + +(template_function + name: (scoped_identifier + name: (identifier) @function)) + +(namespace_identifier) @constant + +((namespace_identifier) @type + (#match? @type "^[A-Z]")) +((namespace_identifier) @constant + (#match? @constant "^[A-Z][A-Z_0-9]*$")) + +(destructor_name + name: (_) @function) + +(function_declarator + declarator: (scoped_identifier + name: (identifier) @function)) +((function_declarator + declarator: (scoped_identifier + name: (identifier) @constructor)) + (#match? @constructor "^[A-Z]")) + +(call_expression + function: (scoped_identifier + name: (identifier) @function)) + +(call_expression + function: (field_expression + field: (field_identifier) @function)) + +((call_expression + function: (scoped_identifier + name: (identifier) @constructor)) +(#match? @constructor "^[A-Z]")) + +((call_expression + function: (field_expression + field: (field_identifier) @constructor)) +(#match? @constructor "^[A-Z]")) + +;; constructing a type in a intizializer list: Constructor (): **SuperType (1)** +((field_initializer + (field_identifier) @constructor + (argument_list)) + (#match? @constructor "^[A-Z]")) + +(auto) @keyword + +; Constants + +(this) @constant.builtin +(nullptr) @constant + +(true) @boolean +(false) @boolean + +; Keywords + +"catch" @exception +"class" @keyword +"constexpr" @keyword +"delete" @keyword +"explicit" @keyword +"final" @exception +"friend" @keyword +"mutable" @keyword +"namespace" @keyword +"noexcept" @keyword +"new" @keyword +"override" @keyword +"private" @keyword +"protected" @keyword +"public" @keyword +"template" @keyword +"throw" @keyword +"try" @exception +"typename" @keyword +"using" @keyword +"virtual" @keyword +"::" @operator diff --git a/queries/cpp/locals.scm b/queries/cpp/locals.scm new file mode 100644 index 000000000..061153c04 --- /dev/null +++ b/queries/cpp/locals.scm @@ -0,0 +1,49 @@ + +;; Class / struct defintions +(class_specifier) @scope +(struct_specifier) @scope + + +(struct_specifier + name: (type_identifier) @definition.type) + +(struct_specifier + name: (scoped_type_identifier + name: (type_identifier) @definition.type) ) + +(class_specifier + name: (type_identifier) @definition.type) + +(class_specifier + name: (scoped_type_identifier + name: (type_identifier) @definition.type) ) + +;; Function defintions +(template_function + name: (identifier) @definition.function) @scope + +(template_method + name: (field_identifier) @definition.method) @scope + +(template_function + name: (scoped_identifier + name: (identifier) @definition.function)) @scope + +(function_declarator + declarator: (scoped_identifier + name: (type_identifier) @definition.function)) @scope + +(field_declaration + declarator: (function_declarator + (field_identifier) @definition.method)) + +(lambda_expression) @scope + +;; Control structures +(try_statement + body: (_) @scope) + +(catch_clause) @scope + +(destructor_name + name: (_) @constructor) diff --git a/queries/css/highlights.scm b/queries/css/highlights.scm index 3fc468ca3..1b876c4b1 100644 --- a/queries/css/highlights.scm +++ b/queries/css/highlights.scm @@ -1,72 +1,91 @@ -"@media" @keyword -"@import" @include -"@charset" @keyword -"@namespace" @keyword -"@supports" @keyword -"@keyframes" @keyword -(at_keyword) @keyword -(to) @keyword -(from) @keyword -(important) @keyword +[ + "@media" + "@import" + "@charset" + "@namespace" + "@supports" + "@keyframes" + (at_keyword) + (to) + (from) + (important) + ] @keyword (comment) @comment -(tag_name) @type -(nesting_selector) @type -(universal_selector) @type +[ + (tag_name) + (nesting_selector) + (universal_selector) + ] @type (function_name) @function -"~" @operator -">" @operator -"+" @operator -"-" @operator -"*" @operator -"/" @operator -"=" @operator -"^=" @operator -"|=" @operator -"~=" @operator -"$=" @operator -"*=" @operator +[ + "~" + ">" + "+" + "-" + "*" + "/" + "=" + "^=" + "|=" + "~=" + "$=" + "*=" + "and" + "or" + "not" + "only" + ] @operator -"and" @operator -"or" @operator -"not" @operator -"only" @operator (attribute_selector (plain_value) @string) (pseudo_element_selector (tag_name) @property) (pseudo_class_selector (class_name) @property) -(class_name) @property -(id_name) @property -(namespace_name) @property -(property_name) @property -(feature_name) @property -(attribute_name) @property +[ + (class_name) + (id_name) + (namespace_name) + (property_name) + (feature_name) + (attribute_name) + ] @property ((property_name) @type - (match? @type "^--")) + (#match? @type "^--")) ((plain_value) @type - (match? @type "^--")) + (#match? @type "^--")) -(string_value) @string -(color_value) @string -(identifier) @string +[ + (string_value) + (color_value) + (identifier) + (unit) + ] @string -(integer_value) @number -(float_value) @number -(unit) @string +[ + (integer_value) + (float_value) + ] @number -"#" @punctuation.delimiter -"," @punctuation.delimiter -"." @punctuation.delimiter -":" @punctuation.delimiter -"::" @punctuation.delimiter -";" @punctuation.delimiter -"{" @punctuation.bracket -")" @punctuation.bracket -"(" @punctuation.bracket -"}" @punctuation.bracket +[ + "#" + "," + "." + ":" + "::" + ";" + ] @punctuation.delimiter + +[ + "{" + ")" + "(" + "}" + ] @punctuation.bracket + +(ERROR) @error diff --git a/queries/html/highlights.scm b/queries/html/highlights.scm index 582e1e46f..1e83ecf4c 100644 --- a/queries/html/highlights.scm +++ b/queries/html/highlights.scm @@ -8,8 +8,9 @@ "=" @operator -"<" @punctuation.bracket -">" @punctuation.bracket -"" @punctuation.bracket - +[ + "<" + ">" + "" + ] @punctuation.bracket diff --git a/queries/javascript/highlights.scm b/queries/javascript/highlights.scm new file mode 100644 index 000000000..dfbabc977 --- /dev/null +++ b/queries/javascript/highlights.scm @@ -0,0 +1,190 @@ +; Types + +; Javascript +; Special identifiers +;-------------------- + +((identifier) @constant + (#match? @constant "^[A-Z_][A-Z\\d_]+$")) + +((shorthand_property_identifier) @constant + (#match? @constant "^[A-Z_][A-Z\\d_]+$")) + +((identifier) @constructor + (#match? @constructor "^[A-Z]")) + +((identifier) @variable.builtin + (#match? @variable.builtin "^(arguments|module|console|window|document)$")) + +((identifier) @function.builtin + (#eq? @function.builtin "require")) + +; Function and method definitions +;-------------------------------- + +(function + name: (identifier) @function) +(function_declaration + name: (identifier) @function) +(method_definition + name: (property_identifier) @function.method) + +(pair + key: (property_identifier) @function.method + value: (function)) +(pair + key: (property_identifier) @function.method + value: (arrow_function)) + +(assignment_expression + left: (member_expression + property: (property_identifier) @function.method) + right: (arrow_function)) +(assignment_expression + left: (member_expression + property: (property_identifier) @function.method) + right: (function)) + +(variable_declarator + name: (identifier) @function + value: (arrow_function)) +(variable_declarator + name: (identifier) @function + value: (function)) + +(assignment_expression + left: (identifier) @function + right: (arrow_function)) +(assignment_expression + left: (identifier) @function + right: (function)) + +; Function and method calls +;-------------------------- + +(call_expression + function: (identifier) @function) + +(call_expression + function: (member_expression + property: (property_identifier) @function.method)) + +; Variables +;---------- + +(formal_parameters (identifier) @variable.parameter) + +(identifier) @variable + +; Properties +;----------- + +(property_identifier) @property + +; Literals +;--------- + +(this) @variable.builtin +(super) @variable.builtin + +(true) @boolean +(false) @boolean +(null) @constant.builtin +(comment) @comment +(string) @string +(regex) @string.special +(template_string) @string +(number) @number + +; Punctuation +;------------ + +(template_substitution + "${" @punctuation.special + "}" @punctuation.special) @embedded + +";" @punctuation.delimiter +"." @punctuation.delimiter +"," @punctuation.delimiter + +"--" @operator +"-" @operator +"-=" @operator +"&&" @operator +"+" @operator +"++" @operator +"+=" @operator +"<" @operator +"<<" @operator +"=" @operator +"==" @operator +"===" @operator +"=>" @operator +">" @operator +">>" @operator +"||" @operator +"??" @operator + +"(" @punctuation.bracket +")" @punctuation.bracket +"[" @punctuation.bracket +"]" @punctuation.bracket +"{" @punctuation.bracket +"}" @punctuation.bracket + +; Keywords +;---------- + +[ +"if" +"else" +"switch" +"case" +"default" +] @conditional + +[ +"import" +"from" +"as" +] @include + +[ +"for" +"of" +"do" +"while" +"continue" +] @repeat + +[ +"async" +"await" +"break" +"catch" +"class" +"const" +"debugger" +"delete" +"export" +"extends" +"finally" +"function" +"get" +"in" +"instanceof" +"let" +"new" +"return" +"set" +"static" +"switch" +"target" +"throw" +"try" +"typeof" +"var" +"void" +"with" +"yield" +] @keyword diff --git a/queries/javascript/locals.scm b/queries/javascript/locals.scm new file mode 100644 index 000000000..165adfed9 --- /dev/null +++ b/queries/javascript/locals.scm @@ -0,0 +1,35 @@ +; Scopes +;------- + +(statement_block) @scope +(function) @scope +(arrow_function) @scope +(function_declaration) @scope +(method_definition) @scope + +; Definitions +;------------ + +(formal_parameters + (identifier) @definition) + +(formal_parameters + (object_pattern + (identifier) @definition)) + +(formal_parameters + (object_pattern + (shorthand_property_identifier) @definition)) + +(formal_parameters + (array_pattern + (identifier) @definition)) + +(variable_declarator + name: (identifier) @definition) + +; References +;------------ + +(identifier) @reference + diff --git a/queries/json/highlights.scm b/queries/json/highlights.scm new file mode 100644 index 000000000..bdc35ad98 --- /dev/null +++ b/queries/json/highlights.scm @@ -0,0 +1,13 @@ +(true) @boolean +(false) @boolean +(null) @constant.builtin +(number) @number +(pair key: (string) @label) +(pair value: (string) @string) +(string_content (escape_sequence) @string.escape) +(ERROR) @error +"," @punctuation.delimiter +"[" @punctuation.bracket +"]" @punctuation.bracket +"{" @punctuation.bracket +"}" @punctuation.bracket diff --git a/queries/python/highlights.scm b/queries/python/highlights.scm index 0b6e30033..ca0f84387 100644 --- a/queries/python/highlights.scm +++ b/queries/python/highlights.scm @@ -1,33 +1,38 @@ ;; From tree-sitter-python licensed under MIT License ; Copyright (c) 2016 Max Brunsfeld +; Reset highlighing in f-string interpolations +(interpolation) @Normal + ; Identifier naming conventions - - -((import_from_statement - name: (dotted_name - (identifier)) @type) - (match? @type "^[A-Z]")) - ((identifier) @type (match? @type "^[A-Z]")) - ((identifier) @constant - (match? @constant "^[A-Z][A-Z_]*$")) + (match? @constant "^[A-Z][A-Z_0-9]*$")) + +((identifier) @constant.builtin + (match? @constant.builtin "^__[a-zA-Z0-9_]*__$")) ; Function calls (decorator) @function +((decorator (dotted_name (identifier) @function)) + (match? @function "^([A-Z])@!.*$")) + +(call + function: (identifier) @function) (call function: (attribute attribute: (identifier) @method)) -(call - function: (identifier) @function) +((call + function: (identifier) @constructor) + (match? @constructor "^[A-Z]")) ((call - (identifier) @constructor) + function: (attribute + attribute: (identifier) @constructor)) (match? @constructor "^[A-Z]")) ;; Builtin functions @@ -43,10 +48,9 @@ (function_definition name: (identifier) @function) -(identifier) @variable -(attribute attribute: (identifier) @property) (type (identifier) @type) -((call + +((call function: (identifier) @isinstance arguments: (argument_list (*) @@ -55,7 +59,7 @@ ; Normal parameters (parameters - (identifier) @parameter) + (identifier) @parameter) ; Default parameters (keyword_argument name: (identifier) @parameter) @@ -65,17 +69,16 @@ ; Variadic parameters *args, **kwargs (parameters (list_splat ; *args - (identifier) @parameter)) + (identifier) @parameter)) (parameters (dictionary_splat ; **kwargs - (identifier) @parameter)) + (identifier) @parameter)) ; Literals (none) @constant.builtin -(true) @boolean -(false) @boolean +[(true) (false)] @boolean ((identifier) @constant.builtin (match? @constant.builtin "self")) @@ -84,126 +87,103 @@ (comment) @comment (string) @string -(escape_sequence) @escape +(escape_sequence) @string.escape + +; Tokens + +[ + "-" + "-=" + ":=" + "!=" + "*" + "**" + "**=" + "*=" + "/" + "//" + "//=" + "/=" + "&" + "%" + "%=" + "^" + "+" + "+=" + "<" + "<<" + "<=" + "<>" + "=" + "==" + ">" + ">=" + ">>" + "|" + "~" + "and" + "in" + "is" + "not" + "or" +] @operator + +; Keywords + +[ + "assert" + "await" + "class" + "def" + "del" + "except" + "exec" + "finally" + "global" + "lambda" + "nonlocal" + "pass" + "print" + "raise" + "return" + "try" + "with" + "yield" +] @keyword + +[ "as" "from" "import"] @include + +[ "if" "elif" "else" ] @conditional + +[ "for" "while" "break" "continue" ] @repeat + +[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket (interpolation "{" @punctuation.special "}" @punctuation.special) @embedded -; Tokens +[ "," "." ":" ] @punctuation.delimiter -"-" @operator -"->" @operator -"-=" @operator -"!=" @operator -"*" @operator -"**" @operator -"**=" @operator -"*=" @operator -"/" @operator -"//" @operator -"//=" @operator -"/=" @operator -"&" @operator -"%" @operator -"%=" @operator -"^" @operator -"+" @operator -"+=" @operator -"<" @operator -"<<" @operator -"<=" @operator -"<>" @operator -"=" @operator -"==" @operator -">" @operator -">=" @operator -">>" @operator -"|" @operator -"~" @operator -"and" @operator -"in" @operator -"is" @operator -"not" @operator -"or" @operator - -; Keywords - -"as" @include -"assert" @keyword -"async" @keyword -"await" @keyword -"break" @repeat -"class" @keyword -"continue" @repeat -"def" @keyword -"del" @keyword -"elif" @conditional -"else" @conditional -"except" @keyword -"exec" @keyword -"finally" @keyword -"for" @repeat -"from" @include -"global" @keyword -"if" @conditional -"import" @include -"lambda" @keyword -"nonlocal" @keyword -"pass" @keyword -"print" @keyword -"raise" @keyword -"return" @keyword -"try" @keyword -"while" @repeat -"with" @keyword -"yield" @keyword - -; Additions for nvim-treesitter -"(" @punctuation.bracket -")" @punctuation.bracket -"[" @punctuation.bracket -"]" @punctuation.bracket - -"," @punctuation.delimiter -"." @punctuation.delimiter -":" @punctuation.delimiter +; Class definitions (class_definition name: (identifier) @type) (class_definition - superclasses: (argument_list + superclasses: (argument_list (identifier) @type)) -(attribute +((attribute attribute: (identifier) @field) - -((attribute - attribute: (identifier) @constant) - (match? @constant "^[A-Z][A-Z_]*$")) - -((attribute - attribute: (identifier) @type) - (match? @type "^[A-Z][a-z_]+")) - -((attribute - object: (identifier) @type) - (match? @type "^[A-Z][a-z_]+")) - -(class_definition - body: (block - (expression_statement - (assignment - left: (expression_list - (identifier) @field))))) + (match? @field "^([A-Z])@!.*$")) ((class_definition body: (block (expression_statement (assignment left: (expression_list - (identifier) @constant))))) - (match? @constant "^[A-Z][A-Z_]*$")) + (identifier) @field))))) + (match? @field "^([A-Z])@!.*$")) ;; Error (ERROR) @error diff --git a/queries/python/locals.scm b/queries/python/locals.scm index 735271663..cdf4d4117 100644 --- a/queries/python/locals.scm +++ b/queries/python/locals.scm @@ -30,12 +30,8 @@ ; Function defines function and scope (function_definition - name: (identifier) @definition.function) @scope - -;; Should be extended to when syntax supported -;(function_definition - ;name: (identifier) @definition.function - ;body: (block (expression_statement (string) @definition.function.doc)?)) @scope + name: (identifier) @definition.function + body: (block (expression_statement (string) @definition.doc)?)) @scope (class_definition diff --git a/queries/regex/highlights.scm b/queries/regex/highlights.scm new file mode 100644 index 000000000..48242543f --- /dev/null +++ b/queries/regex/highlights.scm @@ -0,0 +1,29 @@ +;; Forked from tree-sitter-regex +;; The MIT License (MIT) Copyright (c) 2014 Max Brunsfeld +[ + "(" + ")" + "(?" + "(?:" + "(?<" + ">" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +(group_name) @property + +[ + (identity_escape) + (control_letter_escape) + (character_class_escape) + (control_escape) + (start_assertion) + (end_assertion) + (boundary_assertion) + (non_boundary_assertion) +] @escape + +[ "*" "+" "|" "=" "<=" "!" "" @operator -"->" @operator -"+" @operator -"-" @operator -"*" @operator -"/" @operator +[ + "=" + "=>" + "->" + "+" + "-" + "*" + "/" + ] @operator -"," @punctuation.delimiter -";" @punctuation.delimiter -"." @punctuation.delimiter +[ + "," + ";" + "." + ] @punctuation.delimiter -"(" @punctuation.bracket -")" @punctuation.bracket -"[" @punctuation.bracket -"]" @punctuation.bracket -"{" @punctuation.bracket -"}" @punctuation.bracket -"%w(" @punctuation.bracket -"%i(" @punctuation.bracket +[ + "(" + ")" + "[" + "]" + "{" + "}" + "%w(" + "%i(" + ] @punctuation.bracket (ERROR) @error diff --git a/queries/ruby/locals.scm b/queries/ruby/locals.scm index f50c2cc99..fe5122d2d 100644 --- a/queries/ruby/locals.scm +++ b/queries/ruby/locals.scm @@ -24,8 +24,10 @@ ((method) @scope (set! scope-inherits false)) -(block) @scope -(do_block) @scope +[ + (block) + (do_block) + ] @scope (method_parameters (identifier) @definition.function) (lambda_parameters (identifier) @definition.function) diff --git a/queries/typescript/highlights.scm b/queries/typescript/highlights.scm new file mode 100644 index 000000000..dd0dd778f --- /dev/null +++ b/queries/typescript/highlights.scm @@ -0,0 +1,27 @@ +[ +"abstract" +"declare" +"enum" +"export" +"implements" +"interface" +"keyof" +"namespace" +"private" +"protected" +"public" +"type" +] @keyword + +(readonly) @keyword +(type_identifier) @type +(predefined_type) @type.builtin + +(type_arguments + "<" @punctuation.bracket + ">" @punctuation.bracket) + +; Variables + +(required_parameter (identifier) @variable.parameter) +(optional_parameter (identifier) @variable.parameter) diff --git a/queries/typescript/locals.scm b/queries/typescript/locals.scm new file mode 100644 index 000000000..cb064b823 --- /dev/null +++ b/queries/typescript/locals.scm @@ -0,0 +1,2 @@ +(required_parameter (identifier) @definition) +(optional_parameter (identifier) @definition)