aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-09-06 10:10:01 +0200
committerGitHub <noreply@github.com>2022-09-06 10:10:01 +0200
commit5b8d6e0b3200c5cb9d98cbdb4ed0afe2b4edd38d (patch)
tree23aac48c4aff31236341260942ceeb7b42fc90ab
parent4bf005e9fdfb57397475b2663a3651faa83886ff (diff)
parent0822896efcf0da7002e323369fdc1e4a15ad1d57 (diff)
downloadrneovim-5b8d6e0b3200c5cb9d98cbdb4ed0afe2b4edd38d.tar.gz
rneovim-5b8d6e0b3200c5cb9d98cbdb4ed0afe2b4edd38d.tar.bz2
rneovim-5b8d6e0b3200c5cb9d98cbdb4ed0afe2b4edd38d.zip
Merge pull request #15391 from vigoux/ts-lua-builtin
feat(treesitter): highlighting for core languages, enabled for Lua
-rwxr-xr-x.github/workflows/env.sh2
-rw-r--r--cmake.deps/CMakeLists.txt6
-rw-r--r--cmake.deps/cmake/BuildTreesitterParsers.cmake52
-rw-r--r--cmake.deps/cmake/TreesitterParserCMakeLists.txt7
-rw-r--r--runtime/CMakeLists.txt2
-rw-r--r--runtime/doc/treesitter.txt67
-rw-r--r--runtime/ftplugin/lua.lua3
-rw-r--r--runtime/lua/vim/treesitter.lua86
-rw-r--r--runtime/queries/c/injections.scm3
-rw-r--r--runtime/queries/lua/highlights.scm192
-rw-r--r--runtime/queries/lua/injections.scm22
-rw-r--r--runtime/queries/vim/highlights.scm245
-rw-r--r--runtime/queries/vim/injections.scm26
-rw-r--r--runtime/syntax/syntax.vim6
-rw-r--r--src/nvim/highlight_group.c1
-rw-r--r--test/functional/helpers.lua10
-rw-r--r--test/functional/treesitter/highlight_spec.lua25
-rw-r--r--test/functional/treesitter/language_spec.lua12
-rw-r--r--test/functional/treesitter/node_spec.lua5
-rw-r--r--test/functional/treesitter/parser_spec.lua3
-rw-r--r--test/functional/treesitter/utils_spec.lua2
21 files changed, 658 insertions, 119 deletions
diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh
index 061588da1a..da70d358a9 100755
--- a/.github/workflows/env.sh
+++ b/.github/workflows/env.sh
@@ -57,7 +57,7 @@ EOF
functionaltest-lua)
BUILD_FLAGS="$BUILD_FLAGS -DPREFER_LUA=ON"
FUNCTIONALTEST=functionaltest-lua
- DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF -DUSE_BUNDLED_TS_PARSERS=OFF"
+ DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
;;
*)
;;
diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt
index d2047c5b3d..2c19aa6e6b 100644
--- a/cmake.deps/CMakeLists.txt
+++ b/cmake.deps/CMakeLists.txt
@@ -208,6 +208,12 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891
set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.2.tar.gz)
set(TREESITTER_C_SHA256 af66fde03feb0df4faf03750102a0d265b007e5d957057b6b293c13116a70af2 )
+set(TREESITTER_LUA_URL https://github.com/MunifTanjim/tree-sitter-lua/archive/v0.0.12.tar.gz)
+set(TREESITTER_LUA_SHA256 b6d7c6d04e9101a2e589d25f1d61668301e776c0b8defa6eae8dd86272e9e7c3)
+
+set(TREESITTER_VIM_URL https://github.com/vigoux/tree-sitter-viml/archive/v0.1.0.tar.gz)
+set(TREESITTER_VIM_SHA256 ea64fa211ccc7197669017b55911fdb56e8d4b6de96ba25c32b9586ec1c4f4c5)
+
set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.7.tar.gz)
set(TREESITTER_SHA256 b355e968ec2d0241bbd96748e00a9038f83968f85d822ecb9940cbe4c42e182e)
diff --git a/cmake.deps/cmake/BuildTreesitterParsers.cmake b/cmake.deps/cmake/BuildTreesitterParsers.cmake
index 1ff86e89b9..dd3f4eb308 100644
--- a/cmake.deps/cmake/BuildTreesitterParsers.cmake
+++ b/cmake.deps/cmake/BuildTreesitterParsers.cmake
@@ -1,29 +1,25 @@
-ExternalProject_Add(treesitter-c
-PREFIX ${DEPS_BUILD_DIR}
-URL ${TREESITTER_C_URL}
-DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/treesitter-c
-DOWNLOAD_COMMAND ${CMAKE_COMMAND}
- -DPREFIX=${DEPS_BUILD_DIR}
- -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/treesitter-c
- -DURL=${TREESITTER_C_URL}
- -DEXPECTED_SHA256=${TREESITTER_C_SHA256}
- -DTARGET=treesitter-c
- -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
- -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
-PATCH_COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TreesitterParserCMakeLists.txt
- ${DEPS_BUILD_DIR}/src/treesitter-c/CMakeLists.txt
-CMAKE_ARGS
- -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
- -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
- -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
- ${BUILD_TYPE_STRING}
- -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
- -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_ALT_SEP}
- # Pass toolchain
- -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
- -DPARSERLANG=c
+function(BuildTSParser LANG TS_URL TS_SHA256 TS_CMAKE_FILE)
+ set(NAME treesitter-${LANG})
+ ExternalProject_Add(${NAME}
+ PREFIX ${DEPS_BUILD_DIR}
+ URL ${TREESITTER_C_URL}
+ DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/${NAME}
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND}
+ -DPREFIX=${DEPS_BUILD_DIR}
+ -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/${NAME}
+ -DURL=${TS_URL}
+ -DEXPECTED_SHA256=${TS_SHA256}
+ -DTARGET=${NAME}
+ -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
+ PATCH_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TS_CMAKE_FILE}
+ ${DEPS_BUILD_DIR}/src/${NAME}/CMakeLists.txt
+ CMAKE_ARGS
+ -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
+ -DPARSERLANG=${LANG})
+endfunction()
-BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}
-INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE}
-LIST_SEPARATOR |)
+BuildTSParser(c ${TREESITTER_C_URL} ${TREESITTER_C_SHA256} TreesitterParserCMakeLists.txt)
+BuildTSParser(lua ${TREESITTER_LUA_URL} ${TREESITTER_LUA_SHA256} TreesitterParserCMakeLists.txt)
+BuildTSParser(vim ${TREESITTER_VIM_URL} ${TREESITTER_VIM_SHA256} TreesitterParserCMakeLists.txt)
diff --git a/cmake.deps/cmake/TreesitterParserCMakeLists.txt b/cmake.deps/cmake/TreesitterParserCMakeLists.txt
index 54bc35fb8a..9ec7a23864 100644
--- a/cmake.deps/cmake/TreesitterParserCMakeLists.txt
+++ b/cmake.deps/cmake/TreesitterParserCMakeLists.txt
@@ -1,10 +1,11 @@
cmake_minimum_required(VERSION 3.10)
-# some parsers have c++ scanner, problem?
-project(parser C) # CXX
+project(parser C)
+
+file(GLOB source_files src/*.c)
add_library(parser
MODULE
- src/parser.c
+ ${source_files}
)
set_target_properties(
parser
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index e0a0b34d28..b42b1de54b 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -123,7 +123,7 @@ foreach(PROG ${RUNTIME_PROGRAMS})
endforeach()
globrecurse_wrapper(RUNTIME_FILES ${CMAKE_CURRENT_SOURCE_DIR}
- *.vim *.lua *.dict *.py *.rb *.ps *.spl *.tutor *.tutor.json)
+ *.vim *.lua *.scm *.dict *.py *.rb *.ps *.spl *.tutor *.tutor.json)
foreach(F ${RUNTIME_FILES})
get_filename_component(BASEDIR ${F} DIRECTORY)
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 2c6c9e4ed8..8d5e494601 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -375,9 +375,9 @@ get_captures_at_position({bufnr}, {row}, {col})
Gets a list of captures for a given cursor position
Parameters: ~
- {bufnr} (number) The buffer number
- {row} (number) The position row
- {col} (number) The position column
+ {bufnr} (number) Buffer number (0 for current buffer)
+ {row} (number) Position row
+ {col} (number) Position column
Return: ~
(table) A table of captures
@@ -398,12 +398,14 @@ get_parser({bufnr}, {lang}, {opts}) *get_parser()*
callback
Parameters: ~
- {bufnr} The buffer the parser should be tied to
- {lang} The filetype of this parser
- {opts} Options object to pass to the created language tree
+ {bufnr} (number|nil) Buffer the parser should be tied to: (default
+ current buffer)
+ {lang} (string) |nil Filetype of this parser (default: buffer
+ filetype)
+ {opts} (table|nil) Options to pass to the created language tree
Return: ~
- The parser
+ (table) Parser object
get_string_parser({str}, {lang}, {opts}) *get_string_parser()*
Gets a string parser
@@ -417,8 +419,8 @@ is_ancestor({dest}, {source}) *is_ancestor()*
Determines whether a node is the ancestor of another
Parameters: ~
- {dest} (table) the possible ancestor
- {source} (table) the possible descendant node
+ {dest} (table) Possible ancestor
+ {source} (table) Possible descendant node
Return: ~
(boolean) True if dest is an ancestor of source
@@ -427,20 +429,57 @@ is_in_node_range({node}, {line}, {col}) *is_in_node_range()*
Determines whether (line, col) position is in node range
Parameters: ~
- {node} Node defining the range
- {line} A line (0-based)
- {col} A column (0-based)
+ {node} (table) Node defining the range
+ {line} (number) Line (0-based)
+ {col} (number) Column (0-based)
+
+ Return: ~
+ (boolean) True if the position is in node range
node_contains({node}, {range}) *node_contains()*
Determines if a node contains a range
Parameters: ~
- {node} (table) The node
- {range} (table) The range
+ {node} (table)
+ {range} (table)
Return: ~
(boolean) True if the node contains the range
+start({bufnr}, {lang}, {opts}) *start()*
+ Start treesitter highlighting for a buffer
+
+ Can be used in an ftplugin or FileType autocommand
+
+ Note: By default, disables regex syntax highlighting, which may be
+ required for some plugins. In this case, add `{ syntax = true }`.
+
+ Example:
+>
+
+ vim.api.nvim_create_autocmd( 'FileType', { pattern = 'tex',
+ callback = function(args)
+ vim.treesitter.start(args.buf, 'latex', { syntax = true })
+ end
+ })
+<
+
+ Parameters: ~
+ {bufnr} (number|nil) Buffer to be highlighted (default: current
+ buffer)
+ {lang} (string|nil) Language of the parser (default: buffer
+ filetype)
+ {opts} (table|nil) Optional keyword arguments:
+ • `syntax` boolean Run regex syntax highlighting (default
+ false)
+
+stop({bufnr}) *stop()*
+ Stop treesitter highlighting for a buffer
+
+ Parameters: ~
+ {bufnr} (number|nil) Buffer to stop highlighting (default: current
+ buffer)
+
==============================================================================
Lua module: vim.treesitter.language *treesitter-language*
diff --git a/runtime/ftplugin/lua.lua b/runtime/ftplugin/lua.lua
new file mode 100644
index 0000000000..415cf28f9a
--- /dev/null
+++ b/runtime/ftplugin/lua.lua
@@ -0,0 +1,3 @@
+if vim.g.ts_highlight_lua then
+ vim.treesitter.start()
+end
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 6431162799..9c43811e03 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -32,9 +32,11 @@ setmetatable(M, {
---
--- It is not recommended to use this, use vim.treesitter.get_parser() instead.
---
----@param bufnr The buffer the parser will be tied to
----@param lang The language of the parser
----@param opts Options to pass to the created language tree
+---@param bufnr string Buffer the parser will be tied to (0 for current buffer)
+---@param lang string Language of the parser
+---@param opts table|nil Options to pass to the created language tree
+---
+---@returns table Created parser object
function M._create_parser(bufnr, lang, opts)
language.require_language(lang)
if bufnr == 0 then
@@ -79,11 +81,11 @@ end
--- If needed this will create the parser.
--- Unconditionally attach the provided callback
---
----@param bufnr The buffer the parser should be tied to
----@param lang The filetype of this parser
----@param opts Options object to pass to the created language tree
+---@param bufnr number|nil Buffer the parser should be tied to: (default current buffer)
+---@param lang string |nil Filetype of this parser (default: buffer filetype)
+---@param opts table|nil Options to pass to the created language tree
---
----@returns The parser
+---@returns table Parser object
function M.get_parser(bufnr, lang, opts)
opts = opts or {}
@@ -120,8 +122,8 @@ end
--- Determines whether a node is the ancestor of another
---
----@param dest table the possible ancestor
----@param source table the possible descendant node
+---@param dest table Possible ancestor
+---@param source table Possible descendant node
---
---@returns (boolean) True if dest is an ancestor of source
function M.is_ancestor(dest, source)
@@ -156,9 +158,11 @@ end
---Determines whether (line, col) position is in node range
---
----@param node Node defining the range
----@param line A line (0-based)
----@param col A column (0-based)
+---@param node table Node defining the range
+---@param line number Line (0-based)
+---@param col number Column (0-based)
+---
+---@returns (boolean) True if the position is in node range
function M.is_in_node_range(node, line, col)
local start_line, start_col, end_line, end_col = M.get_node_range(node)
if line >= start_line and line <= end_line then
@@ -177,8 +181,8 @@ function M.is_in_node_range(node, line, col)
end
---Determines if a node contains a range
----@param node table The node
----@param range table The range
+---@param node table
+---@param range table
---
---@returns (boolean) True if the node contains the range
function M.node_contains(node, range)
@@ -190,9 +194,9 @@ function M.node_contains(node, range)
end
---Gets a list of captures for a given cursor position
----@param bufnr number The buffer number
----@param row number The position row
----@param col number The position column
+---@param bufnr number Buffer number (0 for current buffer)
+---@param row number Position row
+---@param col number Position column
---
---@returns (table) A table of captures
function M.get_captures_at_position(bufnr, row, col)
@@ -241,4 +245,52 @@ function M.get_captures_at_position(bufnr, row, col)
return matches
end
+--- Start treesitter highlighting for a buffer
+---
+--- Can be used in an ftplugin or FileType autocommand
+---
+--- Note: By default, disables regex syntax highlighting, which may be required for some plugins.
+--- In this case, add `{ syntax = true }`.
+---
+--- Example:
+---
+--- <pre>
+--- vim.api.nvim_create_autocmd( 'FileType', { pattern = 'tex',
+--- callback = function(args)
+--- vim.treesitter.start(args.buf, 'latex', { syntax = true })
+--- end
+--- })
+--- </pre>
+---
+---@param bufnr number|nil Buffer to be highlighted (default: current buffer)
+---@param lang string|nil Language of the parser (default: buffer filetype)
+---@param opts table|nil Optional keyword arguments:
+--- - `syntax` boolean Run regex syntax highlighting (default false)
+function M.start(bufnr, lang, opts)
+ bufnr = bufnr or a.nvim_get_current_buf()
+
+ local parser = M.get_parser(bufnr, lang)
+
+ M.highlighter.new(parser)
+
+ vim.b[bufnr].ts_highlight = true
+
+ if opts and opts.syntax then
+ vim.bo[bufnr].syntax = 'on'
+ end
+end
+
+---Stop treesitter highlighting for a buffer
+---
+---@param bufnr number|nil Buffer to stop highlighting (default: current buffer)
+function M.stop(bufnr)
+ bufnr = bufnr or a.nvim_get_current_buf()
+
+ if M.highlighter.active[bufnr] then
+ M.highlighter.active[bufnr]:destroy()
+ end
+
+ vim.bo[bufnr].syntax = 'on'
+end
+
return M
diff --git a/runtime/queries/c/injections.scm b/runtime/queries/c/injections.scm
new file mode 100644
index 0000000000..7e9e73449d
--- /dev/null
+++ b/runtime/queries/c/injections.scm
@@ -0,0 +1,3 @@
+(preproc_arg) @c
+
+; (comment) @comment
diff --git a/runtime/queries/lua/highlights.scm b/runtime/queries/lua/highlights.scm
new file mode 100644
index 0000000000..92baba0f39
--- /dev/null
+++ b/runtime/queries/lua/highlights.scm
@@ -0,0 +1,192 @@
+;; Keywords
+
+"return" @keyword.return
+
+[
+ "goto"
+ "in"
+ "local"
+] @keyword
+
+(label_statement) @label
+
+(break_statement) @keyword
+
+(do_statement
+[
+ "do"
+ "end"
+] @keyword)
+
+(while_statement
+[
+ "while"
+ "do"
+ "end"
+] @repeat)
+
+(repeat_statement
+[
+ "repeat"
+ "until"
+] @repeat)
+
+(if_statement
+[
+ "if"
+ "elseif"
+ "else"
+ "then"
+ "end"
+] @conditional)
+
+(elseif_statement
+[
+ "elseif"
+ "then"
+ "end"
+] @conditional)
+
+(else_statement
+[
+ "else"
+ "end"
+] @conditional)
+
+(for_statement
+[
+ "for"
+ "do"
+ "end"
+] @repeat)
+
+(function_declaration
+[
+ "function"
+ "end"
+] @keyword.function)
+
+(function_definition
+[
+ "function"
+ "end"
+] @keyword.function)
+
+;; Operators
+
+[
+ "and"
+ "not"
+ "or"
+] @keyword.operator
+
+[
+ "+"
+ "-"
+ "*"
+ "/"
+ "%"
+ "^"
+ "#"
+ "=="
+ "~="
+ "<="
+ ">="
+ "<"
+ ">"
+ "="
+ "&"
+ "~"
+ "|"
+ "<<"
+ ">>"
+ "//"
+ ".."
+] @operator
+
+;; Punctuations
+
+[
+ ";"
+ ":"
+ ","
+ "."
+] @punctuation.delimiter
+
+;; Brackets
+
+[
+ "("
+ ")"
+ "["
+ "]"
+ "{"
+ "}"
+] @punctuation.bracket
+
+;; Variables
+
+(identifier) @variable
+
+((identifier) @variable.builtin
+ (#eq? @variable.builtin "self"))
+
+;; Constants
+
+((identifier) @constant
+ (#lua-match? @constant "^[A-Z][A-Z_0-9]*$"))
+
+(vararg_expression) @constant
+
+(nil) @constant.builtin
+
+[
+ (false)
+ (true)
+] @boolean
+
+;; Tables
+
+(field name: (identifier) @field)
+
+(dot_index_expression field: (identifier) @field)
+
+(table_constructor
+[
+ "{"
+ "}"
+] @constructor)
+
+;; Functions
+
+(parameters (identifier) @parameter)
+
+(function_call name: (identifier) @function.call)
+(function_declaration name: (identifier) @function)
+
+(function_call name: (dot_index_expression field: (identifier) @function.call))
+(function_declaration name: (dot_index_expression field: (identifier) @function))
+
+(method_index_expression method: (identifier) @method)
+
+(function_call
+ (identifier) @function.builtin
+ (#any-of? @function.builtin
+ ;; built-in functions in Lua 5.1
+ "assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
+ "load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
+ "rawequal" "rawget" "rawset" "require" "select" "setfenv" "setmetatable"
+ "tonumber" "tostring" "type" "unpack" "xpcall"))
+
+;; Others
+
+(comment) @comment
+
+(hash_bang_line) @comment
+
+(number) @number
+
+(string) @string
+
+;; Error
+(ERROR) @error
diff --git a/runtime/queries/lua/injections.scm b/runtime/queries/lua/injections.scm
new file mode 100644
index 0000000000..0e67329139
--- /dev/null
+++ b/runtime/queries/lua/injections.scm
@@ -0,0 +1,22 @@
+((function_call
+ name: [
+ (identifier) @_cdef_identifier
+ (_ _ (identifier) @_cdef_identifier)
+ ]
+ arguments: (arguments (string content: _ @c)))
+ (#eq? @_cdef_identifier "cdef"))
+
+((function_call
+ name: (_) @_vimcmd_identifier
+ arguments: (arguments (string content: _ @vim)))
+ (#any-of? @_vimcmd_identifier "vim.cmd" "vim.api.nvim_command" "vim.api.nvim_exec" "vim.api.nvim_cmd"))
+
+; ((function_call
+; name: (_) @_vimcmd_identifier
+; arguments: (arguments (string content: _ @query) .))
+; (#eq? @_vimcmd_identifier "vim.treesitter.query.set_query"))
+
+; ;; highlight string as query if starts with `;; query`
+; ((string ("string_content") @query) (#lua-match? @query "^%s*;+%s?query"))
+
+; (comment) @comment
diff --git a/runtime/queries/vim/highlights.scm b/runtime/queries/vim/highlights.scm
new file mode 100644
index 0000000000..c02e226b66
--- /dev/null
+++ b/runtime/queries/vim/highlights.scm
@@ -0,0 +1,245 @@
+(identifier) @variable
+((identifier) @constant
+ (#lua-match? @constant "^[A-Z][A-Z_0-9]*$"))
+
+;; Keywords
+
+[
+ "if"
+ "else"
+ "elseif"
+ "endif"
+] @conditional
+
+[
+ "try"
+ "catch"
+ "finally"
+ "endtry"
+ "throw"
+] @exception
+
+[
+ "for"
+ "endfor"
+ "in"
+ "while"
+ "endwhile"
+ "break"
+ "continue"
+] @repeat
+
+[
+ "function"
+ "endfunction"
+] @keyword.function
+
+;; Function related
+(function_declaration name: (_) @function)
+(call_expression function: (identifier) @function)
+(parameters (identifier) @parameter)
+(default_parameter (identifier) @parameter)
+
+[ (bang) (spread) (at) ] @punctuation.special
+
+[ (no_option) (inv_option) (default_option) (option_name) ] @variable.builtin
+[
+ (scope)
+ "a:"
+ "$"
+] @namespace
+
+;; Commands and user defined commands
+
+[
+ "let"
+ "unlet"
+ "const"
+ "call"
+ "execute"
+ "normal"
+ "set"
+ "setlocal"
+ "silent"
+ "echo"
+ "echomsg"
+ "autocmd"
+ "augroup"
+ "return"
+ "syntax"
+ "lua"
+ "ruby"
+ "perl"
+ "python"
+ "highlight"
+ "command"
+ "delcommand"
+ "comclear"
+ "colorscheme"
+ "startinsert"
+ "stopinsert"
+ "global"
+ "runtime"
+ "wincmd"
+ "cnext"
+ "cprevious"
+ "cNext"
+ "vertical"
+ "leftabove"
+ "aboveleft"
+ "rightbelow"
+ "belowright"
+ "topleft"
+ "botright"
+ (unknown_command_name)
+] @keyword
+(map_statement cmd: _ @keyword)
+(command_name) @function.macro
+
+;; Syntax command
+
+(syntax_statement (keyword) @string)
+(syntax_statement [
+ "enable"
+ "on"
+ "off"
+ "reset"
+ "case"
+ "spell"
+ "foldlevel"
+ "iskeyword"
+ "keyword"
+ "match"
+ "cluster"
+ "region"
+] @keyword)
+
+(syntax_argument name: _ @keyword)
+
+[
+ "<buffer>"
+ "<nowait>"
+ "<silent>"
+ "<script>"
+ "<expr>"
+ "<unique>"
+] @constant.builtin
+
+(hl_attribute
+ key: _ @property
+ val: _ @constant)
+
+(hl_group) @variable
+(augroup_name) @namespace
+
+(au_event) @constant
+(normal_statement (commands) @constant)
+
+;; Highlight command
+
+(highlight_statement [
+ "default"
+ "link"
+ "clear"
+] @keyword)
+
+;; Command command
+
+(command_attribute
+ name: _ @property
+ val: (behavior
+ name: _ @constant
+ val: (identifier)? @function)?)
+
+;; Runtime command
+
+(runtime_statement (where) @keyword.operator)
+
+;; Colorscheme command
+
+(colorscheme_statement (name) @string)
+
+;; Literals
+
+(string_literal) @string
+(integer_literal) @number
+(float_literal) @float
+(comment) @comment
+(pattern) @string.special
+(pattern_multi) @string.regex
+(filename) @string
+(heredoc (body) @string)
+((heredoc (parameter) @keyword))
+((scoped_identifier
+ (scope) @_scope . (identifier) @boolean)
+ (#eq? @_scope "v:")
+ (#any-of? @boolean "true" "false"))
+
+;; Operators
+
+[
+ "||"
+ "&&"
+ "&"
+ "+"
+ "-"
+ "*"
+ "/"
+ "%"
+ ".."
+ "is"
+ "isnot"
+ "=="
+ "!="
+ ">"
+ ">="
+ "<"
+ "<="
+ "=~"
+ "!~"
+ "="
+ "+="
+ "-="
+ "*="
+ "/="
+ "%="
+ ".="
+ "..="
+] @operator
+
+; Some characters have different meanings based on the context
+(unary_operation "!" @operator)
+(binary_operation "." @operator)
+
+;; Punctuation
+
+[
+ "("
+ ")"
+ "{"
+ "}"
+ "["
+ "]"
+] @punctuation.bracket
+
+(field_expression "." @punctuation.delimiter)
+
+[
+ ","
+ ":"
+] @punctuation.delimiter
+
+(ternary_expression ["?" ":"] @conditional)
+
+; Options
+((set_value) @number
+ (#match? @number "^[0-9]+(\.[0-9]+)?$"))
+
+((set_item
+ option: (option_name) @_option
+ value: (set_value) @function)
+ (#any-of? @_option
+ "tagfunc" "tfu"
+ "completefunc" "cfu"
+ "omnifunc" "ofu"
+ "operatorfunc" "opfunc"))
diff --git a/runtime/queries/vim/injections.scm b/runtime/queries/vim/injections.scm
new file mode 100644
index 0000000000..e2dea8fe75
--- /dev/null
+++ b/runtime/queries/vim/injections.scm
@@ -0,0 +1,26 @@
+(lua_statement (script (body) @lua))
+(lua_statement (chunk) @lua)
+; (ruby_statement (script (body) @ruby))
+; (ruby_statement (chunk) @ruby)
+; (python_statement (script (body) @python))
+; (python_statement (chunk) @python)
+;; (perl_statement (script (body) @perl))
+;; (perl_statement (chunk) @perl)
+
+; (autocmd_statement (pattern) @regex)
+
+((set_item
+ option: (option_name) @_option
+ value: (set_value) @vim)
+ (#any-of? @_option
+ "includeexpr" "inex"
+ "printexpr" "pexpr"
+ "formatexpr" "fex"
+ "indentexpr" "inde"
+ "foldtext" "fdt"
+ "foldexpr" "fde"
+ "diffexpr" "dex"
+ "patchexpr" "pex"
+ "charconvert" "ccv"))
+
+; (comment) @comment
diff --git a/runtime/syntax/syntax.vim b/runtime/syntax/syntax.vim
index 55a2ee6d71..5ec99c7e05 100644
--- a/runtime/syntax/syntax.vim
+++ b/runtime/syntax/syntax.vim
@@ -27,13 +27,13 @@ else
endif
" Set up the connection between FileType and Syntax autocommands.
-" This makes the syntax automatically set when the file type is detected.
+" This makes the syntax automatically set when the file type is detected
+" unless treesitter highlighting is enabled.
" Avoid an error when 'verbose' is set and <amatch> expansion fails.
augroup syntaxset
- au! FileType * 0verbose exe "set syntax=" . expand("<amatch>")
+ au! FileType * if !exists('b:ts_highlight') | 0verbose exe "set syntax=" . expand("<amatch>") | endif
augroup END
-
" Execute the syntax autocommands for the each buffer.
" If the filetype wasn't detected yet, do that now.
" Always do the syntaxset autocommands, for buffers where the 'filetype'
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 5c07784db3..412fe3509d 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -186,7 +186,6 @@ static const char *highlight_init_both[] = {
"default link DiagnosticSignInfo DiagnosticInfo",
"default link DiagnosticSignHint DiagnosticHint",
- "default link @error Error",
"default link @text.underline Underlined",
"default link @todo Todo",
"default link @debug Debug",
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 93fb0f245e..d672037a1e 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -755,16 +755,6 @@ function module.pending_win32(pending_fn)
end
end
-function module.pending_c_parser(pending_fn)
- local status, _ = unpack(module.exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]]))
- if not status then
- pending_fn 'no C parser, skipping'
- return true
- end
- module.exec_lua [[vim._ts_remove_language 'c']]
- return false
-end
-
-- Calls pending() and returns `true` if the system is too slow to
-- run fragile or expensive tests. Else returns `false`.
function module.skip_fragile(pending_fn, cond)
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 4b0bd1eb50..d557b2c012 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -5,7 +5,6 @@ local clear = helpers.clear
local insert = helpers.insert
local exec_lua = helpers.exec_lua
local feed = helpers.feed
-local pending_c_parser = helpers.pending_c_parser
local command = helpers.command
local meths = helpers.meths
local eq = helpers.eq
@@ -107,12 +106,11 @@ describe('treesitter highlighting', function()
}
exec_lua([[ hl_query = ... ]], hl_query)
+ command [[ hi link @error ErrorMsg ]]
command [[ hi link @warning WarningMsg ]]
end)
it('is updated with edits', function()
- if pending_c_parser(pending) then return end
-
insert(hl_text)
screen:expect{grid=[[
/// Schedule Lua callback on main loop's event queue |
@@ -276,8 +274,6 @@ describe('treesitter highlighting', function()
end)
it('is updated with :sort', function()
- if pending_c_parser(pending) then return end
-
insert(test_text)
exec_lua [[
local parser = vim.treesitter.get_parser(0, "c")
@@ -351,8 +347,6 @@ describe('treesitter highlighting', function()
end)
it("supports with custom parser", function()
- if pending_c_parser(pending) then return end
-
screen:set_default_attr_ids {
[1] = {bold = true, foreground = Screen.colors.SeaGreen4};
}
@@ -417,8 +411,6 @@ describe('treesitter highlighting', function()
end)
it("supports injected languages", function()
- if pending_c_parser(pending) then return end
-
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
@@ -479,8 +471,6 @@ describe('treesitter highlighting', function()
end)
it("supports overriding queries, like ", function()
- if pending_c_parser(pending) then return end
-
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
@@ -520,8 +510,6 @@ describe('treesitter highlighting', function()
end)
it("supports highlighting with custom highlight groups", function()
- if pending_c_parser(pending) then return end
-
insert(hl_text)
exec_lua [[
@@ -577,8 +565,6 @@ describe('treesitter highlighting', function()
end)
it("supports highlighting with priority", function()
- if pending_c_parser(pending) then return end
-
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
@@ -594,9 +580,9 @@ describe('treesitter highlighting', function()
-- expect everything to have Error highlight
screen:expect{grid=[[
{12:int}{8: x = INT_MAX;} |
- {8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}|
- {8:#define foo void main() { \} |
- {8: return 42; \} |
+ {8:#define READ_STRING(x, y) (}{12:char_u}{8: *)read_string((x), (}{12:size_t}{8:)(y))}|
+ {8:#define foo }{12:void}{8: main() { \} |
+ {8: }{12:return}{8: 42; \} |
{8: }} |
^ |
{1:~ }|
@@ -625,8 +611,6 @@ describe('treesitter highlighting', function()
end)
it("allows to use captures with dots (don't use fallback when specialization of foo exists)", function()
- if pending_c_parser(pending) then return end
-
insert([[
char* x = "Will somebody ever read this?";
]])
@@ -708,7 +692,6 @@ describe('treesitter highlighting', function()
end)
it("supports conceal attribute", function()
- if pending_c_parser(pending) then return end
insert(hl_text)
-- conceal can be empty or a single cchar.
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index 8e9941d797..ed84dedb5a 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -6,7 +6,6 @@ local command = helpers.command
local exec_lua = helpers.exec_lua
local pcall_err = helpers.pcall_err
local matches = helpers.matches
-local pending_c_parser = helpers.pending_c_parser
local insert = helpers.insert
before_each(clear)
@@ -28,15 +27,11 @@ describe('treesitter language API', function()
eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')"))
- if not pending_c_parser(pending) then
- matches("Error executing lua: Failed to load parser: uv_dlsym: .+",
- pcall_err(exec_lua, 'vim.treesitter.require_language("c", nil, false, "borklang")'))
- end
+ matches("Error executing lua: Failed to load parser: uv_dlsym: .+",
+ pcall_err(exec_lua, 'vim.treesitter.require_language("c", nil, false, "borklang")'))
end)
it('inspects language', function()
- if pending_c_parser(pending) then return end
-
local keys, fields, symbols = unpack(exec_lua([[
local lang = vim.treesitter.inspect_language('c')
local keys, symbols = {}, {}
@@ -76,7 +71,6 @@ describe('treesitter language API', function()
end)
it('checks if vim.treesitter.get_parser tries to create a new parser on filetype change', function ()
- if pending_c_parser(pending) then return end
command("set filetype=c")
-- Should not throw an error when filetype is c
eq('c', exec_lua("return vim.treesitter.get_parser(0):lang()"))
@@ -87,7 +81,6 @@ describe('treesitter language API', function()
end)
it('retrieve the tree given a range', function ()
- if pending_c_parser(pending) then return end
insert([[
int main() {
int x = 3;
@@ -102,7 +95,6 @@ describe('treesitter language API', function()
end)
it('retrieve the node given a range', function ()
- if pending_c_parser(pending) then return end
insert([[
int main() {
int x = 3;
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index 87ce1b973c..a82dce47b7 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -4,7 +4,6 @@ local clear = helpers.clear
local eq = helpers.eq
local exec_lua = helpers.exec_lua
local insert = helpers.insert
-local pending_c_parser = helpers.pending_c_parser
before_each(clear)
@@ -15,10 +14,6 @@ end
describe('treesitter node API', function()
clear()
- if pending_c_parser(pending) then
- return
- end
-
it('can move between siblings', function()
insert([[
int main(int x, int y, int z) {
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 7f3b0e770a..ccbd55df0e 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -5,13 +5,11 @@ local eq = helpers.eq
local insert = helpers.insert
local exec_lua = helpers.exec_lua
local feed = helpers.feed
-local pending_c_parser = helpers.pending_c_parser
before_each(clear)
describe('treesitter parser API', function()
clear()
- if pending_c_parser(pending) then return end
it('parses buffer', function()
if helpers.pending_win32(pending) then return end
@@ -249,7 +247,6 @@ void ui_refresh(void)
end)
it('supports getting text of multiline node', function()
- if pending_c_parser(pending) then return end
insert(test_text)
local res = exec_lua([[
local parser = vim.treesitter.get_parser(0, "c")
diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua
index 4f4c18a748..7f5a864c3d 100644
--- a/test/functional/treesitter/utils_spec.lua
+++ b/test/functional/treesitter/utils_spec.lua
@@ -4,7 +4,6 @@ local clear = helpers.clear
local insert = helpers.insert
local eq = helpers.eq
local exec_lua = helpers.exec_lua
-local pending_c_parser = helpers.pending_c_parser
before_each(clear)
@@ -12,7 +11,6 @@ describe('treesitter utils', function()
before_each(clear)
it('can find an ancestor', function()
- if pending_c_parser(pending) then return end
insert([[
int main() {