Как использовать внешнюю команду в Vim для изменения выбранных слов и строк?

22

Что-то, что я нашел полезным в других редакторах, - это способность:

  • взять выделенный текст
  • запустить внешнюю команду и передать выбор ее stdin
  • возьмите внешние команды stdoutи замените текущий выбор им.

Таким образом, вы можете написать полезные текстовые инструменты, которые работают с выделением, используя любой язык, который может выполнять базовые функции ввода-вывода.

Как это можно сделать с помощью vim, используя выбор? ... один символ, слово, абзац ... и т. д.

(Прямо в командной строке или через привязку клавиш?)


Заметка

Такие команды, как !sortработа на уровне строки, причина, по которой я задаю этот вопрос, заключается в том, что я хотел бы работать с выбором. (т. е. текст, который будет удален при xнажатии).

ideasman42
источник

Ответы:

17

Я считаю, что часто самым простым способом является использование визуального режима с v(или заглавная буква Vдля выделения целых строк) и выделения текста, который вы хотите передать.

Затем введите:

:!cat

Это не делает ничего полезного, как такового. Полезная команда, которую я часто использую:

:!python -m json.tool

отформатировать JSON.

Вы также можете просто набрать (без визуального режима):

:<range>!command

Например, для всего файла:

:%!python -m json.tool

Или для текущей строки:

:.!python -m json.tool
Мартин Турной
источник
Другой действительно полезный инструмент для использования с этой sortкомандой.
опрос Коди
4
@CodyPoll Что не так с Vim's :sort?
Мартин Турной
5
@Carpetsmoker. Команда внешней сортировки имеет гораздо больше опций и (в зависимости от локали и т. Д.) Создает другой порядок.
Дероберт
1
Это не работает для выбора одного слова в строке. (см. вопрос упоминает выбор уровня слова)
ideasman42
@ ideasman42 Правильно ... Я думаю, что изначально я читал этот вопрос как "строки или слова" вместо "строк и слов" ... В любом случае, делать это со словами неочевидно, программы UNIX работают со строками, а Vim не исключение Я немного поэкспериментировал и вроде как нашел решение, но оно не очень хорошо работает ... Возможно, мой подход неправильный, поэтому я просто оставлю его на несколько дней и вернусь к нему позже.
Мартин Турной
7

Я написал плагин под названием express.vim, который может помочь с этим. Плагин определяет оператор, g=который позволяет вам оценивать выражение VimScript по движению (или визуальному выбору). Он запрашивает выражение, в котором вы можете использовать v:valв качестве заполнителя текст, охватываемый движением (или, опять же, визуальный выбор).

В этом случае полезное выражение будет использовать system()функцию, которая запускает внешнюю команду.

system('tr a-z A-Z', v:val)

(Здесь я использовал trв качестве простого примера внешнюю команду.)

Способ использования express.vim для этой проблемы состоит в том, чтобы выделить текст в визуальном режиме, затем ввести текст, затем g=это выражение, а затем нажать Enter:

g=system('tr a-z A-Z', v:val)<CR>

Я признаю, это не легко использовать. (На самом деле, я редко использую этот плагин!) Я подумываю добавить ярлык для вызова внешней команды, такой как запуск выражения с помощью !. Я опубликую обновление здесь, если я в конечном итоге сделаю это.

РЕДАКТИРОВАТЬ

Я изменил express.vim для обработки выражений, начинающихся с !внешних команд. Таким образом, придерживаясь trпримера, выше становится намного проще. После визуального выбора введите следующее:

g=!tr a-z A-Z<CR>

Объяснение:

  1. Вызовите экспресс-оператор с помощью g=
  2. Введите !tr a-z A-Zв качестве выражения
  3. Нажмите Enter
tommcdo
источник
4

Вы ищете команды фильтра в Vim. См :help filter. Вот соответствующая документация:

!{motion}{filter}   Filter {motion} text lines through the external
                    program {filter}.
!!{filter}          Filter [count] lines through the external program
                    {filter}.
{Visual}!{filter}   Filter the highlighted lines through the external
                    program {filter} (for {Visual} see |Visual-mode|).
                    {not in Vi}

:{range}![!]{filter} [!][arg]               *:range!*
                    Filter {range} lines through the external program
                   {filter}.  ...[See documentation for details]

Таким образом, ввод 5!!sortбудет сортировать следующие 5 строк, начиная с курсора.

Самир
источник
Можно ли отфильтровать одно слово? (не на уровне линии)
ideasman42
Да. Третий вариант (визуальный режим) работает для всего, что выделено (слова, частичная строка, несколько строк, прямоугольный блок и т. Д.).
Самер
1
Третий вариант также фильтрует целые строки. Если вы выберете одно слово и отфильтруете его, например, через tr [:lower:] [:upper], то vim выделит не только это слово, но и всю строку.
с
0

Обратите внимание, что это можно сделать с помощью:

  1. визуально выберите все, что вы хотите
  2. s^R=system('tr a-z A-Z', @")[:-2]^M^RCTRL + R и ^ M с ENTER)

Он также может работать с чем угодно, что делает выбор + замена как ci"^R=....

Люк Эрмитт
источник
При выполнении этого при многострочном выделении текста (после нажатия vи перемещения курсора) я получаю сообщение об ошибке E16: Invalid range\nE16: Invalid range\nE476: Invalid command(в Linux существуют trи другие основные команды).
ideasman42
Вы нажали, sчто входит в режим вставки или :sкоманды?
Люк Эрмит
Подозреваю, что нет, но также не уверен, как вы имеете в виду, возможно, пример может показать, как связать это с ключом?
ideasman42
Вы бьете прямо sиз визуального режима или бьете :первым? Там нет никакого :участия в последовательности клавиш, которые я написал. Отображение будет: vnoremap µ s<c-r>=system('tr a-z A-Z', @")[:-2]<cr>.
Люк Эрмитт