在任意宽度的窗口中,使用Vim软换行使每行限制在80个字符以内

156
我想使用Vim的软换行功能(:set wrap)在80个字符处换行代码,而不考虑我的实际窗口宽度。目前还没有找到方法来实现这一点-所有软换行似乎都与窗口的宽度有关。 textwidthwrapmargin都是用于硬换行(它们将换行符插入文件中)。垂直分割为多个窗口并在其中一个窗口上使用:vertical resize 80(可能需要:set breakat=以允许在任何字符上断开)有点像可以工作(即使有些hackish),但当使用:set number时会出问题,因为行号占用可变数量的列(取决于文件长度),这些列是80的一部分。有没有办法在vim中实现这一点呢? 根据其他来源,看起来不太乐观。现在我的近似值只是将/^.\{80}\zs.\+作为默认搜索,这样至少可以高亮显示。我想过为它添加一个:syntax项,但当它重叠其他语法项时就会失败,所以我放弃了那个想法。

你是如何设置默认搜索的? - thethinman
我通常最终只是使用:vsplit并调整右侧分屏的大小,以使左侧分屏达到我想要的大小... - fbence
6个回答

46

您可以通过:set numberwidth=6设置行号列的最小宽度,

  • 然后您可以使用:set columns=86(或鼠标)调整窗口大小到合适的大小。

如果您编辑一个有一百万行的文件,您可能会遇到问题,但这是不太可能的。这种方式浪费了屏幕6列的空间,因此仍然存在各种问题。

您可以使用:match来突出显示80列以后的内容,就像这里这里所说的那样。

除此之外,我看不到其他的方法。虽然似乎这将是一个不错的功能。


不幸的是,如果窗口被调整大小,vim不会保留列设置。这导致在平铺式窗口管理器中出现了一个不幸的情况,即如果窗口太宽,就没有好的软换行到80列的方法。 - gravitation
这个有效,但不粘性。我猜下一步是设置一个autocmd来保持你想要的文件类型的列的新大小。 - xer0x
2
这是正确的答案,因为它确认了你不能做到。我相信我不是唯一一个不想为此调整终端窗口大小的人。我希望有更多的宽度用于非 vim 使用。 - Sridhar Sarnobat

28

试试这个:

set columns=80
autocmd VimResized * if (&columns > 80) | set columns=80 | endif
set wrap
set linebreak
set showbreak=+++

如果您希望始终只有80个列,可以删除if (&columns > 80) |


在我的iTerm终端上,这会使窗口变小。我不确定是否是我的环境有问题(我看到你正在做自动调整大小的事情),但否则这是不可取的。谢谢您的建议。 - Sridhar Sarnobat
自动命令对我来说很完美(使用guake终端)。 - mzcarlos
在 Alacritty 中与 Tmux + NeoVim 完美结合,表现得非常好。 - meh

18

我对软换行没有解决方案,但是从 Vim 7.3 开始(发布于2010-08-15),:set colorcolumn=80 命令可以突出显示第 80 列。颜色取决于您的语法文件。

请参阅Vim 80列布局问题:h colorcolumn


引号不是有效的URL,因此它是有意义的。锚文本不应包含无效的URL字符,因此SO不应修复其他站点开发者的错误。 - Shadow The Spring Wizard
1
Shadow Wizard提到了我之前的回答,当时我在想如何使用Markdown在URL中放置单引号。然后ib建议使用%27,这行得通。谢谢,ib。 - ftvs
最近发现了如何仅突出显示80列之后的列::let w:eighty_column_match = matchadd('ColorColumn', '\%81v.\+', 100) - rampion
“colorwidth” 这个东西还有其他用处,所以我很高兴你发布了这个。 - Sridhar Sarnobat

3
将以下文本翻译成中文:

eborisch的答案与我在这里找到的其他答案以及我必须解决的问题相结合,我想出了以下两部分解决方案:

第一部分使得编辑长行文本更加容易:

" Allow enabling by running the command ":Freeform", or <leader>sw
command! Softwrap :call SetupSoftwrap()
map <Leader>sw :call SetupSoftwrap() <CR>

func! SetupFreeform()
  " Use setlocal for all of these so they don't affect other buffers

  " Enable line wrapping.
  setlocal wrap
  " Only break at words.
  setlocal linebreak
  " Turn on spellchecking
  setlocal spell

  " Make jk and 0$ work on visual lines.
  nnoremap <buffer> j gj
  nnoremap <buffer> k gk
  nnoremap <buffer> 0 g0
  nnoremap <buffer> $ g$

  " Disable colorcolumn, in case you use it as a column-width indicator
  " I use: let &colorcolumn = join(range(101, 300), ",")
  " so this overrides that.
  setlocal colorcolumn=

  " cursorline and cursorcolumn don't work as well in wrap mode, so
  " you may want to disable them. cursorline highlights the whole line,
  " so if you write a whole paragraph on a single line, the whole
  " paragraph will be highlighted. cursorcolumn only highlights the actual
  " column number, not the visual line, so the highlighting will be broken
  " up on wrapped lines.
  setlocal nocursorline
  setlocal nocursorcolumn
endfunc

仅使用这个功能,您就可以得到像Markdown或Readme这样的文本自动换行的效果。
正如其他答案中指出的那样,要在精确的列宽处进行换行,需要告诉vim有多少列,并在每次调整vim大小时覆盖该值:
command! -nargs=? Draft :call SetupDraftMode(<args>)
func! SetupDraftMode()
  " I like 80 columns + 4 for line numbers
  set columns=84
  autocmd VimResized * if (&columns > 84) | set columns=84 | endif

  :Softwrap
endfunc

这还有几个问题:
  • 在调用set columns之后,vim不会清除屏幕外的列,我无法弄清如何告诉它这样做,所以最好在打开vim后立即调用此命令
  • 打开vim时,它会显示一个带有版本号和一些有用命令的提示符,因此这些内容不会被清除。您可以添加set shm+=I来禁用该提示符
  • 您不能打开任何垂直分割,因为然后两个分割线都将是约40列。您需要将列设置为您所需宽度的2倍,并始终保持分割线打开。
  • 我的vimscript很糟糕,但理想情况下,有人可以修改上面的Draft函数以接受列宽作为参数,或使用全局变量(g:explicit_vim_width?),如果您的窗口大小更改,则可以手动设置。

3

你尝试过使用 'linebreak' 吗?

        *'linebreak'* *'lbr'* *'nolinebreak'* *'nolbr'*
  'linebreak' 'lbr' boolean (default off)
        local to window
        {not in Vi}
        {not available when compiled without the  |+linebreak|
        feature}
If on Vim will wrap long lines at a character in 'breakat' rather
than at the last character that fits on the screen.  Unlike
'wrapmargin' and 'textwidth', this does not insert <EOL>s in the file,
it only affects the way the file is displayed, not its contents.  The
value of 'showbreak' is used to put in front of wrapped lines.
This option is not used when the 'wrap' option is off or 'list' is on.
Note that <Tab> characters after an <EOL> are mostly not displayed
with the right amount of white space.

3
“breakat”只是一个模式(不是一个长度),所以我不知道如何使用它来强制在80个字符处软换行。 - rampion
嗯,我在想是否有可能创建一个正则表达式,可以匹配总长度(加上中间的空格)小于或等于n个字符的单词。 - Shane Creighton-Young
@ShaneCreighton-Young:对于使用软制表符/扩展制表符的人来说,^.{,80}\b就可以了。请注意,这是Perl正则表达式,而不是Vim正则表达式。 - Mark K Cowan
@MarkKCowan Vim的等价命令是 ^.\{,80}\zs - tejasvi88
@ShaneCreighton-Young 实际上,我刚试了一下,看起来 breakat 只是普通的字符字符串,而不是正则表达式模式。 - tejasvi88

-1

没有好的方法来做这件事。如果我们修改@eborisch的答案,我们可以使用autocmd来实现一个临时的setlocal softwrap。如果我们每次进入缓冲区时都调整大小,并在设置本地变量softwrap时调整到特定长度,我们就可以得到所需的行为。

假设我们想要将软换行设置为80列,我们可以在.vimrc中编写以下内容。

augroup softwrap
    autocmd VimResized * if (exists('b:softwrap') && &columns > 80) | set columns=80 | endif
    autocmd BufEnter * set columns=999
augroup END

要为特定缓冲区打开模式,请使用以下命令:

let b:softwrap=1
set columns=80

这只是把我的文件变成了无意义的乱码。 - Suuuehgi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接