删除向后连续的空白或连续的非空白直到行首

Delete backwards contiguous whitespace or contiguous non-whitespace upto beginning of line

Vim 经常创建包含大量连续空格的行,所以我很惊讶没有一种简单的方法可以向后删除直到前一个单词结束。我是否漏掉了一些明显的东西?

hello this is a line       |

删回这里:

hello this is a line|

或光标前有非空白:

hello this is a line|

删回这里:

hello this is a |

这样我就可以在插入模式下映射一个键,然后返回删除单词或非单词。

虽然 vim 不附带这样的命令,但它附带的命令非常接近您想要的命令:gegE,请在的帮助。幸运的是,这意味着将它们包装在以下正常、可视和运算符挂起的映射中是微不足道的:

noremap <expr> <leader>e 'h'.v:count1.'gel'
noremap <expr> <leader>E 'h'.v:count1.'gEl'
onoremap <expr> <silent> <leader>e ':<c-u>normal! vh'.v:count1.'gel<cr>'
onoremap <expr> <silent> <leader>E ':<c-u>normal! vh'.v:count1.'gEl<cr>'

显然将它们映射到您想要的任何位置,我个人将第一个映射到 <BS>。 e 和 E 之间的区别在于它们分别调用 ge(移动 word)和 gE(移动 WORD)。有关其含义的详细信息,请参阅 :h word:h WORD

这些并不完全符合您的要求:它们不会根据我们开始时的位置进行调整,例如使用此运算符删除将更改

this is a line|

this is a|

而不是

this is a |

如果您想编写更复杂的 vim 脚本,您当然可以解决这个问题,但是对于一个 space.

来说,这几乎不值得

如果这让您感到困扰,则由等待运算符的地图移动的内容也会根据 'selection' 的值进行微妙的更改。

编辑:这就是我创建所要求的确切解决方案的方式

function! s:Backup(mode)
  let str  = a:mode == 2 ? 'g' : ''
  let str .= a:mode ? 'v' : ''

  let at_end = col('.') >= col('$') - 1
  let str .= getline('.') =~ '\%'.(col('.') - !at_end).'c\S' ? 'b' : 'gel'
  let str .= !at_end && a:mode == 1 ? 'oho' : ''

  execute 'normal!' str
endfunction

这不会自行删除,而是与任何 vim 命令组合,例如 dyc 运算符,并且适用于所有只要您传递正确的参数即可。要复制提问者答案中使用的映射:

inoremap <silent> <c-b> <c-o>d:<c-u>call <SID>Backup(1)<cr>

这里是 <leader>e

上正常、可视、等待操作员模式的绑定
nnoremap <silent> <leader>e :<c-u>call <SID>Backup(0)<cr>
onoremap <silent> <leader>e :<c-u>call <SID>Backup(1)<cr>
xnoremap <silent> <leader>e :<c-u>call <SID>Backup(2)<cr>

N.B。映射必须在与使用 s:<SID> 的函数相同的脚本中定义,否则请删除它们。

编辑 2:修复了函数名称:/
编辑 3:调整为在不在行尾时修复操作。显然 vim 认为光标在行尾追加时与插入时不同。

好的,这个函数可以满足我的需要:

function! BackspaceContiguousInsertMode()
python << EOF
import vim  
try:
    line = vim.current.line
    row, deleteto = vim.current.window.cursor
    if deleteto==0:
        vim.current.line = ""
        vim.command("startinsert")
    elif line[deleteto] == " ":
        deletefrom=deleteto
        while deletefrom-1>0 and vim.current.line[deletefrom-1] == " ":
            deletefrom=deletefrom-1
        vim.current.line=line[:deletefrom] + line[deleteto+1:]
        if len(line)-1 == deleteto:
            vim.current.window.cursor = (row,deletefrom+1)
            vim.command("startinsert!")
        else:
            vim.current.window.cursor = (row,deletefrom)
            vim.command("startinsert")
    else:
        eol=deleteto+1 >= len(line)
        if not eol and line[deleteto+1] != " ":
            trailingline = line[deleteto+1:]
            vim.current.line=line[:deleteto+1] + " " + trailingline
            vim.command("normal diw")
            leadingto=len(vim.current.line)-len(trailingline)-1
            vim.current.line=vim.current.line[:leadingto] + trailingline
            vim.command("startinsert")
        elif eol:    
            vim.command("normal diw")
            vim.command("startinsert!")
        else: 
            vim.command("normal diw")
            vim.command("startinsert")

except Exception as e:
    print("Error: {}".format(e))
EOF
endfunction
inoremap <C-b> <Esc>:call BackspaceContiguousInsertMode()<CR>

从插入模式(这是我想从中调用它的地方)我可以按 <C-b> 将每个单词块或空白块删除到行的开头。给定以下行,每次我按 <C-b> 都会发生这种情况:

alskdjf       a;sjdf a kjkdjd        |kja sdf
alskdjf       a;sjdf a kjkdjd|kja sdf
alskdjf       a;sjdf a |kja sdf
alskdjf       a;sjdf a|kja sdf
alskdjf       a;sjdf |kja sdf
alskdjf       a;sjdf|kja sdf
alskdjf       a;|kja sdf
alskdjf       a|kja sdf
alskdjf       |kja sdf
alskdjf|kja sdf
|kja sdf
|... (stays on the same line)