mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	feat(treesitter): handle quantified fold captures
This commit is contained in:
		
				
					committed by
					
						
						Christian Clason
					
				
			
			
				
	
			
			
			
						parent
						
							8886b1807c
						
					
				
				
					commit
					5e6240ffc2
				
			@@ -267,6 +267,8 @@ The following new APIs and features were added.
 | 
			
		||||
  • The `#set!` directive can set the "url" property of a node to have the
 | 
			
		||||
    node emit a hyperlink. Hyperlinks are UI specific: in the TUI, the OSC 8
 | 
			
		||||
    control sequence is used.
 | 
			
		||||
  • |vim.treesitter.foldexpr()| now recognizes folds captured using a
 | 
			
		||||
    quantified query pattern.
 | 
			
		||||
 | 
			
		||||
• |:Man| now supports `:hide` modifier to open page in the current window.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -149,27 +149,43 @@ local function get_folds_levels(bufnr, info, srow, erow, parse_injections)
 | 
			
		||||
 | 
			
		||||
    -- Collect folds starting from srow - 1, because we should first subtract the folds that end at
 | 
			
		||||
    -- srow - 1 from the level of srow - 1 to get accurate level of srow.
 | 
			
		||||
    for id, node, metadata in query:iter_captures(tree:root(), bufnr, math.max(srow - 1, 0), erow) do
 | 
			
		||||
      if query.captures[id] == 'fold' then
 | 
			
		||||
        local range = ts.get_range(node, bufnr, metadata[id])
 | 
			
		||||
        local start, _, stop, stop_col = Range.unpack4(range)
 | 
			
		||||
    for _, match, metadata in
 | 
			
		||||
      query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow, { all = true })
 | 
			
		||||
    do
 | 
			
		||||
      for id, nodes in pairs(match) do
 | 
			
		||||
        if query.captures[id] == 'fold' then
 | 
			
		||||
          local range = ts.get_range(nodes[1], bufnr, metadata[id])
 | 
			
		||||
          local start, _, stop, stop_col = Range.unpack4(range)
 | 
			
		||||
 | 
			
		||||
        if stop_col == 0 then
 | 
			
		||||
          stop = stop - 1
 | 
			
		||||
        end
 | 
			
		||||
          for i = 2, #nodes, 1 do
 | 
			
		||||
            local node_range = ts.get_range(nodes[i], bufnr, metadata[id])
 | 
			
		||||
            local node_start, _, node_stop, node_stop_col = Range.unpack4(node_range)
 | 
			
		||||
            if node_start < start then
 | 
			
		||||
              start = node_start
 | 
			
		||||
            end
 | 
			
		||||
            if node_stop > stop then
 | 
			
		||||
              stop = node_stop
 | 
			
		||||
              stop_col = node_stop_col
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        local fold_length = stop - start + 1
 | 
			
		||||
          if stop_col == 0 then
 | 
			
		||||
            stop = stop - 1
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        -- Fold only multiline nodes that are not exactly the same as previously met folds
 | 
			
		||||
        -- Checking against just the previously found fold is sufficient if nodes
 | 
			
		||||
        -- are returned in preorder or postorder when traversing tree
 | 
			
		||||
        if
 | 
			
		||||
          fold_length > vim.wo.foldminlines and not (start == prev_start and stop == prev_stop)
 | 
			
		||||
        then
 | 
			
		||||
          enter_counts[start + 1] = (enter_counts[start + 1] or 0) + 1
 | 
			
		||||
          leave_counts[stop + 1] = (leave_counts[stop + 1] or 0) + 1
 | 
			
		||||
          prev_start = start
 | 
			
		||||
          prev_stop = stop
 | 
			
		||||
          local fold_length = stop - start + 1
 | 
			
		||||
 | 
			
		||||
          -- Fold only multiline nodes that are not exactly the same as previously met folds
 | 
			
		||||
          -- Checking against just the previously found fold is sufficient if nodes
 | 
			
		||||
          -- are returned in preorder or postorder when traversing tree
 | 
			
		||||
          if
 | 
			
		||||
            fold_length > vim.wo.foldminlines and not (start == prev_start and stop == prev_stop)
 | 
			
		||||
          then
 | 
			
		||||
            enter_counts[start + 1] = (enter_counts[start + 1] or 0) + 1
 | 
			
		||||
            leave_counts[stop + 1] = (leave_counts[stop + 1] or 0) + 1
 | 
			
		||||
            prev_start = start
 | 
			
		||||
            prev_stop = stop
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -404,6 +404,28 @@ t3]])
 | 
			
		||||
    }, get_fold_levels())
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('handles quantified patterns', function()
 | 
			
		||||
    insert([[
 | 
			
		||||
import hello
 | 
			
		||||
import hello
 | 
			
		||||
import hello
 | 
			
		||||
import hello
 | 
			
		||||
import hello
 | 
			
		||||
import hello]])
 | 
			
		||||
 | 
			
		||||
    exec_lua([[vim.treesitter.query.set('python', 'folds', '(import_statement)+ @fold')]])
 | 
			
		||||
    parse('python')
 | 
			
		||||
 | 
			
		||||
    eq({
 | 
			
		||||
      [1] = '>1',
 | 
			
		||||
      [2] = '1',
 | 
			
		||||
      [3] = '1',
 | 
			
		||||
      [4] = '1',
 | 
			
		||||
      [5] = '1',
 | 
			
		||||
      [6] = '1',
 | 
			
		||||
    }, get_fold_levels())
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('updates folds in all windows', function()
 | 
			
		||||
    local screen = Screen.new(60, 48)
 | 
			
		||||
    screen:attach()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user