diff options
-rw-r--r-- | ci/build.ps1 | 16 | ||||
-rwxr-xr-x | ci/install.sh | 24 | ||||
-rwxr-xr-x | ci/run_tests.sh | 2 | ||||
-rw-r--r-- | config/pathdef.c.in | 1 | ||||
-rw-r--r-- | runtime/doc/lua.txt | 8 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter.lua | 31 | ||||
-rwxr-xr-x | src/clint.py | 6 | ||||
-rw-r--r-- | src/nvim/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 34 | ||||
-rw-r--r-- | src/nvim/globals.h | 1 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 5 | ||||
-rw-r--r-- | src/nvim/lua/treesitter.c | 9 | ||||
-rw-r--r-- | src/nvim/option.c | 28 | ||||
-rw-r--r-- | src/nvim/os/env.c | 21 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 24 | ||||
-rw-r--r-- | test/functional/lua/treesitter_spec.lua | 107 | ||||
-rw-r--r-- | test/functional/options/defaults_spec.lua | 33 | ||||
-rw-r--r-- | third-party/CMakeLists.txt | 8 | ||||
-rw-r--r-- | third-party/cmake/BuildTreesitterParsers.cmake | 28 | ||||
-rw-r--r-- | third-party/cmake/TreesitterParserCMakeLists.txt | 19 |
20 files changed, 294 insertions, 116 deletions
diff --git a/ci/build.ps1 b/ci/build.ps1 index a7a456f67a..01cf20874e 100644 --- a/ci/build.ps1 +++ b/ci/build.ps1 @@ -123,22 +123,6 @@ if (-not $NoTests) { npm.cmd install -g neovim Get-Command -CommandType Application neovim-node-host.cmd npm.cmd link neovim - - - $env:TREE_SITTER_DIR = $env:USERPROFILE + "\tree-sitter-build" - mkdir "$env:TREE_SITTER_DIR\bin" - - $xbits = if ($bits -eq '32') {'x86'} else {'x64'} - Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/tree-sitter/tree-sitter/releases/download/0.15.9/tree-sitter-windows-$xbits.gz" -OutFile tree-sitter.exe.gz - C:\msys64\usr\bin\gzip -d tree-sitter.exe.gz - - Invoke-WebRequest -UseBasicParsing -Uri "https://codeload.github.com/tree-sitter/tree-sitter-c/zip/v0.15.2" -OutFile tree_sitter_c.zip - Expand-Archive .\tree_sitter_c.zip -DestinationPath . - cd tree-sitter-c-0.15.2 - ..\tree-sitter.exe test - if (-Not (Test-Path -PathType Leaf "$env:TREE_SITTER_DIR\bin\c.dll")) { - exit 1 - } } if ($compiler -eq 'MSVC') { diff --git a/ci/install.sh b/ci/install.sh index b3ec9e7f65..769f00c5ba 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -27,29 +27,5 @@ nvm use 10 npm install -g neovim npm link neovim -echo "Install tree-sitter npm package" - -# FIXME -# https://github.com/tree-sitter/tree-sitter/commit/e14e285a1087264a8c74a7c62fcaecc49db9d904 -# If queries added to tree-sitter-c, we can use latest tree-sitter-cli -npm install -g tree-sitter-cli@v0.15.9 - -echo "Install tree-sitter c parser" -curl "https://codeload.github.com/tree-sitter/tree-sitter-c/tar.gz/v0.15.2" -o tree_sitter_c.tar.gz -tar xf tree_sitter_c.tar.gz -cd tree-sitter-c-0.15.2 -export TREE_SITTER_DIR=$HOME/tree-sitter-build/ -mkdir -p "$TREE_SITTER_DIR/bin" - -if [[ "$BUILD_32BIT" != "ON" ]]; then - # builds c parser in $HOME/tree-sitter-build/bin/c.(so|dylib) - tree-sitter test -else - # no tree-sitter binary for 32bit linux, so fake it (no tree-sitter unit tests) - cd src/ - gcc -m32 -o "$TREE_SITTER_DIR/bin/c.so" -shared parser.c -I. -fi -test -f "$TREE_SITTER_DIR/bin/c.so" - sudo cpanm -n Neovim::Ext || cat "$HOME/.cpanm/build.log" perl -W -e 'use Neovim::Ext; print $Neovim::Ext::VERSION' diff --git a/ci/run_tests.sh b/ci/run_tests.sh index 97f380b7b9..d91ac5589e 100755 --- a/ci/run_tests.sh +++ b/ci/run_tests.sh @@ -19,7 +19,7 @@ exit_suite --continue source ~/.nvm/nvm.sh nvm use 10 -export TREE_SITTER_DIR=$HOME/tree-sitter-build/ + enter_suite tests diff --git a/config/pathdef.c.in b/config/pathdef.c.in index 41950f5ac5..6a8a2b205a 100644 --- a/config/pathdef.c.in +++ b/config/pathdef.c.in @@ -3,5 +3,6 @@ #include "${PROJECT_SOURCE_DIR}/src/nvim/vim.h" char *default_vim_dir = "${CMAKE_INSTALL_FULL_DATAROOTDIR}/nvim"; char *default_vimruntime_dir = ""; +char *default_lib_dir = "${CMAKE_INSTALL_FULL_LIBDIR}/nvim"; char_u *compiled_user = (char_u *)"${USERNAME}"; char_u *compiled_sys = (char_u *)"${HOSTNAME}"; diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index af1f4a8c1f..c113a70027 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -494,10 +494,12 @@ VIM.TREESITTER *lua-treesitter* Nvim integrates the tree-sitter library for incremental parsing of buffers. Currently Nvim does not provide the tree-sitter parsers, instead these must -be built separately, for instance using the tree-sitter utility. -The parser is loaded into nvim using > +be built separately, for instance using the tree-sitter utility. The only +exception is a C parser being included in official builds for testing +purposes. Parsers are searched for as `parser/{lang}.*` in any 'runtimepath' +directory. A parser can also be loaded manually using a full path: > - vim.treesitter.add_language("/path/to/c_parser.so", "c") + vim.treesitter.require_language("python", "/path/to/python.so") <Create a parser for a buffer and a given language (if another plugin uses the same buffer/language combination, it will be safely reused). Use > diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index aa8b8fcdd1..0d0e22adb3 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -31,8 +31,6 @@ function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_ end local M = { - add_language=vim._ts_add_language, - inspect_language=vim._ts_inspect_language, parse_query = vim._ts_parse_query, } @@ -45,12 +43,34 @@ setmetatable(M, { end }) -function M.create_parser(bufnr, ft, id) +function M.require_language(lang, path) + if vim._ts_has_language(lang) then + return true + end + if path == nil then + local fname = 'parser/' .. lang .. '.*' + local paths = a.nvim_get_runtime_file(fname, false) + if #paths == 0 then + -- TODO(bfredl): help tag? + error("no parser for '"..lang.."' language") + end + path = paths[1] + end + vim._ts_add_language(path, lang) +end + +function M.inspect_language(lang) + M.require_language(lang) + return vim._ts_inspect_language(lang) +end + +function M.create_parser(bufnr, lang, id) + M.require_language(lang) if bufnr == 0 then bufnr = a.nvim_get_current_buf() end - local self = setmetatable({bufnr=bufnr, lang=ft, valid=false}, Parser) - self._parser = vim._create_ts_parser(ft) + local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser) + self._parser = vim._create_ts_parser(lang) self.change_cbs = {} self:parse() -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is @@ -94,6 +114,7 @@ local Query = {} Query.__index = Query function M.parse_query(lang, query) + M.require_language(lang) local self = setmetatable({}, Query) self.query = vim._ts_parse_query(lang, query) self.info = self.query:inspect() diff --git a/src/clint.py b/src/clint.py index 675b67ccef..12bada6aac 100755 --- a/src/clint.py +++ b/src/clint.py @@ -270,6 +270,8 @@ _line_length = 80 # This is set by --extensions flag. _valid_extensions = set(['c', 'h']) +_RE_COMMENTLINE = re.compile(r'^\s*//') + def ParseNolintSuppressions(filename, raw_line, linenum, error): """Updates the global list of error-suppressions. @@ -1358,7 +1360,9 @@ def CheckForOldStyleComments(filename, line, linenum, error): linenum: The number of the line to check. error: The function to call with any errors found. """ - if line.find('/*') >= 0 and line[-1] != '\\': + # hack: allow /* inside comment line. Could be extended to allow them inside + # any // comment. + if line.find('/*') >= 0 and line[-1] != '\\' and not _RE_COMMENTLINE.match(line): error(filename, linenum, 'readability/old_style_comment', 5, '/*-style comment found, it should be replaced with //-style. ' '/*-style comments are only allowed inside macros. ' diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 089dd537e9..29427c7d08 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -546,6 +546,11 @@ else() endif() set_target_properties(nvim_runtime_deps PROPERTIES FOLDER deps) +file(COPY ${DEPS_PREFIX}/lib/nvim/parser DESTINATION ${PROJECT_BINARY_DIR}/lib/nvim/) +install(DIRECTORY ${PROJECT_BINARY_DIR}/lib/nvim/ + DESTINATION ${CMAKE_INSTALL_LIBDIR}/nvim/ + USE_SOURCE_PERMISSIONS) + add_library( libnvim STATIC diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9c58ce853b..30fc48fea5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -703,6 +703,40 @@ ArrayOf(String) nvim_list_runtime_paths(void) return rv; } +/// Find files in runtime directories +/// +/// 'name' can contain wildcards. For example +/// nvim_get_runtime_file("colors/*.vim", true) will return all color +/// scheme files. +/// +/// It is not an error to not find any files. An empty array is returned then. +/// +/// @param name pattern of files to search for +/// @param all whether to return all matches or only the first +/// @return list of absolute paths to the found files +ArrayOf(String) nvim_get_runtime_file(String name, Boolean all) + FUNC_API_SINCE(7) +{ + Array rv = ARRAY_DICT_INIT; + if (!name.data) { + return rv; + } + int flags = DIP_START | (all ? DIP_ALL : 0); + do_in_runtimepath((char_u *)name.data, flags, find_runtime_cb, &rv); + return rv; +} + +static void find_runtime_cb(char_u *fname, void *cookie) +{ + Array *rv = (Array *)cookie; + ADD(*rv, STRING_OBJ(cstr_to_string((char *)fname))); +} + +String nvim__get_lib_dir(void) +{ + return cstr_as_string(get_lib_dir()); +} + /// Changes the global working directory. /// /// @param dir Directory path diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 4741778c14..0d419d202c 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -833,6 +833,7 @@ enum { #ifdef HAVE_PATHDEF extern char *default_vim_dir; extern char *default_vimruntime_dir; +extern char *default_lib_dir; extern char_u *compiled_user; extern char_u *compiled_sys; #endif diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 242d4e18d1..9a8347cf19 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1025,9 +1025,12 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, create_tslua_parser); lua_setfield(lstate, -2, "_create_ts_parser"); - lua_pushcfunction(lstate, tslua_register_lang); + lua_pushcfunction(lstate, tslua_add_language); lua_setfield(lstate, -2, "_ts_add_language"); + lua_pushcfunction(lstate, tslua_has_language); + lua_setfield(lstate, -2, "_ts_has_language"); + lua_pushcfunction(lstate, tslua_inspect_lang); lua_setfield(lstate, -2, "_ts_inspect_language"); diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 874fabd89f..a420f79ffd 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -119,7 +119,14 @@ void tslua_init(lua_State *L) build_meta(L, "treesitter_querycursor", querycursor_meta); } -int tslua_register_lang(lua_State *L) +int tslua_has_language(lua_State *L) +{ + const char *lang_name = luaL_checkstring(L, 1); + lua_pushboolean(L, pmap_has(cstr_t)(langs, lang_name)); + return 1; +} + +int tslua_add_language(lua_State *L) { if (lua_gettop(L) < 2 || !lua_isstring(L, 1) || !lua_isstring(L, 2)) { return luaL_error(L, "string expected"); diff --git a/src/nvim/option.c b/src/nvim/option.c index 37c0928d86..15ff8414ce 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -498,6 +498,24 @@ static inline char *add_dir(char *dest, const char *const dir, return dest; } +char *get_lib_dir(void) +{ + // TODO(bfredl): too fragile? Ideally default_lib_dir would be made empty + // in an appimage build + if (strlen(default_lib_dir) != 0 + && os_isdir((const char_u *)default_lib_dir)) { + return xstrdup(default_lib_dir); + } + + // Find library path relative to the nvim binary: ../lib/nvim/ + char exe_name[MAXPATHL]; + vim_get_prefix_from_exepath(exe_name); + if (append_path(exe_name, "lib" _PATHSEPSTR "nvim", MAXPATHL) == OK) { + return xstrdup(exe_name); + } + return NULL; +} + /// Sets &runtimepath to default value. /// /// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing @@ -508,6 +526,7 @@ static void set_runtimepath_default(void) char *const data_home = stdpaths_get_xdg_var(kXDGDataHome); char *const config_home = stdpaths_get_xdg_var(kXDGConfigHome); char *const vimruntime = vim_getenv("VIMRUNTIME"); + char *const libdir = get_lib_dir(); char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs); char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs); #define SITE_SIZE (sizeof("site") - 1) @@ -515,6 +534,7 @@ static void set_runtimepath_default(void) size_t data_len = 0; size_t config_len = 0; size_t vimruntime_len = 0; + size_t libdir_len = 0; if (data_home != NULL) { data_len = strlen(data_home); if (data_len != 0) { @@ -544,6 +564,12 @@ static void set_runtimepath_default(void) rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1; } } + if (libdir != NULL) { + libdir_len = strlen(libdir); + if (libdir_len != 0) { + rtp_size += libdir_len + memcnt(libdir, ',', libdir_len) + 1; + } + } rtp_size += compute_double_colon_len(data_dirs, NVIM_SIZE + 1 + SITE_SIZE + 1, AFTER_SIZE + 1); rtp_size += compute_double_colon_len(config_dirs, NVIM_SIZE + 1, @@ -562,6 +588,7 @@ static void set_runtimepath_default(void) true); rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, kXDGNone, NULL, 0, NULL, 0); + rtp_cur = add_dir(rtp_cur, libdir, libdir_len, kXDGNone, NULL, 0, NULL, 0); rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, "after", AFTER_SIZE, false); rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome, @@ -583,6 +610,7 @@ static void set_runtimepath_default(void) xfree(data_home); xfree(config_home); xfree(vimruntime); + xfree(libdir); } #undef NVIM_SIZE diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index ec266796a8..082ad58223 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -847,6 +847,20 @@ const void *vim_env_iter_rev(const char delim, } } + +/// @param[out] exe_name should be at least MAXPATHL in size +void vim_get_prefix_from_exepath(char *exe_name) +{ + // TODO(bfredl): param could have been written as "char exe_name[MAXPATHL]" + // but c_grammar.lua does not recognize it (yet). + xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH), + MAXPATHL * sizeof(*exe_name)); + char *path_end = (char *)path_tail_with_sep((char_u *)exe_name); + *path_end = '\0'; // remove the trailing "nvim.exe" + path_end = (char *)path_tail((char_u *)exe_name); + *path_end = '\0'; // remove the trailing "bin/" +} + /// Vim getenv() wrapper with special handling of $HOME, $VIM, $VIMRUNTIME, /// allowing the user to override the Nvim runtime directory at runtime. /// Result must be freed by the caller. @@ -902,12 +916,7 @@ char *vim_getenv(const char *name) char exe_name[MAXPATHL]; // Find runtime path relative to the nvim binary: ../share/nvim/runtime if (vim_path == NULL) { - xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH), - sizeof(exe_name)); - char *path_end = (char *)path_tail_with_sep((char_u *)exe_name); - *path_end = '\0'; // remove the trailing "nvim.exe" - path_end = (char *)path_tail((char_u *)exe_name); - *path_end = '\0'; // remove the trailing "bin/" + vim_get_prefix_from_exepath(exe_name); if (append_path( exe_name, "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR, diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d901a5e2eb..fb3755cb8e 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -23,6 +23,7 @@ local pcall_err = helpers.pcall_err local format_string = helpers.format_string local intchar2lua = helpers.intchar2lua local mergedicts_copy = helpers.mergedicts_copy +local endswith = helpers.endswith describe('API', function() before_each(clear) @@ -1853,4 +1854,27 @@ describe('API', function() command('silent! call nvim_create_buf(0, 1)') end) end) + + describe('nvim_get_runtime_file', function() + it('works', function() + eq({}, meths.get_runtime_file("bork.borkbork", false)) + eq({}, meths.get_runtime_file("bork.borkbork", true)) + eq(1, #meths.get_runtime_file("autoload/msgpack.vim", false)) + eq(1, #meths.get_runtime_file("autoload/msgpack.vim", true)) + local val = meths.get_runtime_file("autoload/remote/*.vim", true) + eq(2, #val) + local p = helpers.alter_slashes + if endswith(val[1], "define.vim") then + ok(endswith(val[1], p("autoload/remote/define.vim"))) + ok(endswith(val[2], p("autoload/remote/host.vim"))) + else + ok(endswith(val[1], p("autoload/remote/host.vim"))) + ok(endswith(val[2], p("autoload/remote/define.vim"))) + end + val = meths.get_runtime_file("autoload/remote/*.vim", false) + eq(1, #val) + ok(endswith(val[1], p("autoload/remote/define.vim")) + or endswith(val[1], p("autoload/remote/host.vim"))) + end) + end) end) diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 76e9899d34..494d6c84bb 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -6,7 +6,6 @@ local clear = helpers.clear local eq = helpers.eq local insert = helpers.insert local exec_lua = helpers.exec_lua -local iswin = helpers.iswin local feed = helpers.feed local pcall_err = helpers.pcall_err local matches = helpers.matches @@ -16,37 +15,35 @@ before_each(clear) describe('treesitter API', function() -- error tests not requiring a parser library it('handles missing language', function() - eq('Error executing lua: .../treesitter.lua: no such language: borklang', + eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language", pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')")) -- actual message depends on platform - matches('Error executing lua: Failed to load parser: uv_dlopen: .+', - pcall_err(exec_lua, "parser = vim.treesitter.add_language('borkbork.so', 'borklang')")) + matches("Error executing lua: Failed to load parser: uv_dlopen: .+", + pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')")) - eq('Error executing lua: [string "<nvim>"]:1: no such language: borklang', + eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) end) describe('treesitter API with C parser', function() - local ts_path = os.getenv("TREE_SITTER_DIR") - - -- The tests after this requires an actual parser - if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) - return + local function check_parser() + local status, msg = unpack(exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]])) + if not status then + if helpers.isCI() then + error("treesitter C parser not found, required on CI: " .. msg) + else + pending('no C parser, skipping') + end + end + return status end - before_each(function() - local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') - exec_lua([[ - local path = ... - vim.treesitter.add_language(path,'c') - ]], path) - end) - it('parses buffer', function() + if not check_parser() then return end + insert([[ int main() { int x = 3; @@ -138,6 +135,8 @@ void ui_refresh(void) ]] it('support query and iter by capture', function() + if not check_parser() then return end + insert(test_text) local res = exec_lua([[ @@ -167,6 +166,8 @@ void ui_refresh(void) end) it('support query and iter by match', function() + if not check_parser() then return end + insert(test_text) local res = exec_lua([[ @@ -198,6 +199,8 @@ void ui_refresh(void) end) it('supports highlighting', function() + if not check_parser() then return end + local hl_text = [[ /// Schedule Lua callback on main loop's event queue static int nlua_schedule(lua_State *const lstate) @@ -357,41 +360,43 @@ static int nlua_schedule(lua_State *const lstate) end) it('inspects language', function() - local keys, fields, symbols = unpack(exec_lua([[ - local lang = vim.treesitter.inspect_language('c') - local keys, symbols = {}, {} - for k,_ in pairs(lang) do - keys[k] = true - end + if not check_parser() then return end - -- symbols array can have "holes" and is thus not a valid msgpack array - -- but we don't care about the numbers here (checked in the parser test) - for _, v in pairs(lang.symbols) do - table.insert(symbols, v) - end - return {keys, lang.fields, symbols} - ]])) - - eq({fields=true, symbols=true}, keys) + local keys, fields, symbols = unpack(exec_lua([[ + local lang = vim.treesitter.inspect_language('c') + local keys, symbols = {}, {} + for k,_ in pairs(lang) do + keys[k] = true + end - local fset = {} - for _,f in pairs(fields) do - eq("string", type(f)) - fset[f] = true + -- symbols array can have "holes" and is thus not a valid msgpack array + -- but we don't care about the numbers here (checked in the parser test) + for _, v in pairs(lang.symbols) do + table.insert(symbols, v) end - eq(true, fset["directive"]) - eq(true, fset["initializer"]) - - local has_named, has_anonymous - for _,s in pairs(symbols) do - eq("string", type(s[1])) - eq("boolean", type(s[2])) - if s[1] == "for_statement" and s[2] == true then - has_named = true - elseif s[1] == "|=" and s[2] == false then - has_anonymous = true - end + return {keys, lang.fields, symbols} + ]])) + + eq({fields=true, symbols=true}, keys) + + local fset = {} + for _,f in pairs(fields) do + eq("string", type(f)) + fset[f] = true + end + eq(true, fset["directive"]) + eq(true, fset["initializer"]) + + local has_named, has_anonymous + for _,s in pairs(symbols) do + eq("string", type(s[1])) + eq("boolean", type(s[2])) + if s[1] == "for_statement" and s[2] == true then + has_named = true + elseif s[1] == "|=" and s[2] == false then + has_anonymous = true end - eq({true,true}, {has_named,has_anonymous}) + end + eq({true,true}, {has_named,has_anonymous}) end) end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 57e5077989..11ce26410d 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -293,6 +293,14 @@ describe('XDG-based defaults', function() -- TODO(jkeyes): tests below fail on win32 because of path separator. if helpers.pending_win32(pending) then return end + local function vimruntime_and_libdir() + local vimruntime = eval('$VIMRUNTIME') + -- libdir is hard to calculate reliably across various ci platforms + -- local libdir = string.gsub(vimruntime, "share/nvim/runtime$", "lib/nvim") + local libdir = meths._get_lib_dir() + return vimruntime, libdir + end + describe('with too long XDG variables', function() before_each(function() clear({env={ @@ -308,6 +316,8 @@ describe('XDG-based defaults', function() end) it('are correctly set', function() + local vimruntime, libdir = vimruntime_and_libdir() + eq((('/x'):rep(4096) .. '/nvim' .. ',' .. ('/a'):rep(2048) .. '/nvim' .. ',' .. ('/b'):rep(2048) .. '/nvim' @@ -316,7 +326,8 @@ describe('XDG-based defaults', function() .. ',' .. ('/A'):rep(2048) .. '/nvim/site' .. ',' .. ('/B'):rep(2048) .. '/nvim/site' .. (',' .. '/C/nvim/site'):rep(512) - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. (',' .. '/C/nvim/site/after'):rep(512) .. ',' .. ('/B'):rep(2048) .. '/nvim/site/after' .. ',' .. ('/A'):rep(2048) .. '/nvim/site/after' @@ -339,7 +350,8 @@ describe('XDG-based defaults', function() .. ',' .. ('/A'):rep(2048) .. '/nvim/site' .. ',' .. ('/B'):rep(2048) .. '/nvim/site' .. (',' .. '/C/nvim/site'):rep(512) - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. (',' .. '/C/nvim/site/after'):rep(512) .. ',' .. ('/B'):rep(2048) .. '/nvim/site/after' .. ',' .. ('/A'):rep(2048) .. '/nvim/site/after' @@ -368,11 +380,13 @@ describe('XDG-based defaults', function() end) it('are not expanded', function() + local vimruntime, libdir = vimruntime_and_libdir() eq(('$XDG_DATA_HOME/nvim' .. ',$XDG_DATA_DIRS/nvim' .. ',$XDG_CONFIG_HOME/nvim/site' .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',$XDG_CONFIG_DIRS/nvim/site/after' .. ',$XDG_CONFIG_HOME/nvim/site/after' .. ',$XDG_DATA_DIRS/nvim/after' @@ -387,7 +401,8 @@ describe('XDG-based defaults', function() .. ',$XDG_DATA_DIRS/nvim' .. ',$XDG_CONFIG_HOME/nvim/site' .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',$XDG_CONFIG_DIRS/nvim/site/after' .. ',$XDG_CONFIG_HOME/nvim/site/after' .. ',$XDG_DATA_DIRS/nvim/after' @@ -402,7 +417,8 @@ describe('XDG-based defaults', function() .. ',$XDG_DATA_DIRS/nvim' .. ',$XDG_CONFIG_HOME/nvim/site' .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',$XDG_CONFIG_DIRS/nvim/site/after' .. ',$XDG_CONFIG_HOME/nvim/site/after' .. ',$XDG_DATA_DIRS/nvim/after' @@ -426,13 +442,15 @@ describe('XDG-based defaults', function() end) it('are escaped properly', function() + local vimruntime, libdir = vimruntime_and_libdir() eq(('\\, \\, \\,/nvim' .. ',\\,-\\,-\\,/nvim' .. ',-\\,-\\,-/nvim' .. ',\\,=\\,=\\,/nvim/site' .. ',\\,≡\\,≡\\,/nvim/site' .. ',≡\\,≡\\,≡/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',≡\\,≡\\,≡/nvim/site/after' .. ',\\,≡\\,≡\\,/nvim/site/after' .. ',\\,=\\,=\\,/nvim/site/after' @@ -451,7 +469,8 @@ describe('XDG-based defaults', function() .. ',\\,=\\,=\\,/nvim/site' .. ',\\,≡\\,≡\\,/nvim/site' .. ',≡\\,≡\\,≡/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',≡\\,≡\\,≡/nvim/site/after' .. ',\\,≡\\,≡\\,/nvim/site/after' .. ',\\,=\\,=\\,/nvim/site/after' diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 46bc689471..cff063e894 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -42,6 +42,7 @@ option(USE_BUNDLED_LUV "Use the bundled version of luv." ${USE_BUNDLED}) #XXX(tarruda): Lua is only used for debugging the functional test client, no # build it unless explicitly requested option(USE_BUNDLED_LUA "Use the bundled version of lua." OFF) +option(USE_BUNDLED_TS_PARSERS "Use the bundled treesitter parsers." ${USE_BUNDLED}) if(USE_BUNDLED AND MSVC) option(USE_BUNDLED_GETTEXT "Use the bundled version of gettext." ON) @@ -199,6 +200,9 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891 set(UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/v2.2.0.tar.gz) set(UTF8PROC_SHA256 3f8fd1dbdb057ee5ba584a539d5cd1b3952141c0338557cb0bdf8cb9cfed5dbf) +set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/6002fcd.tar.gz) +set(TREESITTER_C_SHA256 46f8d44fa886d9ddb92571bb6fa8b175992c8758eca749cb1217464e512b6e97) + if(USE_BUNDLED_UNIBILIUM) include(BuildUnibilium) endif() @@ -254,6 +258,10 @@ if(USE_BUNDLED_UTF8PROC) include(BuildUtf8proc) endif() +if(USE_BUNDLED_TS_PARSERS) + include(BuildTreesitterParsers) +endif() + if(WIN32) include(GetBinaryDeps) diff --git a/third-party/cmake/BuildTreesitterParsers.cmake b/third-party/cmake/BuildTreesitterParsers.cmake new file mode 100644 index 0000000000..690a8fbed1 --- /dev/null +++ b/third-party/cmake/BuildTreesitterParsers.cmake @@ -0,0 +1,28 @@ +ExternalProject_Add(treesitter-c +PREFIX ${DEPS_BUILD_DIR} +URL ${TREESITER_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 +BUILD_IN_SOURCE 1 +CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TreesitterParserCMakeLists.txt + ${DEPS_BUILD_DIR}/src/treesitter-c/CMakeLists.txt + COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/treesitter-c/CMakeLists.txt + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_GENERATOR=${CMAKE_GENERATOR} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} + # Pass toolchain + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -DPARSERLANG=c + +BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} +INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE}) diff --git a/third-party/cmake/TreesitterParserCMakeLists.txt b/third-party/cmake/TreesitterParserCMakeLists.txt new file mode 100644 index 0000000000..2808a9ee14 --- /dev/null +++ b/third-party/cmake/TreesitterParserCMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.12) +# some parsers have c++ scanner, problem? +project(parser C) # CXX + +add_library(parser + MODULE + src/parser.c +) +set_target_properties( + parser + PROPERTIES + POSITION_INDEPENDENT_CODE ON + OUTPUT_NAME ${PARSERLANG} + PREFIX "" +) + +include_directories(src) + +install(TARGETS parser LIBRARY DESTINATION lib/nvim/parser) |