Добавить аргументы из предыдущей команды для завершения zsh

22

В zsh (также как и в bash) вы можете использовать некоторые расширения исторического слова для обозначения аргументов из предыдущих команд.

Этот пример показывает получение второго параметра из предыдущей команды в истории с !:#расширением:

% echo foo bar baz
foo bar baz
% echo !:2
echo bar
bar

Я часто забываю, что конкретно является параметром # конкретного аргумента, и ввод !:#не всегда такой быстрый, когда я помню, что это за аргумент. Я знаю о meta-.замене последнего аргумента, но иногда это не последний аргумент, который я хочу.

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

Мне удалось выяснить, как создать функцию оболочки, которая может создать массив аргументов (0..N) из последней команды и связать ее с конкретной командой.

_last_command_args() {
    last_command=$history[$[HISTCMD-1]]
    last_command_array=("${(s/ /)last_command}") 
    _sep_parts last_command_array
}

# trying to get last_command_args to be suggested for any command, this just works for foo
compdef _last_command_args foo

Вот как это выглядит для завершения просто foo, где я нажимаю клавишу Tab <TAB>:

% echo bar baz qux
bar baz qux
% foo <TAB>
bar   baz   echo  qux 

Это прекрасно подходит для выполнения команды "foo", но я бы хотел, чтобы это были опции для любого расширения zsh, которое я делаю. Я думаю, что это как-то связано с завершающим материалом zstyle, но после нескольких часов хакерских атак я понял, что я не в себе.

Как я могу получить аргументы из моей предыдущей команды в качестве предлагаемых дополнений для любой команды в zsh?

Я распространил свой полный файл zshrc compinstall на bitbucket, если это поможет. Многие из них взяты из разных источников, и некоторые из них я сам взломал.

ОБНОВИТЬ:

@Julien Nicoulaud ответил мне близко, я отмечаю его как принятый, так как я получил то, что мне нужно было получить.

С моим конкретным конфигом, используя предложенное:

zstyle ':completion:*' completer _last_command_args _complete

У меня не совсем получилось, так как это приводило к тому, что при завершении табуляции отображался только список аргументов из последней команды (хотя на самом деле он также заканчивался именами файлов, просто не отображал их). Изменив порядок, _complete _last_command_argsсделал обратное. Он будет отображать обычные имена файлов, но не last_command_args

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

Вот полная функция, которую я использовал вместе с другими имеющимися у меня средствами zstyle:

# adds the arguments from the last commadn to the autocomplete list
# I wasn't able to get this to work standalone and still print out both regular
# completion plus the last args, but this works well enough.
_complete_plus_last_command_args() {
    last_command=$history[$[HISTCMD-1]]
    last_command_array=("${(s/ /)last_command}") 
    _sep_parts last_command_array
    _complete 
}


_force_rehash() {
  (( CURRENT == 1 )) && rehash
  return 1  # Because we didn't really complete anything
}

zstyle ':completion:::::' completer _force_rehash _complete_plus_last_command_args _approximate 

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

zstyle -e ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX + $#SUFFIX) / 3 )) )'
zstyle ':completion:*:descriptions' format "- %d -"
zstyle ':completion:*:corrections' format "- %d - (errors %e})"
zstyle ':completion:*:default' list-prompt '%S%M matches%s'
zstyle ':completion:*' group-name ''
zstyle ':completion:*:manuals' separate-sections true
zstyle ':completion:*' menu select
zstyle ':completion:*' verbose yes

Теперь, если я нахожусь в каталоге с file1.txtи file2.txt, и моя последняя команда была echo foo bar baz, я получаю это для автозаполнения, что именно то, что я хотел:

% ls
bar   baz   echo  foo 
- files -
file1.txt   file2.txt 
Тед налейд
источник
2
Это захватывающая идея
Михаил Мрозек
2
Мне нравится дополнение ^[ .( insert-last-word), copy-earlier-wordкоторое циклически повторяет слова строки, достигнутой insert-last-word. Для вашего .zshrc:autoload copy-earlier-word && zle -N copy-earlier-word && bindkey '^[,' copy-earlier-word
Жиль "ТАК - перестать быть злым"
@ Жиль, спасибо! Это приближает меня к функциональности, если я не могу получить полное автозаполнение. ~ 80% времени, если это не последний аргумент, это второй и последний аргумент, который я хочу, и C-. + C-, это довольно хорошо.
Тед Нейлид

Ответы:

6

Вы можете добавить свой завершитель в список используемых по умолчанию:

zstyle ':completion:*' completer _last_command_args _complete
nicoulaj
источник
1
Если есть какие-либо _last_command_argsдополнения, остальные не отображаются. Как вы получаете их в дополнение к обычным?
Жиль "ТАК - перестань быть злым"
1
Спасибо за ответ, это подобрало меня достаточно близко, чтобы заставить что-то работать на меня, поэтому я принимаю это. То, что я сделал по-другому, отмечено как обновление вопроса выше. Ваше решение не распечатывало как аргументы из последней команды, так и файлы и т. Д. Из обычного завершителя. Я сочинил _completeвнутри созданной мной функции, и она работает так, как я хотел.
Тед Нейлид
Вы правы, мой ответ не верен.
nicoulaj