如何从Vim'中永久删除特定条目;是否在不丢失最近编辑的文件的更改列表的情况下创建命令行历史记录?

如何从Vim'中永久删除特定条目;是否在不丢失最近编辑的文件的更改列表的情况下创建命令行历史记录?,vim,Vim,当我们执行Vim Ex命令时,它会保存在命令行历史记录中,我们可以通过使用q:打开命令行窗口来访问该历史记录 然而,有时,我希望能够永久删除其中一些。例如,如果我执行命令:a,则命令行窗口中的所有后续命令都会被识别为语法组vimsert的元素,该语法组链接到高亮显示组String,该组在我的配色方案中以青色显示 为了修复语法突出显示,我可以尝试从命令行窗口中删除:点击dd,删除一个命令,但只有在打开窗口时才删除该条目。一旦我关闭它,稍后再重新打开它,:a命令就会返回。为了使删除永久化,我尝试在我

当我们执行Vim Ex命令时,它会保存在命令行历史记录中,我们可以通过使用
q:
打开命令行窗口来访问该历史记录

然而,有时,我希望能够永久删除其中一些。例如,如果我执行命令
:a
,则命令行窗口中的所有后续命令都会被识别为语法组
vimsert
的元素,该语法组链接到高亮显示组
String
,该组在我的配色方案中以青色显示

为了修复语法突出显示,我可以尝试从命令行窗口中删除
:点击
dd
,删除一个
命令,但只有在打开窗口时才删除该条目。一旦我关闭它,稍后再重新打开它,
:a
命令就会返回。为了使删除永久化,我尝试在我的
vimrc
中添加一个autocmd:

augroup my_cmdline_window
    au!
    au CmdWinLeave * call s:update_history()
augroup END

fu! s:update_history() abort
    let new_hist = getline(1, '$')
    call histdel(':')
    for i in new_hist
        call histadd(':', i)
    endfor
endfu
它调用一个函数,该函数在关闭命令历史记录之前,通过从当前窗口读取命令历史记录来更新命令历史记录。它在当前Vim会话运行时工作,但一旦我退出它然后启动一个新会话,所有删除的条目都会返回

我认为,删除操作不会在会话间持续存在的原因是,当我退出会话时,Vim会将当前命令行历史记录与存储在
~/.viminfo
中的命令行历史记录合并

let hist = filter(getline(1, '$'), 'v:val !~# "^\\s*$"')
call histdel(':')
for i in hist
    call histadd(':', i)
endfor
call sort(filter(deleted_entries, 'v:val >= 0'))
if empty(deleted_entries)
    return
endif
此文件中保存的内容由
'viminfo'
选项控制。我的
'viminfo'
的值是:

viminfo='100,<50,s10,h
我在
:wviminfo
中添加了一个爆炸,根据
:h:wviminfo

When [!] is used, the old information is not read first,
only the internal info is written.
这似乎是可行的,因为有了这个autocmd,命令行窗口中的条目的删除会在会话中持续进行。但是,它似乎也会删除最近编辑的文件的所有变更列表,因为在启动新的Vim会话之后,它们的所有变更列表都是空的

由于
:h'viminfo
解释了当您在
'viminfo'
中包含
'
项时,变更列表和跳转列表也存储在
~/.viminfo
中,我怀疑使用
:wviminfo>后跳转列表和标记也会丢失

是否有一种方法可以避免更改列表/跳转列表/标记丢失,同时仍然从命令行历史记录中删除任意条目


编辑:

我想到了这个:

augroup my_cmdline_window
    au!
    au CmdWinEnter * let s:old_cmdline_hist = getline(1, line('$')-1)
    au CmdWinLeave * call s:update_history()
augroup END

fu! s:update_history() abort
    let hist = filter(getline(1, '$'), 'v:val !~# "^\\s*$"')

    call histdel(':')
    for i in hist
        call histadd(':', i)
    endfor

    let viminfo = expand('~/.viminfo')
    if !filereadable(viminfo)
        return
    endif

    let info = readfile(viminfo)
    let deleted_entries = filter(copy(s:old_cmdline_hist), 'index(hist, v:val) == -1')

    call map(deleted_entries, 'index(info, ":".v:val)')
    call sort(filter(deleted_entries, 'v:val >= 0'))
    if empty(deleted_entries)
        return
    endif

    for entry in reverse(deleted_entries)
        call remove(info, entry, entry + 1)
    endfor
    call writefile(info, viminfo, 'b')
endfu
下面是代码的作用:

当您进入命令行窗口时,第一个autocmd将捕获
s:old\u cmdline\u hist
中的命令行历史记录

当您离开时,第二个autocmd将更新当前会话的历史记录,并尝试从
~/.viminfo
中删除删除的条目

let hist = filter(getline(1, '$'), 'v:val !~# "^\\s*$"')
call histdel(':')
for i in hist
    call histadd(':', i)
endfor
call sort(filter(deleted_entries, 'v:val >= 0'))
if empty(deleted_entries)
    return
endif
此块仅更新当前会话的历史记录

let viminfo = expand('~/.viminfo')
if !filereadable(viminfo)
    return
endif
这一个检查
~/.viminfo
是否可读。如果不是,则函数停止

let info = readfile(viminfo)
let deleted_entries = filter(copy(s:old_cmdline_hist), 'index(hist, v:val) == -1')
for entry in reverse(deleted_entries)
    call remove(info, entry, entry + 1)
endfor
此块获取列表
info
(1项=1行)中
~/.viminfo
的内容。它还获取通过调用
filter()
删除的条目。后者删除所有不满足条件
索引(hist,v:val)=-1
的条目。如果操作
filter()
的旧历史记录的条目不在新历史记录中,则此表达式为真

call map(deleted_entries, 'index(info, ":".v:val)')
此行将删除的文本条目转换为
~/.viminfo
内的行地址

let hist = filter(getline(1, '$'), 'v:val !~# "^\\s*$"')
call histdel(':')
for i in hist
    call histadd(':', i)
endfor
call sort(filter(deleted_entries, 'v:val >= 0'))
if empty(deleted_entries)
    return
endif
此块对行地址进行排序,并删除非正的行地址,以防在上一步中找不到某些行地址(
index()
返回
-1
)。它还检查此时是否仍有行地址,如果没有,函数将再次停止

let info = readfile(viminfo)
let deleted_entries = filter(copy(s:old_cmdline_hist), 'index(hist, v:val) == -1')
for entry in reverse(deleted_entries)
    call remove(info, entry, entry + 1)
endfor
此块从
info
中删除相关行。它删除了两行(
entry
entry+1
),因为对于
~/.viminfo
中保存的每个命令行,还有第二行似乎是时间戳。此外,它以相反的顺序删除,不必更新要删除的行的地址(每次删除一行时,下一行的地址将减少一个)

此行将使用新内容覆盖
~/.viminfo
,新内容应与以前相同,而不会在命令行窗口中删除这些行

我不把它作为一个答案,因为我不确定它是否可靠,也没有任何副作用。在测试代码之前,我备份了
~/.viminfo

编辑2:


我认为它不能删除包含文本回车的行。可能还有其他特殊字符导致类似问题(如空字符
^@
)。

历史记录以纯文本形式存储在
.viminfo
文件中。所以你可以打开你的
.viminfo
,删除那行错误代码

或者,您可以通过histdel()函数清除历史记录,例如,对于搜索:

:调用histdel('/')

您可以按数字或正则表达式删除某些历史记录条目。请参见
:help histdel