Функция Vimscript для замены визуально выбранного буфера в nvim

Я пытаюсь создать плагин выбора цвета 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()

Вам следует свести свой пример к чему-то, что может запустить каждый.

romainl 17.03.2024 15:38

Основная причина, по-видимому, заключается в блоке else с " default behavior (insert after the cursor), который делает именно это. if is_visual_mode никогда не запускается, потому что переменная никогда не принимает значение true. Непонятно, что вы пытаетесь сделать в случае визуального режима, пожалуйста, уточните. Просто заменить все визуальное выделение цветовым кодом?

Friedrich 17.03.2024 16:57

Я хотел заменить визуально выделенный текст цветовым кодом, который возвращает скрипт Python. Это сделано с помощью решения, которое вы даете!

Tribhuwan 18.03.2024 03:46

Рад, что это помогло. Для будущих вопросов, пожалуйста, отредактируйте пояснения в свой вопрос. Это поможет будущим читателям найти другие (лучшие) ответы.

Friedrich 18.03.2024 08:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем вопросе неясно, что вы хотите делать, если присутствует визуальное выделение. Этот ответ предполагает, что вы хотите заменить весь выбор тем, что возвращает ваш 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.

Спасибо, все работает так, как я ожидал!

Tribhuwan 18.03.2024 03:43

Другие вопросы по теме