Skip to content

Commit

Permalink
Feature: Suspend live grep and filter results
Browse files Browse the repository at this point in the history
See README for explanation. Use <c-k> to switch to pattern search
  mode during live grep.

M  README.md
M  autoload/scope/fuzzy.vim
M  autoload/scope/popup.vim
M  doc/scope.txt
  • Loading branch information
girishji committed Apr 14, 2024
1 parent e22702d commit 9f6eda6
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 17 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ def File(findCmd: string = null_string, count: number = 10000, ignore: bool = tr
```

> [!NOTE]
>
> - To prevent *find* command from descending into `.git` directory, put `.git/` in the `~/.gitignore` or `~/.findignore` file.
> - If `.gitignore` file contains `**` or `!` in the patterns, performance of *find* command may degrade. Use [fd](https://github.com/sharkdp/fd) if this becomes an issue.
> - To **echo the command string** in Vim's command line, set the option `find_echo_cmd` to `true`. Default is `false`. Setting of options is discussed later.
Expand All @@ -95,6 +94,7 @@ nnoremap <your_key> <scriptcmd>fuzzy.Grep()<cr>
> [!NOTE]
> 1. To perform a second grep with the same keyword, there's no need to retype it. The prompt conveniently retains the previous grep string as virtual text. Simply input `<Right>` or `<PgDn>` to auto-fill and proceed, or overwrite it as needed. For smaller projects, you can efficiently execute repeated greps without relying on the quickfix list.
> 2. Special characters can be entered into the prompt window directly without requiring backslash escaping.
> 3. It is sometimes useful to suspend live grep and filter results returned by live grep. Type `<C-k>` to enter pattern search mode (case insensitive). For example, typing `^foo` will filter lines that begin with `foo`. Patterns are negated if the first character is `!`. To filter lines *not* containing `foo` or `bar` type `!foo|bar` into the prompt.
Define your own grep command:

Expand Down Expand Up @@ -314,6 +314,7 @@ Mapping | Action
`<C-Q>` | Send only filtered items to the quickfix list
`<C-l>` | Send all unfiltered items to the location list (`:h location-list`)
`<C-L>` | Send only filtered items to the location list
`<C-k>` | Switch to pattern search of results during live grep

Prompt window editor key mappings align with Vim's default mappings for command-line editing.

Expand Down
34 changes: 32 additions & 2 deletions autoload/scope/fuzzy.vim
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export def Grep(grepCmd: string = null_string, ignorecase: bool = true,
var grep_throttle_len = max([0, options.grep_throttle_len])
var grep_skip_len = max([0, options.grep_skip_len])
var cmd: string
var select_mode = false # grep mode or select mode

def DoGrep(prompt: string, timer: number)
# during pasting from clipboard to prompt window, spawning a new job for
Expand Down Expand Up @@ -162,6 +163,12 @@ export def Grep(grepCmd: string = null_string, ignorecase: bool = true,

menu = popup.FilterMenu.new('Grep', [],
(res, key) => {
if key == "\<C-k>"
select_mode = true
menu.SetPrompt(null_string)
menu.SetText(menu.items_dict)
return
endif
if !util.Send2Qickfix(key, menu.items_dict, menu.filtered_items[0], cmd, null_function, true)
# let quicfix parse output of 'grep' for filename, line, column.
# it deals with ':' in filename and other corner cases.
Expand All @@ -178,6 +185,9 @@ export def Grep(grepCmd: string = null_string, ignorecase: bool = true,
endif
},
(id, idp) => {
if select_mode
return
endif
if cword != null_string
def SetPrompt(s: string, timer: number)
menu.SetPrompt(s)
Expand All @@ -204,8 +214,28 @@ export def Grep(grepCmd: string = null_string, ignorecase: bool = true,
},
(lst: list<dict<any>>, prompt: string): list<any> => {
# This function is called everytime when user types something
timer_start(timer_delay, function(DoGrep, [prompt]))
return [[], [[]]]
if select_mode
if prompt->empty()
return [lst, [lst]]
else
# pattern match only (not fuzzy match)
var filtered = []
if prompt[0] == '!'
filtered = lst->copy()->filter((_, v) => v.text !~ $'\v{prompt->slice(1)}')
else
for item in lst
var pos = item.text->matchstrpos($'\c{prompt}')
if pos[1] != -1
filtered->add({text: item.text, props: [{col: pos[1] + 1, length: pos[2] - pos[1], type: 'ScopeMenuMatch'}]})
endif
endfor
endif
return [lst, [filtered]]
endif
else
timer_start(timer_delay, function(DoGrep, [prompt]))
return [[], [[]]]
endif
},
() => {
if options.grep_echo_cmd
Expand Down
15 changes: 4 additions & 11 deletions autoload/scope/popup.vim
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ export class FilterMenu
this.prompt = this.prompt->slice(0, pos) .. key .. this.prompt->slice(pos)
this.cursorpos = this.cursorpos + 1
endif
elseif key == "\<C-k>"
Callback(null_string, key)
return true
endif
var GetFilteredItemsFn = GetFilteredItems == null_function ? this._GetFilteredItems : GetFilteredItems
[this.items_dict, this.filtered_items] = GetFilteredItemsFn(this.items_dict, this.prompt)
Expand Down Expand Up @@ -372,13 +375,7 @@ export class FilterMenu
})}
})
else
if itemsAny[0]->empty()
return []
else
return itemsAny[0]->mapnew((_, v) => {
return {text: v.text}
})
endif
return itemsAny->empty() ? [] : itemsAny[0]
endif
enddef

Expand All @@ -389,7 +386,3 @@ export class FilterMenu
matchaddpos('ScopeMenuCursor', [[1, bytepos]], 10, -1, {window: this.idp})
enddef
endclass

# some chunks shamelessly ripped from habamax
# https://github.com/habamax/.vim/blob/master/autoload/popup.vim

17 changes: 14 additions & 3 deletions doc/scope.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ API ~
# Applicable only when 'findCmd' is omitted or set to 'null_string'.
def File(findCmd: string = null_string, count: number = 10000, ignore: bool = true)
<
To echo the command string in Vim's command line, set the option
`find_echo_cmd` to `true`. Default is `false`. Setting of options is discussed
later.
> [!NOTE]
> - To prevent 'find' command from descending into `.git` directory, put `.git/`
> in the `~/.gitignore` or `~/.findignore` file.
> - If `.gitignore` file contains `**` or `!` in the patterns, performance of
> 'find' command may degrade. Use fd (https://github.com/sharkdp/fd) if this
> becomes an issue.
> - To echo the command string in Vim's command line, set the option
> `find_echo_cmd` to `true`. Default is `false`. Setting of options is
> discussed later.

Live Grep ~

Expand All @@ -76,6 +82,11 @@ Live grep in the directory.
> repeated greps without relying on the quickfix list.
> 2. Special characters can be entered into the prompt window directly without
> requiring backslash escaping.
> 3. It is sometimes useful to suspend live grep and filter results returned
> by live grep. Type `<C-k>` to enter pattern search mode (case
> insensitive). For example, typing `^foo` will filter lines that begin
> with `foo`. Patterns are negated if the first character is `!`. To filter
> lines not containing `foo` or `bar` type `!foo|bar` into the prompt.

Define your own grep command.
>
Expand Down

0 comments on commit 9f6eda6

Please sign in to comment.