Skip to content

regexp: match at cursor position for \%.l \%.c and \%.v#8497

Closed
chrisbra wants to merge 1 commit intovim:masterfrom
chrisbra:vim_8179
Closed

regexp: match at cursor position for \%.l \%.c and \%.v#8497
chrisbra wants to merge 1 commit intovim:masterfrom
chrisbra:vim_8179

Conversation

@chrisbra
Copy link
Member

@chrisbra chrisbra commented Jul 1, 2021

This change allows to match the cursor position using the special mark
'.', so that \%.c will match the current cursor column, \%.l matches the
current cursor line and \%.v matches the current virtual column.

This has been wished for at #8179

It also works for the greater than \%>. and less than variants \%<.

However, the \%.v look actually quite ugly. An alternative would be to omit
the . altogether and use those variants: \%>l so that when no number is given
the cursor position would be automatically be used.

Would that be better? I don't know.

@chrisbra chrisbra changed the title regexp: match at cursor position for \%l \%c and \%v regexp: match at cursor position for \%.l \%.c and \%.v Jul 1, 2021
@codecov
Copy link

codecov bot commented Jul 1, 2021

Codecov Report

Merging #8497 (8ae8f8a) into master (22f85d0) will decrease coverage by 0.07%.
The diff coverage is 100.00%.

❗ Current head 8ae8f8a differs from pull request most recent head 92c5c2b. Consider uploading reports for the commit 92c5c2b to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master    #8497      +/-   ##
==========================================
- Coverage   90.02%   89.94%   -0.08%     
==========================================
  Files         149      145       -4     
  Lines      168044   167043    -1001     
==========================================
- Hits       151278   150254    -1024     
- Misses      16766    16789      +23     
Flag Coverage Δ
huge-clang-none 89.12% <100.00%> (+0.07%) ⬆️
huge-gcc-none 89.51% <100.00%> (+<0.01%) ⬆️
huge-gcc-testgui 88.12% <100.00%> (+<0.01%) ⬆️
huge-gcc-unittests ?

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/regexp_bt.c 92.62% <100.00%> (+0.05%) ⬆️
src/regexp_nfa.c 92.96% <100.00%> (+0.03%) ⬆️
src/json.c 91.65% <0.00%> (-1.13%) ⬇️
src/os_unix.c 71.16% <0.00%> (-0.96%) ⬇️
src/message.c 88.83% <0.00%> (-0.96%) ⬇️
src/if_python.c 82.65% <0.00%> (-0.62%) ⬇️
src/gui.c 71.97% <0.00%> (-0.44%) ⬇️
src/syntax.c 86.58% <0.00%> (-0.43%) ⬇️
src/ops.c 95.58% <0.00%> (-0.42%) ⬇️
src/getchar.c 91.14% <0.00%> (-0.39%) ⬇️
... and 23 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 22f85d0...92c5c2b. Read the comment docs.

@brammool
Copy link
Contributor

brammool commented Jul 3, 2021 via email

@chrisbra
Copy link
Member Author

chrisbra commented Jul 5, 2021

I think it's better to keep the dot. If we would leave it out, it's too
easy to have an invalid pattern go unnoticed.

Okay, I'll leave it as is. However, please note, \%l, \%c and \%v is currently not an error, except for ("E486: Pattern not found").

Thanks for noticing the other two things. I think I have fixed that now, will push a new version in a minute (after rebasing)

This change allows to match the cursor position using the special mark
'.', so '\%.c' will match the current cursor column, '\%.l' matches the
current cursor line and '\%.v' matches the current virtual column.

This has been wished for at vim#8179

It also works for the greater than '\%>.' and less than variants '\%<.'
@lacygoill
Copy link

lacygoill commented Jul 6, 2021

Thank you very much for the feature; it's extremely useful.


I don't know whether it's possible to implement, but \%<=.c would have been also useful. Without, we sometimes have to write this (which is a bit harder to read):

\%(\%<.c\|\%.c\)

Here is a real example where it's necessary. Suppose you want a mapping to insert the text under the cursor and between backticks on the command-line:

cnoremap <C-R>` <C-R><C-R>=<SID>InsertCodespan()<CR>
def InsertCodespan(): string
    var pat: string = '\%(\%<.c\|\%.c\)`\zs[^`]\+\ze`\%>.c'
    return getline('.')
        ->matchstr(pat)
        ->substitute('^:', '', '')
enddef

Working test:

vim9script
'# some comment with a `codespan` we want to insert on the command-line'->setline(1)
search('codespan')

cnoremap <C-R>` <C-R><C-R>=<SID>InsertCodespan()<CR>
def InsertCodespan(): string
    var pat: string = '\%(\%<.c\|\%.c\)`\zs[^`]\+\ze`\%>.c'
    return getline('.')
        ->matchstr(pat)
        ->substitute('^:', '', '')
enddef

feedkeys(":\<C-R>`")
# expected: the command-line contains "codespan"
# actual:   the command-line contains "codespan"

But notice this regex in the first line of the function:

\%(\%<.c\|\%.c\)`\zs[^`]\+\ze`\%>.c

And in particular, notice the start:

\%(\%<.c\|\%.c\)`\zs[^`]\+\ze`\%>.c
^--------------^

We can't just write \%<.c, because the mapping would fail if we're on the first backtick, which might seem unexpected to the user. Failing test:

vim9script
'# some comment with a `codespan` we want to insert on the command-line'->setline(1)
search('`codespan')

cnoremap <C-R>` <C-R><C-R>=<SID>InsertCodespan()<CR>
def InsertCodespan(): string
    var pat: string = '\%<.c`\zs[^`]\+\ze`\%>.c'
    return getline('.')
        ->matchstr(pat)
        ->substitute('^:', '', '')
enddef

feedkeys(":\<C-R>`")
# expected: the command-line contains "codespan"
# actual:   the command-line is empty

With \%<=.c, we could simplify the regex in the working code like this:

\%<=.c`\zs[^`]\+\ze`\%>.c
^----^

With regards to \%.v, it doesn't work when we're on a multicell characters (like a tab):

vim9script
'the quick brown fox jumps over the lazy dog'->setline(1)
substitute/ /\t/g
search('jumps')
normal! h
feedkeys('/\%.v' .. "\<CR>")
E486: Pattern not found: \%.v

I guess that's because – internally – \%.v must be translated into \%123v where 123 is the index of the cell under the cursor. And on a multicell character, the cell under the cursor is usually the last one (unless we've tweaked 'virtualedit'). But \%123v does not want the index of the last cell; it wants the index of the first cell.

When \%.v is translated into \%123v (again, internally), could Vim make sure to use the index of the first cell, rather than the index of the last one?

@lacygoill
Copy link

When %.v is translated into %123v (again, internally), could Vim make sure to use the index of the first cell, rather than the index of the last one?

Otherwise, we have to write this (which is much harder to read):

var vcol: number = virtcol([line('.'), col('.') - 1]) + 1
var pat: string = '\%' .. vcol .. 'v'

Example:

vim9script
'the quick brown fox jumps over the lazy dog'->setline(1)
substitute/ /\t/g
search('jumps')
normal! h
var vcol: number = virtcol([line('.'), col('.') - 1]) + 1
var pat: string = '\%' .. vcol .. 'v'
feedkeys('/' .. pat .. "\<CR>")

@chrisbra chrisbra deleted the vim_8179 branch July 12, 2021 18:46
chrisbra pushed a commit to chrisbra/vim that referenced this pull request Aug 30, 2021
…ated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim#8497, closes vim#8179)
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 19, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 19, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b

Also use `n = ++vcol` in regexp_bt.c as `++vcol` alone fails lint.
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 20, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b

Also use `n = ++vcol` in regexp_bt.c as `++vcol` alone fails lint.
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 26, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b

Also use `n = ++vcol` in regexp_bt.c as `++vcol` alone fails lint.
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 29, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b

Also use `n = ++vcol` in regexp_bt.c as `++vcol` alone fails lint.
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 29, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b

Also use `n = ++vcol` in regexp_bt.c as `++vcol` alone fails lint.
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Mar 30, 2022
…plicated

Problem:    A pattern that matches the cursor position is bit complicated.
Solution:   Use a dot to indicate the cursor line and column. (Christian
            Brabandt, closes vim/vim#8497, closes vim/vim#8179)
vim/vim@04db26b

Also use `n = ++vcol` in regexp_bt.c as `++vcol` alone fails lint.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants