我正在尝试创建一个 neovim 颜色选择器插件,我制作了一个 Python 应用程序,用于使用 Python 的
tkinter
库从色轮中选择颜色,并使用 vimscript 函数在 nvim 的缓冲区窗口中打印 Python 应用程序的输出。
但问题是,当我在 nvim 中直观地选择缓冲区并尝试替换为 Python 应用程序的输出时,它会在缓冲区窗口中附加输出而不是替换它。
我该如何修复它?
这是我尝试过的 vimscript 功能:
function! s:open_color_picker()
let lnum = line('.')
let col = col('.')
let current_line = getline(lnum)
let is_visual_mode = (mode() ==# 'v' || mode() ==# 'V' || mode() ==# "\<C-v>")
let insert_after = get(g:, 'NVIMColorPicker#InsertAfter#TheCursor', 0)
let insert_before = get(g:, 'NVIMColorPicker#InsertBefore#TheCursor', 0)
let color_picker_path = system('find ~/.local/share/nvim -type f -name color_picker.py')
let color_picker_path = substitute(color_picker_path, '\n\+$', '', '')
let color_picker_path = substitute(color_picker_path, '^\\n\+', '', '')
let color = system('python3 ' . shellescape(color_picker_path))
let color = substitute(color, '\n\+$', '', '')
let color = substitute(color, '^\\n\+', '', '')
if insert_after
" insert after the cursor
let hex_color = substitute(current_line, '\%' . (col + 1) . 'c', "\\0" . color, '')
call setline(lnum, hex_color)
elseif insert_before
" insert before the cursor
let hex_color = strpart(current_line, 0, col - 1) . color . strpart(current_line, col - 1)
call setline(lnum, hex_color)
else
" default behavior (insert after the cursor)
let hex_color = substitute(current_line, '\%' . (col + 1) . 'c', "\\0" . color, '')
call setline(lnum, hex_color)
endif
" for replacing the visually selected hex
if is_visual_mode
let old_reg = getreg('"')
let old_regtype = getregtype('"')
normal! gvy
let selected_text = @"
let new_output = color
call setreg('"', new_output, 'v')
let start_pos = getpos("'<")
let end_pos = getpos("'>")
let start_line = start_pos[1]
let start_col = start_pos[2]
let end_line = end_pos[1]
let end_col = end_pos[2]
if start_line == end_line
let current_line = getline(start_line)
let new_line = current_line[:start_col-2] . new_output . current_line[end_col-1:]
call setline(start_line, new_line)
else
let first_line = getline(start_line)
let last_line = getline(end_line)
let new_first_line = first_line[:start_col-2] . new_output
let new_last_line = last_line[end_col-1:]
call setline(start_line, new_first_line)
call setline(end_line, new_last_line)
if end_line - start_line > 1
call deletebufline('%', start_line + 1, end_line - 1)
endif
endif
call setreg('"', old_reg, old_regtype)
endif
endfunction
command! -range ColorPicker call s:open_color_picker()
您的问题不清楚如果存在视觉选择您想要做什么。此答案假设您想要将整个选择替换为您的
color_picker.py
返回的内容。
我选择停用全局变量
g:NVIMColorPicker#Insert#After#TheCursor
。拥有两个互斥的变量确实没有意义。现在,默认行为是在光标后插入,除非 g:NVIMColorPicker#InsertBefore#TheCursor
设置为真值。
另一个决定是返回一个可以通过
:normal!
运行的 Vim 命令,而不是通过 setline()
更改行,但这仍然存在争议。我的解决方案大量使用 execute 'normal!...
,这确实是我一般想要避免的事情。人们可能会争论哪种方法更漂亮。
整个范围管理现在在命令
:ColorPicker
内完成,这减轻了 s:open_color_picker()
处理可视范围的负担。
也就是说,如果
<range>
存在,我们用 gv
恢复最后的视觉选择(我们已经处于命令行模式,不再处于视觉模式了),并用 "_d
将其推入黑洞寄存器
。再见。
关于命令行模式的评论是顺便说一下为什么你的原始功能不起作用。当我们执行这个函数时,视觉模式就消失了,
mode()
将会忘记它。
之后,只需执行
s:open_color_picker()
作为正常模式命令返回的内容即可。
function! s:open_color_picker() abort
let insert_before = get(g:, 'NVIMColorPicker#InsertBefore#TheCursor', 0)
" Line below is untested as I did not have the script
let color_picker_path = findfile('color_picker.py', expand('~')..'/.local/share/nvim/**')
if ! executable('python3')
" Python not in PATH? Log an error and bail out!
endif
let color = system('python3 ' . shellescape(color_picker_path))
" I tested with the line below
" let color = system('echo ff00ff')
let color = substitute(color, '\n\+$', '', '')
let color = substitute(color, '^\\n\+', '', '')
if insert_before
" insert before the cursor
return 'i'..color
else
" default behavior (insert after the cursor)
return 'a'..color
endif
endfunction
command! -range ColorPicker if <range> | execute 'normal! gv"_d' | endif | execute 'normal! '..s:open_color_picker()
作为参考,请参阅所使用的相应命令上的
:help
。
最后一件事,我在 Vim 9.1 中编写并测试了所有这些。它应该也可以在 NeoVim 中工作。