3

I would like to:

  1. First, save the current highlight state (nohlsearch? or hlsearch?).

  2. ...the current cursor position and the current search pattern.

  3. Then search for the trailing spaces, highlighting those and also be able to move around them.

  4. Once done, turn OFF the trailing space highlighting and revert back to whatever the highlight state was (same search pattern, same highlighted characters).

For example:

Let's search for the word "line" by typing /line in the command line. The word line lights up across the document.

Now I would like to run ShowWhiteSpace('ON') so now the word(s) "line" are no longer highlighted, but the trailing spaces are. By pressing N or n I can move around the trailing space sections.

Finally I would like to run ShowWhiteSpace('OFF') so now the trailing spaces are no longer highlighted and we are back at where we have started with the word(s) line highlighted and our cursor at it's original position.

What I have so far:

  • I know that I can save the current search pattern and restore it through the @/ variable.

  • I also know how to store the cursor position so I can restore it.

The problems start when I attempt to track the hlsearch state. echo &hlsearch would return 0 if the current hl state is set using the :set nohlsearch command or 1 if the :set hlsearch command is used.

However, in cases where :nohl is used, there is no way to know if there was a highlighted situation prior to executing the ShowWhiteSpace('ON') command.

One possible solution is to give up trying to store and restore the hlsearch state all together and simply restore the search pattern. Which works, however, once the trailing spaces are lit-up and N or n is used to move around them, the hlsearch seems to be OFF once we restore the search pattern.

Any clean methods to handle a slightly more complex TrailingSpace scenario?

P.S: I know that I can use match ExtraWhitespace /\s\+$/ and a syntax highlighting, however, that would not give me the option to move around the highlighted trailing space regions.

  • 1
    This question and the answer actually helps: What is the functional difference between :nohlsearch and :set nohlsearch? According to that post, v:hlsearch is a more reliable way to track the hlsearch state. – mbilyanov Mar 29 '16 at 16:26
  • 1
    @user9433424 Thanks. That is a fresh point of view, however, I am worried that location list or quickfix list might introduce issues related to other plugins using those resources and might be an overkill for just dealing with trailing spaces. – mbilyanov Mar 29 '16 at 16:54
  • 1
    If you're not familiar with the command window, try q/. (NB: That's q/ in normal mode, not :q/.) – Wildcard Mar 29 '16 at 20:23
  • 2
    @symbolix It's probably best if you post your answer as an answer (and then accept it), rather than as an edit to the question. Answering your own question is fine, and this has the benefit of helping future visitors (who may now think that the question has no answer), and helps current visitors who can now easily see that this question has been solved. – Martin Tournoij Mar 29 '16 at 21:00
  • 2
    Why exactly do you want to jump from trailing space to trailing space? – romainl Mar 29 '16 at 21:08
2

The comments posted below the question and the function that I am adding at the end of this post should be enough as an answer to the topic.

I am adding my initial function below, as the answer:

function! ToggleTrailingSpace()
    " Initialize variables.
    if !exists('g:storedSearchPattern')
        let g:storedSearchPattern = ""
    endif
    if !exists('g:storedHlsearchState')
        let g:storedHlsearchState = 0
    endif
    if !exists('g:isTrailingSpaceActive')
        let g:isTrailingSpaceActive = 0
    endif
    if !exists('g:storedCursorPosition')
        let g:isTrailingSpaceActive = 0
    endif
    " Debug.
    let l:hl_state = v:hlsearch ? 'TRUE' : 'FALSE'
    echom 'Current hlsearch state: [' . l:hl_state . ']'
    if !g:isTrailingSpaceActive
        " Debug
        echom 'Highlight trailing space: [ON]'
        " Store current states.
        let g:storedHlsearchState = v:hlsearch
        let g:storedSearchPattern = @/
        let g:storedCursorPosition = getpos('.')
        "Debug.
        echom 'Stored search pattern: ['. g:storedSearchPattern . ']'
        echom 'Stored hlsearch state: [' . g:storedHlsearchState. ']'
        echom 'Stored position: ' . string(g:storedCursorPosition) . ']'
        " Override the search pattern.
        let @/='\v(\s+$)|( +\ze\t)'
        " Override the hlsearch state
        let &hlsearch=1
        " Activate the syntax for the trailing space pattern.
        exe 'match ErrorMsg /\s\+$/'
        " Update toggle controller.
        let g:isTrailingSpaceActive = 1
    else
        echom 'Highlight trailing space: [OFF]'
        " Debug
        echom 'Restore the search pattern to: ['. g:storedSearchPattern . ']'
        echom 'Restore the hlsearch state to: [' . g:storedHlsearchState. ']'
        echom 'Restore the position to: ' . string(g:storedCursorPosition) . ']'
        " Restore
        let @/=g:storedSearchPattern
        let &hlsearch=g:storedHlsearchState
        call setpos('.', g:storedCursorPosition)
        " Activate the syntax for the trailing space pattern.
        exe "match ErrorMsg '' | syn clear ErrorMsg"
        " Update toggle controller.
        let g:isTrailingSpaceActive = 0
   endif
endfunction
  • @Carpetsmoker I should be able to mark this as answered in 2 days. – mbilyanov Mar 29 '16 at 21:08
  • 1
    The problem with this solution is that once the trailing space is highlighted, as a search cheat, and we invoke another search on top of that with /{pattern then things are going to get messy :) I guess, a clean solution would be a quite complex one. So probably only keeping the trailing space highlighted and give up the GoToNextTrailingSpace functionality is the best option. – mbilyanov Mar 29 '16 at 21:33
2

An alternative to use a custom function is to use Vim built functionality:

  1. First, save the current highlight state (nohlsearch? or hlsearch?).
  2. ...the current cursor position and the current search pattern.

Vim saves the current search pattern; you could navigate through your previous searches (similar to navigating to your previous commands on Vim or a shell). That could be achieved with the arrow keys up/down, ctrl+n/p or q/.

You could use a mark (see :help mark-motions) to remember the current position (e.g.: mz) and them jump back to it later ('z).

  1. Then search for the trailing spaces, highlighting those and also be able to move around them.

You could use a simple mapping to make it easier than type the regex and set the highlight option:

nnoremap <F3> :let @/='\v(\s+$)<bar>( +\ze\t)' <bar> set hlsearch<cr>
  1. Once done, turn OFF the trailing space highlighting and revert back to whatever the highlight state was (same search pattern, same highlighted characters).

You could retrieve your previous search easily, as explained above. You could also toggle the 'hlsearch' using the mapping coh, which is provided by the plugin unimpaired.

This approach has the advantage that you don't have to change your workflow to remember or wait until you finished handling the trailing spaces before making other searches.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.