1

Background

  • vim 7.4
  • VimL scripting problem

Question

Does VimL have a means of polling the current Visual selection?

Goal

  • Trevor wishes to create a function in VimL script that does one thing only.

    • return TRUE if there is currently a visual selection containing one or characters in the currently-active buffer.
    • return FALSE if there is not currently a visual selection containing one or more characters in the currently-active buffer.
  • The function will be an addon to other functions that need to exhibit different behavior, depending on whether or not there is a currently-non-empty Visual selection (either line-wise or character-wise) in the currently-active buffer.

Failed attempts

  • For some reason this is not coming through in the docs, no existing solution seems readily apparent, and it seems like a pretty basic thing.
4
  • Ask about your goal, not about your failed means. Commented Apr 8, 2015 at 18:55
  • //Ask about your goal, not about your failed means// The goal is precisely explained under the Goal header. To create a function that returns True if there is an existing visual selection, and False if there is not an existing visual selection. Commented Apr 8, 2015 at 18:57
  • No, that's not your goal. Commented Apr 8, 2015 at 19:00
  • //No, that's not your goal.// Uhhmm ... yes it is. Unambiguously and unconditionally so. Please note this is StackOverflow and contributions to this site are expected to be constructive and of high-quality. Unsubstantiated claims that do not demonstrate familiarity with the subject matter do not meet that threshold. Commented Apr 8, 2015 at 19:58

2 Answers 2

4

I believe the mode() function is what you are looking for. (From :h mode())

                                                        mode()
mode([expr])    Return a string that indicates the current mode.
                If [expr] is supplied and it evaluates to a non-zero Number or
                a non-empty String (non-zero-arg), then the full mode is
                returned, otherwise only the first letter is returned.  Note
                that " " and "0" are also non-empty strings.

                        n       Normal
                        no      Operator-pending
                        v       Visual by character
                        V       Visual by line
                        CTRL-V  Visual blockwise
                        s       Select by character
                        S       Select by line
                        CTRL-S  Select blockwise
                        i       Insert
                        R       Replace R
                        Rv      Virtual Replace gR
                        c       Command-line
                        cv      Vim Ex mode gQ
                        ce      Normal Ex mode Q
                        r       Hit-enter prompt
                        rm      The -- more -- prompt
                        r?      A :confirm query of some sort
                        !       Shell or external command is executing
                This is useful in the 'statusline' option or when used
                with remote_expr() In most other places it always returns
                "c" or "n".
                Also see visualmode().

If will return v, V or CTRL-V if you are in a visual mode.

However this function almost always returns c or n since a visual selection ends immediately when an ex command is run. You can determine where the visual selection was by using the marks '< and '>. You can also determine if you were in a visual function by using xnoremap commands that pass a flag to the function to say you were in visual mode.


If you put your function in a mapping mode() seems to work properly.

Sign up to request clarification or add additional context in comments.

8 Comments

// However this function almost always returns c or n since a visual selection ends immediately when an ex command is run // this sounds like a catch-22 since the goal is to get a function that returns either "true" or "false" only.
@dreftymac it would almost always return false, (if you wrote a wrapper function). Most functions are executed after the visual selection has ended. You probably need to look for an alternate method for what you are doing
OK, just to clarify. The current understanding is, if a visual selection is made, (using ggVG for example) and someone immediately does :<,>:call MyCustomFunction you're saying that MyCustomFunction will terminate the Visual mode selection?
@dreftymac correct. If you call mode inside MyCustomFunction it will return n
If you run your main function from an <expr> mapping then mode() will work correctly: xnoremap <expr> MyFunction()
|
2

As your question is about polling, the strict answer is mode(). But polling only happens during status line evaluation, or in triggered :autocmd event handlers.

If the other function that you're vaguely referring to is invoked by a custom mapping or command, mode() doesn't help you, as visual mode has already been left by the time your function is invoked. The right way™ to handle visual selections for this is as follows:

  • Custom commands should work on a supplied range, and that range can be generated from a visual selection; Vim will automatically prepend the :'<,'> range for you. In rare cases, you may want to create a special command to work on the visual selection, e.g. :Frobnize vs. :FrobnizeVisual, and then just use :normal! gv to get and work on the selection.
  • Separate custom mappings can be defined for normal and visual mode, and pass information as a flag to the invoked function:
:nnoremap <Leader>x :<C-u>call Frobnize(0)<CR>
:xnoremap <Leader>x :<C-u>call Frobnize(1)<CR>
function! Frobnize( isVisualMode )
    ...

TL/DR: There's a reason you didn't find such convenient function; rethink your approach.

4 Comments

//rethink your approach// The approach here is to find a simple, unambiguous way to return "true or false" ... as this is a very specific and very pintpointed question on VimL programming. Putting such a function to practical use is another matter. However, your point about mode() is well taken. If a specific "practical use-case" is required in order for this question to make sense, consider this one: a user wishes to use a single function that applies ROT13 to the currently-selected text, or the entire line if there is no current selection
Addressing your use case: 1. users usually don't invoke functions (too cumbersome), they prefer either custom commands or mappings. 2. Let's assume it's still a function. In order to invoke that, you'd have to go through command-line mode, so the "current" mode (visual or entire line) is lost; that's how Vim's modes work, and that's why it has to be done as I've written in my answer.
//1. users usually don't invoke functions (too cumbersome), they prefer either custom commands or mappings.// Respectfully, this is obvious. Those custom commands or mappings have to exhibit some functionality, right? That functionality comes (at least partially) from functions written in VimL script (or any of various other scripting languages if compiled into Vim, depending on the install settings.
// you'd have to go through command-line mode, so the "current" mode (visual or entire line) is lost [...] it has to be done as I've written in my answer// Your answer reflects one of many ways to do it. For example, even if the Visual selection is lost, there are multiple ways to target a particular region of text in Vim, including setting markers. Also, as @DaanBakker already pointed out in another comment; <<If you run your main function from an <expr> mapping then mode() will work correctly>>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.