Hi all,
On Thu, Jan 4, 2024 at 1:45 PM Christian Brabandt <cblists@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 <yegappan@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
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
--------------------------------------------------------------------------------------------------------
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vim_use/CAAW7x7nDkmO_MQRy4XycR%3DhDPmAVi1pHh2DSV23cPj65%3Dfi%2BQg%40mail.gmail.com.
No comments:
Post a Comment