Skip to content

Commit

Permalink
feat(treesitter): add support for setting query depths
Browse files Browse the repository at this point in the history
  • Loading branch information
lewis6991 authored May 11, 2023
1 parent e90b506 commit af040c3
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 9 deletions.
20 changes: 20 additions & 0 deletions cmake/FindTreesitter.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,23 @@ mark_as_advanced(TREESITTER_LIBRARY TREESITTER_INCLUDE_DIR)
add_library(treesitter INTERFACE)
target_include_directories(treesitter SYSTEM BEFORE INTERFACE ${TREESITTER_INCLUDE_DIR})
target_link_libraries(treesitter INTERFACE ${TREESITTER_LIBRARY})

# TODO(lewis6991): remove when min TS version is 0.20.9
list(APPEND CMAKE_REQUIRED_INCLUDES "${TREESITTER_INCLUDE_DIR}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${TREESITTER_LIBRARY}")
check_c_source_compiles("
#include <tree_sitter/api.h>
int
main(void)
{
TSQueryCursor *cursor = ts_query_cursor_new();
ts_query_cursor_set_max_start_depth(cursor, 32);
return 0;
}
" TS_HAS_SET_MAX_START_DEPTH)
list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${TREESITTER_INCLUDE_DIR}")
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${TREESITTER_LIBRARY}")

if(TS_HAS_SET_MAX_START_DEPTH)
target_compile_definitions(treesitter INTERFACE NVIM_TS_HAS_SET_MAX_START_DEPTH)
endif()
4 changes: 4 additions & 0 deletions runtime/doc/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The following changes may require adaptations in user config or plugins.
set selectmode=mouse,key
set mousemodel=popup
set keymodel=startsel,stopsel
<

==============================================================================
ADDED FEATURES *news-added*
Expand All @@ -52,6 +53,9 @@ iterators |luaref-in|.
|'smoothscroll'| option to scroll by screen line rather than by text line
when |'wrap'| is set.

|Query:iter_matches()| now has the ability to set the maximum start depth
for matches.

==============================================================================
CHANGED FEATURES *news-changed*

Expand Down
7 changes: 6 additions & 1 deletion runtime/doc/treesitter.txt
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ Query:iter_captures({self}, {node}, {source}, {start}, {stop})
metadata

*Query:iter_matches()*
Query:iter_matches({self}, {node}, {source}, {start}, {stop})
Query:iter_matches({self}, {node}, {source}, {start}, {stop}, {opts})
Iterates the matches of self on a given range.

Iterate over all matches within a {node}. The arguments are the same as
Expand All @@ -966,6 +966,11 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop})
{source} (integer|string) Source buffer or string to search
{start} (integer) Starting line for the search
{stop} (integer) Stopping line for the search (end-exclusive)
{opts} (table|nil) Options:
• max_start_depth (integer) if non-zero, sets the maximum
start depth for each match. This is used to prevent
traversing too deep into a tree. Requires treesitter >=
0.20.9.
{self}

Return: ~
Expand Down
14 changes: 8 additions & 6 deletions runtime/lua/vim/treesitter/_meta.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ local TSNode = {}

---@param query userdata
---@param captures true
---@param start integer
---@param end_ integer
---@param start? integer
---@param end_? integer
---@param opts? table
---@return fun(): integer, TSNode, any
function TSNode:_rawquery(query, captures, start, end_) end
function TSNode:_rawquery(query, captures, start, end_, opts) end

---@param query userdata
---@param captures false
---@param start integer
---@param end_ integer
---@param start? integer
---@param end_? integer
---@param opts? table
---@return fun(): string, any
function TSNode:_rawquery(query, captures, start, end_) end
function TSNode:_rawquery(query, captures, start, end_, opts) end

---@class TSParser
---@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean?): TSTree, integer[]
Expand Down
8 changes: 6 additions & 2 deletions runtime/lua/vim/treesitter/query.lua
Original file line number Diff line number Diff line change
Expand Up @@ -686,16 +686,20 @@ end
---@param source (integer|string) Source buffer or string to search
---@param start integer Starting line for the search
---@param stop integer Stopping line for the search (end-exclusive)
---@param opts table|nil Options:
--- - max_start_depth (integer) if non-zero, sets the maximum start depth
--- for each match. This is used to prevent traversing too deep into a tree.
--- Requires treesitter >= 0.20.9.
---
---@return (fun(): integer, table<integer,TSNode>, table): pattern id, match, metadata
function Query:iter_matches(node, source, start, stop)
function Query:iter_matches(node, source, start, stop, opts)
if type(source) == 'number' and source == 0 then
source = api.nvim_get_current_buf()
end

start, stop = value_or_node_range(start, stop, node)

local raw_iter = node:_rawquery(self.query, false, start, stop)
local raw_iter = node:_rawquery(self.query, false, start, stop, opts)
---@cast raw_iter fun(): string, any
local function iter()
local pattern, match = raw_iter()
Expand Down
23 changes: 23 additions & 0 deletions src/nvim/lua/treesitter.c
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,29 @@ static int node_rawquery(lua_State *L)
ts_query_cursor_set_point_range(cursor, (TSPoint){ start, 0 }, (TSPoint){ end, 0 });
}

if (lua_gettop(L) >= 6 && !lua_isnil(L, 6)) {
if (!lua_istable(L, 6)) {
return luaL_error(L, "table expected");
}
lua_pushnil(L);
// stack: [dict, ..., nil]
while (lua_next(L, 6)) {
// stack: [dict, ..., key, value]
if (lua_type(L, -2) == LUA_TSTRING) {
char *k = (char *)lua_tostring(L, -2);
if (strequal("max_start_depth", k)) {
// TODO(lewis6991): remove ifdef when min TS version is 0.20.9
#ifdef NVIM_TS_HAS_SET_MAX_START_DEPTH
uint32_t max_start_depth = (uint32_t)lua_tointeger(L, -1);
ts_query_cursor_set_max_start_depth(cursor, max_start_depth);
#endif
}
}
lua_pop(L, 1); // pop the value; lua_next will pop the key.
// stack: [dict, ..., key]
}
}

TSLua_cursor *ud = lua_newuserdata(L, sizeof(*ud)); // [udata]
ud->cursor = cursor;
ud->predicated_match = -1;
Expand Down

0 comments on commit af040c3

Please sign in to comment.