Vimscript 函数用于替换 nvim 中可视化选择的缓冲区

问题描述 投票:0回答:1

我正在尝试创建一个 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()
vim neovim
1个回答
0
投票

您的问题不清楚如果存在视觉选择您想要做什么。此答案假设您想要将整个选择替换为您的

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 中工作。

© www.soinside.com 2019 - 2024. All rights reserved.