Re: Commit: patch 9.1.0009: Cannot easily get the list of matches

106 views
Skip to first unread message

Yegappan Lakshmanan

unread,
Jan 7, 2024, 11:30:45 AMJan 7
to vim...@googlegroups.com, vim_use
Hi all,

On Thu, Jan 4, 2024 at 1:45 PM Christian Brabandt <cbl...@256bit.org> wrote:
patch 9.1.0009: Cannot easily get the list of matches

Commit: https://github.com/vim/vim/commit/f93b1c881a99fa847a1bafa71877d7e16f18e6ef
Author: Yegappan Lakshmanan <yega...@yahoo.com>
Date:   Thu Jan 4 22:28:46 2024 +0100

    patch 9.1.0009: Cannot easily get the list of matches

    Problem:  Cannot easily get the list of matches
    Solution: Add the matchstrlist() and matchbufline() Vim script
              functions (Yegappan Lakshmanan)


To demonstrate the use of the new matchbufline() function, I have created
the following script.  This does search text completion from the list of words
in the current buffer.  After typing a few letters in the "/" prompt, if you press
Tab, it will complete the word from the current buffer.  If you press Tab again,
then it will go to the next match.  If you press Shift-Tab, it will go back to
the previous match.

Regards,
Yegappan

--------------------------------------------------------------------------------------------------------
vim9script

var searchMatches: list<string> = []
var prevMatchIndex: number = 0
var prevCmdline: string = ''
var prevCmdlinePrefix: string = ''
var prevPat: string = ''

def SearchComplete(forward: bool): string
  var cmdtype: string = getcmdtype()
  if cmdtype != '/' && cmdtype != '?'
    feedkeys(forward ? "\<Tab>" : "\<S-Tab>", 'nt')
    return ''
  endif

  var cmdline: string = getcmdline()
  if cmdline != '' && cmdline ==# prevCmdline
    # Jump to the next/previous match
    if (cmdtype == '/' && forward) || (cmdtype == '?' && !forward)
      prevMatchIndex += 1
    else
      prevMatchIndex -= 1
    endif
    if prevMatchIndex < 0
      prevMatchIndex = searchMatches->len() - 1
    elseif prevMatchIndex >= searchMatches->len()
      prevMatchIndex = 0
    endif
    var s = searchMatches[prevMatchIndex][strlen(prevPat) : ]

    prevCmdline = prevCmdlinePrefix .. s
    setcmdline(prevCmdlinePrefix)
    return s
  endif

  var cmdpos: number = getcmdpos()

  var start: number = cmdpos - 1
  if start >= strlen(cmdline)
    start -= 1
  endif
  while start > 0 && cmdline[start - 1] =~ '\k'
    start -= 1
  endwhile
  var pat: string = cmdline[start : cmdpos]

  # Get the List of matches
  var start_lnum = &wrapscan || cmdtype == '?' ? 1 : line('.')
  var end_lnum = &wrapscan || cmdtype == '/' ? '$' : line('.')
  var l = matchbufline('', $'\<{pat}\k\+\>', start_lnum, end_lnum)
  if l->empty()
    return ''
  endif

  var curline = line('.')
  var curcol = col('.')
  var patStartByte = curcol - 1 - strlen(pat)

  l->filter((_, v) => v.lnum == curline ? cmdtype == '/' ? v.byteidx >= patStartByte : v.byteidx <= patStartByte : true)
  if l->empty()
    return ''
  endif

  # Sort by matched string and line/byte index
  l->sort((a, b) => {
    if a.text > b.text
      return 1
    elseif a.text == b.text
      if a.lnum > b.lnum
        return 1
      elseif a.lnum == b.lnum
        return a.byteidx > b.byteidx ? 1 : 0
      endif
      return 0
    endif
    return 0
  })
  # Remove duplicates
  l->uniq((a, b) => a.text ==# b.text ? 0 : 1)
  # Sort by byte index and line number
  l->sort((a, b) => a.lnum == b.lnum ? a.byteidx - b.byteidx : a.lnum - b.lnum)

  var startIdx: number
  if cmdtype == '/'
    startIdx = l->indexof((_, v) => v.lnum == curline ? v.byteidx >= patStartByte : v.lnum > curline)
  else
    startIdx = l->copy()->reverse()->indexof((_, v) => v.lnum == curline ? v.byteidx <= patStartByte : v.lnum < curline)
    startIdx = l->len() - startIdx - 1
  endif
 
  if startIdx == -1
    startIdx = forward ? 0 : searchMatches->len() - 1
  endif

  # Save the matched strings
  searchMatches = l->map((_, v) => v.text)

  var s = searchMatches[startIdx][strlen(pat) : ]

  # Save the state for jumping to the next previous match
  prevMatchIndex = startIdx
  prevPat = pat
  prevCmdline = cmdline .. s
  prevCmdlinePrefix = cmdline

  return s
enddef

cnoremap <Tab> <C-R>=<SID>SearchComplete(v:true)<CR>
cnoremap <S-Tab> <C-R>=<SID>SearchComplete(v:false)<CR>

# vim: ts=8 sw=2 sts=2 expandtab tw=80
--------------------------------------------------------------------------------------------------------

Christian Brabandt

unread,
Jan 8, 2024, 8:29:52 AMJan 8
to vim...@googlegroups.com, vim...@googlegroups.com

On So, 07 Jan 2024, Yegappan Lakshmanan wrote:

> To demonstrate the use of the new matchbufline() function, I have created
> the following script.  This does search text completion from the list of words
> in the current buffer.  After typing a few letters in the "/" prompt, if you
> press
> Tab, it will complete the word from the current buffer.  If you press Tab
> again,
> then it will go to the next match.  If you press Shift-Tab, it will go back to
> the previous match.

That is great, thanks for sharing!

Thanks,
Christian
--
Two is not equal to three, even for large values of two.

Gary Johnson

unread,
Jan 8, 2024, 3:14:23 PMJan 8
to vim...@googlegroups.com, vim_use
On 2024-01-07, Yegappan Lakshmanan wrote:

> To demonstrate the use of the new matchbufline() function, I have created
> the following script.  This does search text completion from the list of words
> in the current buffer.  After typing a few letters in the "/" prompt, if you
> press
> Tab, it will complete the word from the current buffer.  If you press Tab
> again,
> then it will go to the next match.  If you press Shift-Tab, it will go back to
> the previous match.

I saved your script to a file and sourced it, but it gives me an
error.

Error detected while processing /home/gary/.vim/match_tab.vim:
line 9:
E1171: Missing } after inline function

Line 9 is:

def SearchComplete(forward: bool): string

I've updated to 9.1.16 and done a clean build without any
configuration options.

I haven't done anything with vim9script, so I don't recognize syntax
errors by sight, nor do I know what else I might be missing.

Regards,
Gary

--------------------------------------------------------------------
$ VIMRUNTIME=runtime src/vim --version
VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Jan 8 2024 11:48:09)
Included patches: 1-16
Compiled by gary@epicurus
Huge version with GTK3 GUI. Features included (+) or not (-):
+acl +file_in_path +mouse_urxvt -tag_any_white
+arabic +find_in_path +mouse_xterm -tcl
+autocmd +float +multi_byte +termguicolors
+autochdir +folding +multi_lang +terminal
-autoservername -footer -mzscheme +terminfo
+balloon_eval +fork() +netbeans_intg +termresponse
+balloon_eval_term +gettext +num64 +textobjects
+browse -hangul_input +packages +textprop
++builtin_terms +iconv +path_extra +timers
+byte_offset +insert_expand -perl +title
+channel +ipv6 +persistent_undo +toolbar
+cindent +job +popupwin +user_commands
+clientserver +jumplist +postscript +vartabs
+clipboard +keymap +printer +vertsplit
+cmdline_compl +lambda +profile +vim9script
+cmdline_hist +langmap -python +viminfo
+cmdline_info +libcall -python3 +virtualedit
+comments +linebreak +quickfix +visual
+conceal +lispindent +reltime +visualextra
+cryptv +listcmds +rightleft +vreplace
+cscope +localmap -ruby +wildignore
+cursorbind -lua +scrollbind +wildmenu
+cursorshape +menu +signs +windows
+dialog_con_gui +mksession +smartindent +writebackup
+diff +modify_fname +sodium +X11
+digraphs +mouse +sound +xattr
+dnd +mouseshape +spell -xfontset
-ebcdic +mouse_dec +startuptime +xim
+emacs_tags +mouse_gpm +statusline +xpm
+eval -mouse_jsbterm -sun_workshop +xsmp_interact
+ex_extra +mouse_netterm +syntax +xterm_clipboard
+extra_search +mouse_sgr +tag_binary -xterm_save
-farsi -mouse_sysmouse -tag_old_static
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
user exrc file: "$HOME/.exrc"
system gvimrc file: "$VIM/gvimrc"
user gvimrc file: "$HOME/.gvimrc"
2nd user gvimrc file: "~/.vim/gvimrc"
defaults file: "$VIMRUNTIME/defaults.vim"
system menu file: "$VIMRUNTIME/menu.vim"
fall-back for $VIM: "/usr/local/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK -pthread -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/harfbuzz -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/x86_64-linux-gnu -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -O2 -fno-strength-reduce -Wall -Wno-deprecated-declarations -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc -L/usr/local/lib -Wl,--as-needed -o vim -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lSM -lICE -lXpm -lXt -lX11 -lXdmcp -lSM -lICE -lm -ltinfo -lselinux -lcanberra -lsodium -lacl -lattr -lgpm

Yegappan Lakshmanan

unread,
Jan 8, 2024, 4:57:34 PMJan 8
to vim...@googlegroups.com, vim_use
Hi Gary,

On Mon, Jan 8, 2024 at 12:14 PM Gary Johnson <gary...@spocom.com> wrote:
On 2024-01-07, Yegappan Lakshmanan wrote:

> To demonstrate the use of the new matchbufline() function, I have created
> the following script.  This does search text completion from the list of words
> in the current buffer.  After typing a few letters in the "/" prompt, if you
> press
> Tab, it will complete the word from the current buffer.  If you press Tab
> again,
> then it will go to the next match.  If you press Shift-Tab, it will go back to
> the previous match.

I saved your script to a file and sourced it, but it gives me an
error.

    Error detected while processing /home/gary/.vim/match_tab.vim:
    line    9:
    E1171: Missing } after inline function

Line 9 is:

    def SearchComplete(forward: bool): string


I am not sure what is wrong from the above error message.  In case there
is a cut/paste error, can you please try the attached file?

- Yegappan
searchcomplete.vim

Gary Johnson

unread,
Jan 8, 2024, 6:04:07 PMJan 8
to vim...@googlegroups.com, vim_use
On 2024-01-08, Yegappan Lakshmanan wrote:
> Hi Gary,
>
> On Mon, Jan 8, 2024 at 12:14 PM Gary Johnson wrote:
>
> On 2024-01-07, Yegappan Lakshmanan wrote:
>
> > To demonstrate the use of the new matchbufline() function, I have created
> > the following script.  This does search text completion from the list of
> words
> > in the current buffer.  After typing a few letters in the "/" prompt, if
> you
> > press
> > Tab, it will complete the word from the current buffer.  If you press Tab
> > again,
> > then it will go to the next match.  If you press Shift-Tab, it will go
> back to
> > the previous match.
>
> I saved your script to a file and sourced it, but it gives me an
> error.
>
>     Error detected while processing /home/gary/.vim/match_tab.vim:
>     line    9:
>     E1171: Missing } after inline function
>
> Line 9 is:
>
>     def SearchComplete(forward: bool): string
>
>
>
> I am not sure what is wrong from the above error message.  In case there
> is a cut/paste error, can you please try the attached file?

Hi Yegappan,

Thank you. That fixed the problem. I had copied your script from
your original posting by decode-saving your message from mutt, then
deleting the text before and after the script. It turns out that
the leading spaces in that copy included non-breaking space
characters, 0xa0, which somehow confused Vim's parser.

I did have to convert your attachment from DOS to Unix line endings,
but that was immediately apparent and not a problem.

Regards,
Gary

Yegappan Lakshmanan

unread,
Jan 9, 2024, 9:51:45 AMJan 9
to vim...@googlegroups.com, vim_use
On Sun, Jan 7, 2024 at 8:30 AM Yegappan Lakshmanan <yega...@gmail.com> wrote:
Hi all,

On Thu, Jan 4, 2024 at 1:45 PM Christian Brabandt <cbl...@256bit.org> wrote:
patch 9.1.0009: Cannot easily get the list of matches

Commit: https://github.com/vim/vim/commit/f93b1c881a99fa847a1bafa71877d7e16f18e6ef
Author: Yegappan Lakshmanan <yega...@yahoo.com>
Date:   Thu Jan 4 22:28:46 2024 +0100

    patch 9.1.0009: Cannot easily get the list of matches

    Problem:  Cannot easily get the list of matches
    Solution: Add the matchstrlist() and matchbufline() Vim script
              functions (Yegappan Lakshmanan)


To demonstrate the use of the new matchbufline() function, I have created
the following script.  This does search text completion from the list of words
in the current buffer.  After typing a few letters in the "/" prompt, if you press
Tab, it will complete the word from the current buffer.  If you press Tab again,
then it will go to the next match.  If you press Shift-Tab, it will go back to
the previous match.


I have uploaded this plugin to the https://github.com/yegappan/searchcomplete repository.

Regards,
Yegappan 

Ubaldo Tiberi

unread,
Jan 29, 2024, 8:35:34 AMJan 29
to vim_use
This is very cool!
I have tried to install as soon as it went out (I am follower on GitHub so I am immediately notified) but then I found out that matchbufline() is not available (yet) on MacVim (at its 9.1 Version). 
I'll install it as soon as that command will be available on MacVim. 

Maxim Kim

unread,
Feb 14, 2024, 6:58:48 AMFeb 14
to vim_use
I was hoping it would do multiline regex searches as well (help doesn't mention it can't do it)

Use case, find all C functions in, let's say src/highlight.c from vim sources:

Regex is \v^\s*(\k+\_s+){1,}\k+\(.{-}\)\_s*\{\s*$
And even though I can find them using regular interactive search (/) and :call search('\v^\s*(\k+\_s+){1,}\k+\(.{-}\)\_s*\{\s*$')
the result of the next call to matchbufline is empty:

    :call matchbufline(bufnr(), '\v^\s*(\k+\_s+){1,}\k+\(.{-}\)\_s*\{\s*$', 1, '$')

Apparently it goes line by line matching the pattern and thus fails.


Screenshot from 2024-02-14 22-56-07.png

Reply all
Reply to author
Forward
0 new messages