Я пытаюсь создать плагин выбора цвета neovim, я создал приложение Python для выбора цвета из цветового круга с использованием библиотеки Python tkinter и использовал функцию vimscript для печати вывода приложения Python в буферном окне nvim.
Но проблема в том, что когда я визуально выбираю буфер в 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()
Основная причина, по-видимому, заключается в блоке else с " default behavior (insert after the cursor), который делает именно это. if is_visual_mode никогда не запускается, потому что переменная никогда не принимает значение true. Непонятно, что вы пытаетесь сделать в случае визуального режима, пожалуйста, уточните. Просто заменить все визуальное выделение цветовым кодом?
Я хотел заменить визуально выделенный текст цветовым кодом, который возвращает скрипт Python. Это сделано с помощью решения, которое вы даете!
Рад, что это помогло. Для будущих вопросов, пожалуйста, отредактируйте пояснения в свой вопрос. Это поможет будущим читателям найти другие (лучшие) ответы.





В вашем вопросе неясно, что вы хотите делать, если присутствует визуальное выделение. Этот ответ предполагает, что вы хотите заменить весь выбор тем, что возвращает ваш color_picker.py.
Я решил удалить глобальную переменную g:NVIMColorPicker#Insert#After#TheCursor. На самом деле нет смысла иметь две взаимоисключающие переменные. Теперь поведением по умолчанию является вставка после курсора, если для g:NVIMColorPicker#InsertBefore#TheCursor не установлено истинное значение.
Другое решение заключалось в том, чтобы вернуть команду Vim, которую можно было бы выполнить :normal!, вместо изменения строк через setline(), но это предмет дискуссий. В моем решении много используется execute 'normal!..., чего мне вообще нравится избегать. Можно спорить о том, какой подход более красив.
Обратите внимание, что я использовал встроенную функцию Vim findfile() вместо того, чтобы обращаться к внешней команде find. Я ожидаю, что для готового плагина пути будут разумно определены. Знать, где это лучше, чем знать, где искать.
Все управление диапазоном теперь осуществляется внутри команды :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.
Спасибо, все работает так, как я ожидал!
Вам следует свести свой пример к чему-то, что может запустить каждый.