4

I know this can look a lot like a duplicate of Vim wrap only current line, but none of the answers give a real solution to the original problem, as all of them state that per-line soft wrapping is not possible, proposing alternatives like hard wrapping the line and undoing the change afterwards, or showing the wrapped line in an ad-hoc buffer.

Furthermore, 6 years have passed, Vim has improved, and I wonder if new solutions exist.

A strategy that looks promising to me is to have an autocmd CursorHold showing a popup populated by the current line only, with horizontal scrolling taking into account stuff I use all the time, like number, relativenumber, list lcs.

Leaving aside for now the autocmd/augroup part of the strategy, what I've come up with is the following,

function! Foo()
  call popup_create(getline('.'),
    \ #{ line: 'cursor', col: screencol() - virtcol('.') + 1, moved: [line('.'), 0, col('$')], })
endfunction

which does a pretty good job in terms of formatting, enter image description here

Except that the line is not syntax-colored (the 3 would have to be the same color as the other digits a few lines above).

I've found out that the first argument to popup_create can be a buffer number, which means that popup will be populated with that buffer. This seems useful, but I haven't been able to use it to show only the current line. I can start from the current line, via firstline option, but don't know how to set a final line, as lastline doesn't do the job¹ (probably I don't understand what it is for). Here's the second attempt I'm referring to:

function! Foo()
  call popup_setoptions(
    \ popup_create(
    \   bufnr('.'),
    \   #{ line: 'cursor', col: screencol() - virtcol('.') + 1, moved: [line('.'), 0, col('$')], }
    \ ),
    \ #{ wrap: 1, firstline: line('.')})
endfunction

and here's the result enter image description here

Well, there's also the problem of the background of the popup, but that's likely easier to fix.


(¹) In the sense that I get the same output as the one in second screenshot, whther or not I put lastline: line('.') + 1 or lastline: line('.') in in popup_setoptions's second argument.

2
  • What happens if use lastline: line('.') + 1? Also test without +1. Adding info to the question helps.
    – 3N4N
    Oct 29, 2022 at 10:13
  • 1
    I've clarified what I meant by doesn't to the job. I get the same result.
    – Enlico
    Oct 29, 2022 at 12:23

1 Answer 1

2

So the trick was to use maxheight and compute it based on how much text is on the current line and how much space is in the terminal width.

With the following solution

function! Foo()
  let available_screen = &columns - max([0, screencol() - virtcol('.')])
  call popup_setoptions(
    \ popup_create(
    \   bufnr(),
    \   #{ line: 'cursor', col: screencol() - virtcol('.') + 1, moved: [line('.'), 0, col('$')], }
    \ ),
    \ #{
    \    wrap: 1,
    \    firstline: line('.'),
    \    maxheight: float2nr(ceil(len(getline(line('.')))*1.0/available_screen)),
    \    scrollbar: 0
    \  })
endfunction

nnoremap <silent> <Leader>sb :call Foo()<cr>

(and temporarily changing moved to [0, 0, 0] to make popups permanent), I obtained this result: enter image description here For reference, this is without the popups: enter image description here

Clearly, when hitting the left border of the terminal, the popup has to stop moving left and so it is not aligned with the underlying text, but I think this can't be avoided (unless manually wrapping words back on previous lines).

5
  • If/when you finish the code for wrapped lines, I'll be curious to see it
    – D. Ben Knoble
    Dec 1, 2022 at 21:30
  • 1
    @D.BenKnoble, so you're not referring to the solution in the first screenshot in this answer. Maybe you're referring to something like this? If so, then that's a variation of this which requires little change to the code. Both variations are in review here.
    – Enlico
    Dec 2, 2022 at 6:51
  • Sorry, should have been more clear: I meant if you wrap this up in a script or plugin I'd be curious to look at it or try it
    – D. Ben Knoble
    Dec 2, 2022 at 14:38
  • @D.BenKnoble, still, you just need to copy the code from there, put it in your vimrc, load, and let the cursor on some non-totally-visible line. I could put the two variants of the solution under an option and make a plugin... Why not.
    – Enlico
    Dec 2, 2022 at 14:41
  • 1
    @D.BenKnoble, here it is. Please, feel free to give some feedback. You can set g:softwrap_unwrap to v:false (default) or v:true in your vimrc to keep the popup in the current window or let it overflow. That's the only customization point at the moment.
    – Enlico
    Dec 2, 2022 at 16:11

Your Answer

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

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