[RFC/patch] Expose information about character searches (f, F, t, T) in VimL

90 views
Skip to first unread message

James McCoy

unread,
Jul 23, 2015, 11:30:42 PM7/23/15
to vim...@googlegroups.com, Bram Moolenaar
Recently, I've heard some script authors ponder whether there was a way
to access information about the last character search a user performed.
The ideas being explored were overriding ; and , to always search
forward/backward respectively, or providing visual cues for where a
character search would move the cursor.

There exists a mechanism for script authors to interact with normal
searches via the / register and the v:searchforward variable.

The attached patch implements comparable functionality for character
searches.

* A new, read-write ; register exposes the character which would be the
target for a subsequent ; or , command. If this register is set, then
the direction and type of character search are (re)set as if the user
had used t to perform the search.

* A new, read-write v:csearchforward variable exposes the direction of
the character search, similar to v:searchforward.

* A new, read-write v:csearchuntil variable exposes whether the search
is an "until" (t) search.

* Any normal character searches which happen within a function or
autocmd will not affect the user's character search state, similar to
the handling of normal searches. However, a script author may affect
that through using the above listed variables/register.

Aside from enabling script authors to better interact with character
searches, this also makes it easier to search for composed characters
using character search. One currently has to create a keymap file and
use “:loadkeymap” to easily enter a composed character as the character
search value. With this functionality, one can instead simply “:let
@;="a\u0301"” to search for á.

Cheers,
--
James
GPG Key: 4096R/331BA3DB 2011-12-05 James McCoy <jame...@jamessan.com>
csearch.diff
signature.asc

Bram Moolenaar

unread,
Jul 25, 2015, 12:08:49 PM7/25/15
to James McCoy, vim...@googlegroups.com
Thanks for taking the initiative for this.

How about this alternative, use functions:
getcharsearch() returns a dict with the relevant info
setcharsearch() stores the relevant info

It should be easier to save and restore the search, while all the
information is present in one place.

I think character searches are not very common in plugins, thus having
to manually save and restore is simpler and more efficient than having
all function calls do this.


--
hundred-and-one symptoms of being an internet addict:
10E. You start counting in hex.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Christian Brabandt

unread,
Jul 25, 2015, 12:43:18 PM7/25/15
to vim...@googlegroups.com, Bram Moolenaar
Hi James!
+1 for the whole idea. I'd like to make my improvedft plugin easier to
use.

Best,
Christian
--
Es ist verboten etwas zu verbieten.

James McCoy

unread,
Jul 29, 2015, 8:37:41 AM7/29/15
to Bram Moolenaar, vim...@googlegroups.com
Just to clarify, was that a suggested replacement for the last bullet in
my description or for the entire interface?

Bram Moolenaar

unread,
Jul 29, 2015, 4:17:40 PM7/29/15
to James McCoy, vim...@googlegroups.com
It would replace the register and variables.

--
GALAHAD hurries to the door and pushes through it. As he leaves the room
we CUT TO the reverse to show that he is now in a room full of bathing
and romping GIRLIES, all innocent, wide-eyed and beautiful. They smile
enchantingly at him as he tries to keep walking without being diverted by
the lovely sights assaulting his eyeballs.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

James McCoy

unread,
Jul 29, 2015, 9:51:56 PM7/29/15
to Bram Moolenaar, vim...@googlegroups.com
On Wed, Jul 29, 2015 at 10:17:25PM +0200, Bram Moolenaar wrote:
> > > How about this alternative, use functions:
> > > getcharsearch() returns a dict with the relevant info
> > > setcharsearch() stores the relevant info
> > >
> > > It should be easier to save and restore the search, while all the
> > > information is present in one place.
> >
> > Just to clarify, was that a suggested replacement for the last bullet in
> > my description or for the entire interface?
>
> It would replace the register and variables.

Updated patch attached.

Cheers,
csearch.diff
signature.asc

Roland Eggner

unread,
Jul 30, 2015, 4:28:26 PM7/30/15
to vim...@googlegroups.com, Bram Moolenaar
Hi James
Hi Bram


On 2015-07-29 Wednesday at 21:51 -0400 James McCoy wrote:
> On Wed, Jul 29, 2015 at 10:17:25PM +0200, Bram Moolenaar wrote:
> > > > How about this alternative, use functions:
> > > > getcharsearch() returns a dict with the relevant info
> > > > setcharsearch() stores the relevant info
> > > >
> > > > It should be easier to save and restore the search, while all the
> > > > information is present in one place.
> > >
> > > Just to clarify, was that a suggested replacement for the last bullet in
> > > my description or for the entire interface?
> >
> > It would replace the register and variables.
>
> Updated patch attached.
> …

> diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
> index d9f49ae..893624a 100644
> --- a/runtime/doc/eval.txt
> +++ b/runtime/doc/eval.txt
> @@ -1822,6 +1822,7 @@ getbufvar( {expr}, {varname} [, {def}])
> any variable {varname} in buffer {expr}
> getchar( [expr]) Number get one character from the user
> getcharmod( ) Number modifiers for the last typed character
> +getcharsearch() Dict last character search
> getcmdline() String return the current command-line
> getcmdpos() Number return cursor position in command-line
> getcmdtype() String return current command-line type
> @@ -1971,6 +1972,7 @@ server2client( {clientid}, {string})
> Number send reply string
> serverlist() String get a list of available servers
> setbufvar( {expr}, {varname}, {val}) set {varname} in buffer {expr} to {val}
> +setcharsearch( {dict}) Dict set character search from {dict}
> setcmdpos( {pos}) Number set cursor position in command-line
> setline( {lnum}, {line}) Number set line {lnum} to {line}
> setloclist( {nr}, {list}[, {action}])
> @@ -3361,6 +3363,26 @@ getcharmod() *getcharmod()*
> character itself are obtained. Thus Shift-a results in "A"
> without a modifier.
>
> +getcharsearch() *getcharsearch()*
> + Return the current character search information as a {dict}
> + with the following entries:
> +
> + char character previously used for a character
> + search (|t|, |f|, |T|, or |F|); empty string
> + if no character search has been performed
> + forward direction of character search; 1 for forward,
> + 0 for backward
> + until type of character search; 1 for a |t| or |T|
> + character search, 0 for an |f| or |F|
> + character search

Instead of “forward” and “until” entries having an entry “command” with the four
legal values “f” “F” “t” “T” would be easier to memorize.

What do you think?

> +
> + This can be useful to always have |;| and |,| search
> + forward/backward regardless of the direction of the previous
> + character search: >
> + :nnoremap <expr> ; getcharsearch().forward ? ';' : ','
> + :nnoremap <expr> , getcharsearch().forward ? ',' : ';'

Exactly this usage would be my first addition to my vimrc after rebuilding vim
with this patch applied. Adjusted for the variant I proposed above:

:nnoremap <expr> ; getcharsearch().command =~# /[ft]/ ? ';' : ','
:nnoremap <expr> , getcharsearch().command =~# /[FT]/ ? ',' : ';'

For string search repetition we have
:nnoremap n /<CR>
:nnoremap N ?<CR>
but the analogy with “f<CR>” “F<CR>” does not work. Therefore this patch seems
very useful to me.

Thank you!



--
Best regards,
Roland Eggner

James McCoy

unread,
Jul 30, 2015, 6:45:34 PM7/30/15
to vim...@googlegroups.com, Bram Moolenaar
On Thu, Jul 30, 2015 at 10:28:16PM +0200, Roland Eggner wrote:
> On 2015-07-29 Wednesday at 21:51 -0400 James McCoy wrote:
> > +getcharsearch() *getcharsearch()*
> > + Return the current character search information as a {dict}
> > + with the following entries:
> > +
> > + char character previously used for a character
> > + search (|t|, |f|, |T|, or |F|); empty string
> > + if no character search has been performed
> > + forward direction of character search; 1 for forward,
> > + 0 for backward
> > + until type of character search; 1 for a |t| or |T|
> > + character search, 0 for an |f| or |F|
> > + character search
>
> Instead of “forward” and “until” entries having an entry “command” with the four
> legal values “f” “F” “t” “T” would be easier to memorize.
>
> What do you think?

Interesting idea, but the current functionality allows one to easily control a
single aspect of the search without needing to know the rest.

Currently, to set/reverse the direction I can just

:call setcharsearch({'forward': 1})
or

:call setcharsearch({'forward': !getcharsearch().forward})

respecitvely without needing to know what type of character search is in
effect. Using your proposal turns the above into something like

:call setcharsearch({'command': tolower(getcharsearch().command)})

and

:call setcharsearch({'command': tr(getcharsearch().command, 'tfTF', 'TFtf')})

That seems more unwieldy to me.
signature.asc

Roland Eggner

unread,
Jul 31, 2015, 3:47:00 AM7/31/15
to vim...@googlegroups.com, Bram Moolenaar
Yes in this usage examples I see the advantage of your variant.

“f” or “t“ → “getcharsearch().forward == 1” having the effect of “true“ in
expressions matches intuition, but “until” seems to me rather difficult to
memorize.

Could you imagine {dict} entry name “exlusive” instead of “until”, with the same
values? Or “inclusive” with the values swapped?

Thank you.
Reply all
Reply to author
Forward
0 new messages