Использование vimscript для запуска тестовых сценариев с использованием обычных команд vim - PullRequest
1 голос
/ 14 марта 2020

Я начал использовать VIM в качестве редактора около шести месяцев назад, и мне это очень нравится. Тем не менее, есть несколько сценариев, связанных с работой, которые я хотел бы реализовать, чтобы сделать мою жизнь проще. Если есть кто-нибудь, кто может мне помочь, я был бы благодарен.

Это мой вопрос. У меня есть несколько тестов, написанных на python, и я написал сопоставление клавиш для запуска этих тестов с использованием терминала vim. Работает отлично. Однако теперь я хочу использовать VimScript и некоторые функции vim, чтобы он выглядел лучше. Я новичок в VimScript и поэтому не уверен, выполнимо ли это.

Моя структура папок выглядит так:

.
├── my_test.py
└── test
    └── testRunner.py

1 directory, 2 files

Мой тестовый код выглядит примерно так:

my_test.py:

#!/bin/python

class MyTest1:

    def Run():
        # Test body

class MyTest2:

    def Run():
        # Test body

test / testRunner.py:

#!/bin/python

print "Running the test"

Мое текущее сопоставление клавиш в .vimr c выглядит следующим образом:

nnoremap <leader>t mZ/class<CR>Nwyiw:noh<CR>:terminal<CR>cd test<CR>python testRunner.py <C-W>"0<CR><C-W><C-W>'Z

Что это значит,

  1. Найдите название теста (тест, который я сейчас редактирую)
  2. Скопируйте имя и запустите это имя теста в vim-терминале

То, что я хочу, чтобы это было что-то похожее на:

nnoremap <leader>t :call RunThisTest()<CR>

function! RunThisTest()
    RememberEditContext()
    FindAndCopyTestName()
    RunTestInTestDirectory()
    ReturnToEditContext()
endfunction

Может кто-нибудь помочь мне в разработке этих функции?

Заранее спасибо!

1 Ответ

2 голосов
/ 14 марта 2020

Одним из вариантов является непосредственное использование команды :normal!, которая позволяет вам запускать последовательность нажатий клавиш так же, как если бы вы использовали их в сопоставлении.

Но это Оказывается, мы можем сделать лучше, намного лучше, так что давайте к этому!

Поиск и сопоставление

Вы можете использовать функцию search() чтобы найти класс, в котором вы находитесь. Вы можете передать ему флаги, такие как bcnW, чтобы он выполнял поиск b и наоборот, возможно, совпадет с c урсом Положение, n не перемещайте курсор и не w рэп вокруг файла. Собираем все вместе:

let line = search('^class \w', 'bcnW')

Это вернет номер строки, если было положительное совпадение, или 0, если его не было. Если совпадение было найдено, мы можем использовать getline(), чтобы получить его содержимое, а затем matchlist(), чтобы захватить имя класса.

let [_, classname; _] = matchlist(getline(line), '^class \(\w\+\)')

Как вы можете видеть, используя В Vimscript нам удалось получить имя класса, не перемещая курсор и не касаясь регистра поиска. Поэтому нам не нужно было ставить какие-либо отметки, и нам не нужно беспокоиться о восстановлении текущей позиции и вида!

Выполнение команды

Теперь пришло время запустить команду на Терминал. Мы можем упростить процесс, передав ему команду напрямую. (Обратите внимание, что здесь есть разница в том, что терминал будет запускать только этой команды, он не покинет оболочку после завершения. В зависимости от вашего варианта использования, вы можете предпочесть сделать что-то более похожее на что вы делаете сейчас.)

Мы можем запустить команду в терминале с помощью:

:terminal ++shell cd test && python testRunner.py MyTest1

Но, конечно, нам нужно передать ему имя класса, которое мы получили, здесь не фиксированное значение. Для этой цели мы можем использовать команду :execute. Он берет строку и запускает ее как команду Vimscript. Мы можем использовать это для динамической сборки строки.

execute "terminal ++shell cd test && python testRunner.py ".shellescape(classname)

Наконец, чтобы go вернуться к исходному окну, мы можем использовать команду :wincmd, более конкретно wincmd p.

Собираем все вместе

Получаемая функция:

function! RunThisTest() abort
    let line = search('^class \w', 'bcnW')
    if line == 0
        echoerr "Not inside a test class!"
        return
    endif
    let [_, classname; _] = matchlist(getline(line), '^class \(\w\+\)')
    execute "terminal ++shell cd test && python testRunner.py ".shellescape(classname)
    wincmd p
endfunction

nnoremap <silent> <leader>t :call RunThisTest()<CR>

Определенно есть место для улучшений, но это должно помочь вам начать!

Сохранение и восстановление контекста

Мы не go добавили сохранение и восстановление контекста, так как в этом случае на самом деле ничего этого не нужно!

Если бы вы разрабатывали функции, использующие команды которые влияют на глобальный контекст, вы можете использовать Vimscript для его сохранения и восстановления.

Например, если вы собираетесь искать, вы можете сохранить регистр @/ и восстановить его после поиска:

let saved_search = @/
/class
let @/ = saved_search

Если вы собираетесь восстановить регистр, вы также можете сохранить и восстановить его. Например, @" для регистра по умолчанию. Вам также следует сохранить регистр type , в котором записывается, было ли содержимое взято в символьном, линейном или блочном контексте.

let saved_register = getreg('"')
let saved_regtype = getregtype('"')
normal! y3W
let words = getreg('"')
call setreg('"', saved_register, saved_regtype)

Вы также можете сохранить текущий view , который включает позицию, в которой находится курсор, а также другие параметры окна, такие как первая отображаемая строка и столбец, чтобы вы могли полностью восстановить этот контекст. Подробнее см. Функции winsaveview() и winrestview().

Управление терминалами

Существуют функции для управления терминалом, которые go далеко за пределы возможностей :terminal.

Например, гораздо более богатый term_start() позволяет запускать команду в виде списка и передавать параметры, такие как 'cwd', для запуска команды в другом каталоге.

Таким образом, мы могли бы упростить выполнение нашего теста с помощью:

call term_start(['python', 'testRunner.py', classname], {'cwd': 'test'})

Также имеется term_sendkeys(), который можно использовать для отправки нажатий клавиш на Терминал. Например, если вы предпочитаете запускать оболочку и вызывать сценарий Python через оболочку:

let termbuf = term_start(&shell, {'cwd': 'test'})
call term_sendkeys(termbuf, "python testRunner.py ".shellescape(classname)."\r")

Вы также можете использовать term_getline(termbuf, '.'), чтобы получить содержимое строки, в которой находится курсор в данный момент. Например, вы можете использовать это, чтобы определить, находится ли терминал в приглашении оболочки (строка заканчивается на $ и пробел) или все еще на выполнении тестового бегуна.

Наконец, вы можете даже иметь команда работает внутри терминала вызова Vim команды! Через специальные escape-последовательности он может вызывать экспортированные функции или просить Vim открыть файлы для редактирования. Подробнее см. :help terminal-api.

Узнать больше

Это все очень аккуратно ... Но как я могу узнать больше?

Мой первый Настоятельно рекомендуется прочитать превосходную «Изучите Vimscript на нелегком пути» , написанную Стивом Ло sh. Он охватывает основы языка, как взаимодействовать с редактором (отображения, автокоманды, выражения отступов, типы файлов) и основы того, как собрать подключаемые модули Vim. Он также охватывает распространенные ошибки Vimscript и лучшие практики для написания надежного кода. Это необходимо, если вы хотите серьезно относиться к написанию сценариев Vim.

Второе предложение - прочитать отличную документацию, доступную через :help! Немногие приложения так же хорошо документированы, как Vim, так что знание вашего справочного руководства может действительно помочь.

В-третьих, StackExchange. В частности, Vi & Vim SE , который посвящен этой теме. Там вы найдете не только отличные ответы, но и сможете задавать отличные вопросы. У вас будет также возможность видеть замечательные вопросы, удивляться, как их решать, и, возможно, попытаться написать ответ. (Лично, с тех пор, как я начал использовать Vi & Vim SE, мой Vim-foo значительно улучшился, и я могу считать себя почти экспертом.) Я настоятельно рекомендую это.

Наконец, попрактикуйтесь. Обычно требуется несколько попыток, чтобы получить что-то действительно правильное. Но тот факт, что среда довольно динамична c и гибка, позволяет экспериментировать. Вы можете набирать команды и экспериментировать с ними в самом редакторе, поэтому обычно вы быстро тестируете свой код и получаете его в процессе написания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...