Fügen Sie Argumente aus dem vorherigen Befehl zur Vervollständigung von zsh hinzu

21

In zsh (sowie in bash) können Sie einige Protokollworterweiterungen verwenden, um Argumente aus früheren Befehlen zu kennzeichnen.

In diesem Beispiel wird gezeigt, wie der zweite Parameter aus dem vorherigen Befehl im Verlauf mit !:#Erweiterung abgerufen wird:

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

Ich vergesse oft genau, welcher # -Parameter ein bestimmtes Argument ist, und die Eingabe !:#ist nicht immer so schnell, wenn ich mich erinnere, welches Argument es ist. Ich weiß meta-., dass ich das letzte Argument ersetzen muss, aber manchmal ist es nicht das letzte Argument, das ich möchte.

Ich möchte die Argumente aus dem vorherigen Befehl als Vorschläge hinzufügen, um jeden Befehl zu vervollständigen, den ich in zsh eingebe.

Ich konnte herausfinden, wie man eine Shell-Funktion erstellt, die aus dem letzten Befehl ein Array von Argumenten (0..N) erzeugt und an einen bestimmten Befehl bindet.

_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

So sieht es aus, wenn ich nur foo beende, bei dem ich die Tabulatortaste drücke <TAB>:

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

Dies funktioniert hervorragend, um den Befehl "foo" auszuführen, aber ich möchte, dass dies Optionen für jede zsh-Erweiterung sind, die ich mache. Ich denke, es hat etwas mit dem Zstyle-Completer-Zeug zu tun, aber nach ein paar Stunden des Herumhackens wurde mir klar, dass ich überfordert bin.

Wie kann ich die Argumente aus meinem vorherigen Befehl als vorgeschlagene Vervollständigungen für jeden Befehl in zsh abrufen?

Ich habe meine vollständige zshrc-Compinstall-Datei auf bitbucket verteilt, wenn das hilft. Viele davon stammen aus verschiedenen Quellen und einige davon habe ich selbst zusammen gehackt.

AKTUALISIEREN:

@ Julien Nicoulauds Antwort hat mich sehr nahe gebracht. Ich markiere es als akzeptiert, da es mich dahin gebracht hat, wo ich es brauchte.

Mit meiner speziellen Konfiguration, unter Verwendung der vorgeschlagenen:

zstyle ':completion:*' completer _last_command_args _complete

Hat bei mir nicht ganz geklappt, da beim Vervollständigen der Registerkarte nur die Liste der Argumente aus dem letzten Befehl angezeigt wurde (obwohl auch die Dateinamen vollständig waren, sie nur nicht angezeigt wurden). Ändern der Reihenfolge, um _complete _last_command_argsdas Gegenteil zu tun. Es würde die normalen Dateinamen anzeigen, aber nicht last_command_args

Ich vermute, das hat etwas mit der Funktionsweise von Completer zu tun. Ich denke, es zeigt nur die Ausgabe der ersten Methode an, die erfolgreich zurückgegeben wird, aber ich habe Probleme, die zsh-Quelle zu analysieren, um vollständig zu verstehen, was los ist. Ich konnte meine Methode dahingehend optimieren _complete, dass sie einen Aufruf von enthält , der sowohl die letzten Argumentbefehle als auch das reguläre automatische Vervollständigen anzeigt. Nicht ganz so getrennt, funktioniert aber gut genug für mich.

Hier ist die volle Funktion, die ich zusammen mit den anderen Zstyle-Dingen verwendet habe:

# 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 

Andere Zstyle-Linien, die ich habe, sind nicht erforderlich, um zu funktionieren, können aber den Grund dafür beeinflussen, warum dies bei mir funktioniert:

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

Wenn ich mich jetzt in einem Verzeichnis mit file1.txtund befinde file2.txtund mein letzter Befehl war echo foo bar baz, bekomme ich das für die automatische Vervollständigung, was genau das ist, was ich wollte:

% ls
bar   baz   echo  foo 
- files -
file1.txt   file2.txt 
Ted Naleid
quelle
2
Dies ist eine spektakuläre Idee
Michael Mrozek
2
Um ^[ .( insert-last-word) zu ergänzen , mag ich copy-earlier-word, welche Zyklen zwischen Wörtern der Zeile von erreicht werden insert-last-word. Für Ihre .zshrc:autoload copy-earlier-word && zle -N copy-earlier-word && bindkey '^[,' copy-earlier-word
Gilles 'SO - hören Sie auf, böse zu sein'
@ Gilles danke! Das bringt mich der Funktionalität näher, wenn ich nicht in der Lage bin, eine vollständige Autovervollständigung zu erhalten. ~ 80% der Fälle, wenn es nicht das letzte Argument ist, ist es das zweitletzte Argument, das ich möchte, und C-. + C- ist ziemlich gut.
Ted Naleid

Antworten:

6

Sie können Ihren Vervollständiger zur Liste der standardmäßig verwendeten Vervollständiger hinzufügen:

zstyle ':completion:*' completer _last_command_args _complete
nicoulaj
quelle
1
Wenn es _last_command_argsVervollständigungen gibt, werden die anderen nicht angezeigt. Wie bekommt man sie zusätzlich zu den üblichen?
Gilles 'SO- hör auf böse zu sein'
1
Danke für die Antwort, das hat mich nah genug gebracht, um etwas für mich arbeiten zu lassen, also akzeptiere ich es. Was ich anders gemacht habe, wird als Aktualisierung der obigen Frage vermerkt. Ihre Lösung druckte nicht sowohl die Argumente des letzten Befehls als auch die Dateien usw. des normalen Vervollständigers aus. Ich habe _completein der von mir erstellten Funktion komponiert und sie funktioniert genau so, wie ich es wollte.
Ted Naleid
Sie haben recht, meine Antwort ist nicht richtig.
Nicoulaj