8

When searching for a phrase in hard-wrapped text, one wants newlines to be treated as spaces. Can one have that happen? Saying /the\_sphrase\_sI\_sseek is a bit awkward.

Toothrot
  • 3,129
  • 13
  • 27
  • 2
    See this answer: http://unix.stackexchange.com/a/11848 for a custom function (and command) that does what you want. Adjust to your taste. – VanLaser Feb 26 '16 at 11:52
  • 1
    The problem with this solution is that it can't make use of incremental search. But cmap <m-space> \_s\+ works well (in nvim). – Toothrot Feb 26 '16 at 15:53
  • Whatever floats your boat is ok :) – VanLaser Feb 26 '16 at 17:19

2 Answers2

2

You can automatically replace a space with \_s when searching with:

cnoremap <expr> <Space> index(['/', '?'], getcmdtype()) > -1 ? '\_s' : ' '

Because cnoremap is applied to all the commandline (and not just search), we need an expression mapping to check if we're searching or in another commandline mode (e.g. :).


Because you probably don't always want to search like this, you can trigger this newline-insensitive mode with something like:

fun! StartNewlineSearch()
    cnoremap <expr> <Space> index(['/', '?'], getcmdtype()) > -1 ? '\_s' : ' '

    " Unmap both <Space> and this same mapping when pressing <CR>
    cnoremap <CR> <CR>:cunmap <lt>Space><CR>:cunmap <lt>CR><CR>:cunmap <lt>Esc><CR>

    " And the same for <Esc>
    cnoremap <Esc> <Esc>:cunmap <lt>Space><CR>:cunmap <lt>CR><CR>:cunmap <lt>Esc><CR>
endfun

nnoremap // :call StartNewlineSearch()<CR>/

When pressing // it maps <Space> to \_s, and it unmaps it when pressing <CR> or <Esc>.


You could also map this to a key to toggle the two "modes":

let g:search_mode = 0
fun! ToggleMode()
    if g:search_mode == 0
        cnoremap <expr> <Space> index(['/', '?'], getcmdtype()) > -1 ? '\_s' : ' '
        let g:search_mode = 1
    else
        cunmap <Space>
        let g:search_mode = 0
    endif
    return getcmdline()
endfun

cnoremap <C-@> <C-\>eToggleMode()<CR>
Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
0

The other answser is certainly great.

However, I've found that it has one weakpoint, which is not necessarily negligible: if you abort the special search, i.e. you press //(changed your mind)Escape, you'll get E385: Search hit BOTTOM without match for: ; afterwards you'll get the same error even for plain /Escape, which is a bit annoying.

Probably the fix is easy, but I wanted to explore other ways of solving the same problem, so I came up with another solution:

fun! EnableAutocmdToUnmapSpace()
  augroup UnmapSpaceAug
    autocmd!
    autocmd CmdLineLeave,CmdWinEnter / cunmap <space>
    autocmd CmdLineLeave,CmdWinEnter \? cunmap <space>
  augroup END
endf
fun! s:ctrlSMakesSpaceEOLFriendly()
  augroup UnmapSpaceAug
    autocmd!
  augroup END
  cnoremap <expr> <silent> <C-S> execute(':cnoremap <lt>space> \_s\+\| call EnableAutocmdToUnmapSpace()')
endf
augroup EOLFriendlySpace
  autocmd!
  autocmd CmdLineEnter,CmdWinLeave / execute(':call s:ctrlSMakesSpaceEOLFriendly()')
  autocmd CmdLineEnter,CmdWinLeave \? execute(':call s:ctrlSMakesSpaceEOLFriendly()')
  autocmd CmdLineLeave,CmdWinEnter / cunmap <C-S>
  autocmd CmdLineLeave,CmdWinEnter \? cunmap <C-S>
augroup END

It is slighly longer, but it doesn't suffer the issue I described above. And it works differently:

  • when you start your search with /, Space behaves normally,
  • but if you hit Ctrl-S, then
    1. Space is cnoremapped to \_s\+,
    2. and an autocmd is activated to cunmap it;
  • quite importantly, before mapping Ctrl-S, we first clear the autocmd of point 2 above, because we don't want to cunmap <space> on subsequent searches where we don't hit Ctrl-S.
  • leaving the search cunmaps Ctrl-S.
  • CmdWinEnter is treated as CmdLineLeave and CmdWinLeave as CmdLineEnter, for the reason explained here; it is fundamentally depending on an implementation detail, but that's necessary to deal with the case that you hit / from within the command window, e.g. if you do /Ctrl+F/ from normal mode.
  • To make things work for ?, the autocmd needs that you write \?, not ?, as explained here.
Enlico
  • 2,194
  • 15
  • 31