Fish-shell: Docopt-basierte Optionsparsing-Funktion für Funktionen und Builtins

Erstellt am 26. Dez. 2012  ·  54Kommentare  ·  Quelle: fish-shell/fish-shell

Dies ist eine weniger aggressive Version von Ausgabe #447. Ich habe versucht, syntaktisch signifikante Optionen zu implementieren (für Interessierte unter https://github.com/xiaq/fish-shell/tree/opt-parse), aber ich habe mich zurückgehalten und entschieden, dass dies keine gute Idee ist, da die unvermeidliche Inkonsistenz mit externen Befehlen fühlt sich für mich wirklich schlecht an.

Wie von @cben betont , ist die Option zum Parsen jedoch orthogonal zu den

  • Funktionen und Builtins haben _Signaturen_, die die Optionen beschreiben, die sie akzeptieren, Einschränkungen für die Optionen (ob sie Argumente akzeptieren oder nicht, und wenn ja, wie viele usw.) und die Beschreibungen dafür. Mit diesen Informationen können Vervollständigungen _automatisch generiert_ werden, wodurch viel Doppelarbeit vermieden wird.
  • Das Parsen von Optionen erfolgt unmittelbar vor dem Aufruf einer Funktion oder eines eingebauten Befehls, sodass erkannte Optionen (und möglicherweise ihre Argumente) aus $argv und an anderer Stelle erscheinen.

Für Builtins wird zusätzlich zu argv ein std::map<wcstring, wcstring_list_t> opts übergeben (Dies reduziert auch den LoC von builtin.cpp drastisch. :). Für Funktionen werden Optionen in entsprechende Umgebungsvariablen abgelegt. Für boolesche Optionen (auch bekannt als _switches_) wird ein leeres Array erstellt (und kann mit set -q getestet werden); für nicht-boolesche Optionen werden die angegebenen Werte beibehalten.

Einige Details, zusammengefasst aus Ausgabe #447:

  • Die genaue Syntax für Funktionssignaturen bedarf noch einiger Überlegungen. Ich habe ursprünglich vorgeschlagen

function foo -o h,help,'Display help' -o c:,count:,'Specify a count' ... end

was den Vorteil hat, dass keine spezielle Syntax erforderlich ist, aber nicht sehr schön aussieht und das Schreiben langer Optionslisten umständlich macht. @ridiculousfish schlug zwei Formen vor,

function history function --options --save,-s: 'Save all changes in history file' --clear: 'Delete all history items' --search "command": Searches for the given command end <body of function> end

und

function history option 'prefix:' --description 'Match history items that start with the given prefix' end

Ersteres ähnelt optisch Optionsspezifikationen in Manpages, erfordert jedoch eine spezielle Syntax für die Signaturspezifikation. Letzteres hat den Vorteil, dass keine Syntaxänderung erforderlich ist. Ich habe versucht, letzteres zu implementieren, aber nach dem Versuch bin ich nicht dafür - es bricht die übliche Semantik der "übersprungenen Ausführung" von Befehlen innerhalb von Funktionen. Es kann irreführend sein, dass option wie ein gewöhnliches Builtin aussieht, aber tatsächlich Teil der Funktionsdeklaration ist. @cben schlug zusätzlich vor, dass option _ein normales Built-In sein kann, aber es erfordert option um die $argv im _calling frame_ zu zerlegen, was ich später nicht wirklich gut fand .

  • Wie Optionsvariablen benannt werden sollten, bedarf auch einiger Überlegungen. Die von mir vorgeschlagene Regel lautete:

    1. Wenn eine kurze Option eine lange Form hat, wird sie in die lange Form kanonisiert.

    2. Optionen werden in $opt_optname .

Der Aufruf von f -a a -b b --long some , angenommen -a entspricht --arg und -b hat keine Langform, ergibt $opt_arg , $opt_b und $opt_long jeweils a , b und c zugewiesen.

@maxfl hat vorgeschlagen, dass wir das Präfix $opt_ für lange Optionen weglassen . Ich war ursprünglich dafür, aber nachdem ich gemerkt habe, dass es dadurch unpraktisch ist, --status und --version , die plausible Optionsnamen sind, da sie die bekannten Variablen $status und $version , denke ich, dass es sich lohnt, das Präfix $opt_ in jedem Fall beizubehalten.

RFC enhancement

Hilfreichster Kommentar

Sollten wir ein getopt() Äquivalent für Fischskripte implementieren? Diese Ausgabe ist seit vier Jahren offen. Wie das von @floam geöffnete Problem #3403 getopt für die Verwendung durch fish-Skripte implementieren. Das ist grenzwertig trivial. Es würde uns erlauben, unsere Fischskripte (Funktionen) so zu parsen, dass sie mit eingebauten Befehlen kompatibel sind. Wenn dies implementiert ist, kann sowohl das Parsen von eingebauten als auch von Funktions-Flags geändert werden.

Alle 54 Kommentare

Die Syntax der Funktionssignatur sollte es auch ermöglichen, anzugeben, ob die Signatur _autoritativ_ ist, dh ob nicht erkannte Optionen zu einem Fehler führen oder in $argv .

Die Unterscheidung zwischen booleschen und nicht-booleschen Optionen kann Teil allgemeinerer Einschränkungen für die _Anzahl_ von Optionsargumenten sein: 0 Argument = boolean, 1+ Argument = nicht-boolean. Ein weiterer häufiger Anwendungsfall kann die Angabe von _exactly 1_ Argument sein, sodass Sie sich darauf verlassen können, dass eine Optionsvariable $opt_foo in genau 1 Wort erweitert wird.

Attribution: Argumentnummernbeschränkung wurde von @maxfl vorgeschlagen.

Für Switches wolltest du set -q statt test -q schreiben

Klingt für mich soweit gut. Ergänzende Ziele hier:

  1. Erleichtern Sie es Funktionen und Built-Ins, ihre Optionen zu analysieren
  2. Funktionen selbstdokumentierender machen
  3. Erlauben Sie Syntaxhervorhebungen und Tab-Vervollständigungen, um die Funktionssignatur zu nutzen, sodass keine separate Vervollständigung erforderlich ist
  4. Verbessern Sie die Syntax zum Angeben von Vervollständigungen

Die letzten beiden sind die ehrgeizigsten und implizieren auch, dass wir in der Lage sein sollten, eine Funktionssignatur für einen externen Befehl zu schreiben, nicht nur für eine Funktion.

Ich dachte, es wäre nützlich, die Optionseigenschaften aufzulisten, die wir unterstützen möchten. Globale Eigenschaften für eine Optionsspezifikation:

  1. Maßgeblich: ob es vielleicht mehr Optionen gibt oder das ist es
  2. Nur Dateien: Die Argumente, die keine Option sind, sind immer Dateien
  3. Dateien nie: Die Nicht-Option-Argumente sind nie Dateien (https://github.com/fish-shell/fish-shell/issues/379)
  4. Alte lange Optionen: Alle langen Optionen verwenden einen Bindestrich ('-foo' nicht '--foo') (vielleicht ist dies stattdessen eine Sache pro Option)
  5. (Vielleicht) Alle Optionen müssen literal sein: 'count --help'
  6. (Vielleicht) Optionen gelten für einen Unterbefehl: ('git checkout ...')
  7. (Vielleicht) Unterstützt zwei Bindestriche, die "Ende der Optionen" bedeuten (vielleicht gehen wir einfach immer davon aus, dass dies aktiviert ist)
  8. (Vielleicht) Alias: Verwenden Sie die gleichen Vervollständigungen wie bei diesem anderen Befehl (https://github.com/fish-shell/fish-shell/issues/393).
  9. (Vielleicht) Mindestens ein Argument ist erforderlich.

Eigenschaften für eine individuelle Option:

  1. Beschreibung
  2. Langname: '--foo'
  3. Kurzname: '-f', mit der Maßgabe, dass diese kombiniert werden können: ('rm -Rf')
  4. (Vielleicht) Langer Name mit einem Bindestrich: '-foo' (was Fisch "alten Stil" nennt)
  5. Hat Argument: ob die Option einen Parameter annimmt
  6. (Vielleicht) Argument für Option ist immer eine Datei
  7. (Vielleicht) Parameter verwendet gleich: ('gcc -std=c99')
  8. (Vielleicht) Option muss literal sein ('count --help')
  9. Bedingung: ein Shell-Befehl, der 0 zurückgeben muss, wenn die Vervollständigung verwendet werden soll

Ich habe Mühe, Vervollständigungen zu lesen, also hoffe ich, dass die Syntax gut lesbar ist und so nah wie möglich an der tatsächlichen Befehlsverwendung ist, damit sie als Beispiel dient.

Viele Skriptsprachen haben Bibliotheken für die Optionsspezifikation und das Parsen, oft mehr als eine. Wir sollten eine Umfrage durchführen, um zu sehen, wie sie damit umgehen und ob sie gute Syntaxideen haben, die wir verwenden könnten.

Eine andere syntaktische Möglichkeit besteht darin, die gesamte Signatur zu einem einzigen Argument für function , aber das Argument umfasst normalerweise mehrere Zeilen, indem Anführungszeichen verwendet werden:

function history --options '
        -s, --save: Save all changes in history file
        -c, --clear: Delete all history items
    '
    <body of function>
end

docpt hat eine schöne Syntax. Keine der vorhandenen Implementierungen verwendet eine geeignete Sprache, aber sie könnten es begrüßen, wenn wir eine C++-Implementierung beitragen.

@ridiculousfish Behoben : s/test -q/set -q/ .

@ridiculousfish Ich bin mir nicht sicher, ob docopt das Richtige getan hat - es ist sehr gut lesbar, aber ich habe auch das Gefühl, dass es die Struktur irgendwie verdeckt. Ich würde etwas formelleres bevorzugen.

Ich komme nach ein paar Wochen darauf zurück. Ich habe mir docopt noch einmal genauer angeschaut. Viele seiner Ideen wie Mustervergleich, ein einziges Diktat für alle Ergebnisse (sei es eine Option, ein Optionsargument oder ein Positionsargument) sind inspirierend.

Ich denke, eine docopt-ähnliche Lösung ist praktikabel, aber ich sehe jetzt zwei Probleme. Erstens, wie es in die Fischsyntax passt. Ein einfacher Ansatz, um docopt in einfache Anführungszeichen zu setzen, aber das macht das Hervorheben von Syntax umständlich (wenn überhaupt möglich). Wenn wir es nicht in Anführungszeichen setzen, müssen wir wahrscheinlich einen speziellen "Docopt-Block" einführen, um die übliche Syntax zu ändern.

Zweitens bräuchte es einige Erweiterungen. Insbesondere wünsche ich mir, dass die Syntax zum Schreiben von Vervollständigungen eine Obermenge der Signatursyntax ist, und die Unterstützung von Vervollständigungen würde mindestens die folgenden Erweiterungen erfordern:

  • Angeben einer möglicherweise nicht erschöpfenden Liste von Kandidaten für Argumente, wie completion . Aus diesem Grund gibt es Vervollständigungen, die auch in Signaturen nützlich sein können (Vervollständigung generieren, Argument mit der Liste vergleichen, wenn sie vollständig ist).
  • Volle Programmierbarkeit. Wir können kaum alle möglichen Varianten der Optionsspezifikation abdecken; Geben Sie in diesem Fall dem Vervollständigungsschreiber die volle Kontrolle.

Folgendes kann optional unterstützt werden, aber da ich "volle Programmierbarkeit" behandelt habe, sind sie optional :) :

  • Exotische Optionsführer. zB sh(1p) unterstützt + , so dass sh +ab sh +a +b .
  • Wo die Auswahlmöglichkeiten begrenzt sind, werden eindeutige Präfixe zum vollständigen Wort aufgelöst. Linux ip(8) ist ein Beispiel dafür: Es hat Unterbefehle wie link , addr , route usw. und ip route können abgekürzt werden zu einem von ip rout , ip rou und ip ro ( ip r ist eigentlich eine akzeptierte Abkürzung, aber kein eindeutiges Präfix). Wenn der Benutzer etwas davon geschrieben hat, sollte sich die Vervollständigung so verhalten, als würde ip route angezeigt.

Ich frage mich darüber und beschloss, ein wenig damit zu experimentieren, indem ich ein selbstdokumentierendes Format erstelle. Nehmen wir etwas Einfaches an, wie den folgenden Befehl (wenn jemand etwas wirklich Komplexes braucht (wie Optionen, die mit + ), sollte er keinen Fischparser zum Parsen des Befehls verwendet haben).

cut --as-well-as-possible --budget=5000 -x --name=Me --name=Him something else

Dies könnte so dargestellt werden.

function cut --description 'It cuts!'
    options --as-well-as-possible/-a --budget/-b= -x --name=... rest-arguments...
    if test $x
        echo "You provided $rest_arguments."
    end
end

Alternativ mit Dokumentation.

function cut --description 'It cuts!'
    options --as-well-as-possible/-a: 'Does stuff as well as possible.' \
            --short/-s=: 'Does something important for sure.'
end

Die hier bereitgestellte Syntax soll einfach und selbstdokumentierend sein (Deklaration ahmt die Verwendung nach, wie in C). ... bedeutet mehrere Argumente (im CoffeeScript-Stil), / ist Alternation (die erste Variable darin wäre der endgültige Variablenname (aber , würde auch funktionieren)), = bedeutet, dass die Option Argumente akzeptiert, : ist Dokumentation, und das war es auch schon. Ja, mir ist das Problem mit _ und - , aber ich kann mir leider keine Lösung dafür vorstellen.

Ich frage mich nur, was ist Ihre Meinung zu meinem Vorschlag?

Scheint ein guter Anfang zu sein! Besonders interessant ist der Befehl 'Optionen'.

Ein wichtiges Merkmal werden Einschränkungen für Argumente sein. Wir möchten ausdrücken können, dass Argumente nur Dateien sind, niemals Dateien, nur Verzeichnisse ( cd ), nur Befehle ( sudo ) oder programmgesteuert bestimmt werden ( git checkout ... ) . Wir möchten auch in der Lage sein, Argumente für die automatische Parameteranalyse innerhalb von Fischfunktionen zu benennen. Ich ermutige Sie zu überlegen, wie diese in die Syntax passen könnten.

Mir ist gerade aufgefallen, dass docops jetzt eine C++-Implementierung hat. Könnte sich lohnen, nochmal reinzuschauen. https://github.com/docopt/docopt.cpp

Ich stimme auch für docopt . Es hat Spaß gemacht, es in Python und sogar C zu verwenden. Ich denke, dass es einfacher ist, die in einfache Anführungszeichen eingeschlossene Docopt-Spezifikation zu implementieren und zu verstehen. Hervorheben ist ein Problem, aber ich denke, es kann gelöst werden, indem man universal vim/emacs/etc. Plugin, das die Docopt-Spezifikation in python/c++/fish/etc behandelt. Quellen.

Ich habe eine Wiki-Seite mit einigen Beispielen hinzugefügt, wie es aussehen würde, Signaturen mit einer erweiterten Docopt-Syntax zu schreiben, und einige Gedanken darüber, wie wir sie erweitern würden. Beiträge willkommen.

@ridiculousfish gab es diesbezüglich in letzter Zeit Fortschritte?

Ja, viel Arbeit in der Docopt-Branche.

Ich habe diese Filiale vermisst. Tolle Neuigkeiten :100: :+1:

Hier meine bisherige Arbeit. Dies wird zu einem sehr großen Feature, aber es wird andere Features subsumieren, so dass ich denke, dass es insgesamt die Komplexität reduziert. Ich poste dies, um Feedback zu erhalten - bitte lesen und teilen Sie Ihre Gedanken.

Zusammenfassung

Wir fügen einen Begriff eines Befehls _signature_ hinzu, mit einer Syntax basierend auf docopt . Die Signatur ist ein Stück Metadaten, das Fisch mit vielen Informationen darüber versorgt, wie der Befehl aufgerufen wird.

Um Ihnen einen Vorgeschmack zu geben:

complete --signature '
Usage: cowsay [options] [<message>...]
Options: -e, --eye <eyestr>         Specify eye string
         -f, --cowfile <cowname>    Specify cow file name
         -help                      Display help and exit
         -l, --list                 List all cowfiles
         -n                         No word wrapping
         -T                         Specify tongue string
         -W, --width <colwidth>     Column width

Conditions: <cowname>  (cowsay -l|tail -n +2|tr \  \n)

Cowsay generates an ASCII picture of a cow saying something provided by the user. If
run with no arguments, it accepts standard input, word-wraps the message given at
about 40 columns, and prints the cow saying the given message on standard output.
'

Ziele

Die Signatur spielt mehrere Rollen:

  1. Es wird die bevorzugte Methode zum Schreiben von Tabulatorvervollständigungen. complete Flags wie -l , -s und -o werden den stärkeren Signaturen vorgezogen.
  2. Es wird von Syntax-Highlighting verwendet. Da es mehr Informationen als Vervollständigungen bereitstellt, wird die Syntaxhervorhebung genauer.
  3. Es analysiert $argv in Fischfunktionen (und eingebauten). Fischfunktionen können einfacher gemacht werden und müssen nicht mehr nach getopt .
  4. Es ersetzt die Verwendungsspezifikation des Befehls. Dateien wie doc_src/complete.txt können verschwinden. Der Hilfetext wird direkt aus der Signatur abgeleitet (mit Lichtfilterung), entweder zur Build- oder zur Laufzeit.

Verwendungszweck

Die Befehle complete und function beide eine neue Option --signature (kurze Option -g ), deren Argument eine Signatur ist. Die Signatur ist ein gewöhnliches String-Argument und unterliegt daher den üblichen Anführungs- und Escape-Regeln.

Die Signatur ohne Escapezeichen muss gültiges _fish-flavored docopt_ sein, was eine etwas strengere Menge von docopt ist . Die Unterschiede werden hier beschrieben .

Wenn Sie eine Signatur angeben, können Sie den Befehlsnamen in complete weglassen und er wird aus der Signatur gelesen. Wenn Sie einen Befehlsnamen angeben, hat dieser Vorrang vor dem in der Signatur.

Syntax

Hinweis: Von Benutzern und Vervollständigungsautoren wird nicht erwartet, dass sie Experten auf diesem Gebiet werden. Stattdessen enthält die Manpage für complete und function einige Beispiele, die Benutzer kopieren und ändern können, indem sie einer (hoffentlich offensichtlichen) Syntax folgen. Da es sich um Fisch handelt, werden Syntaxfehler mit ausstehenden Diagnosemeldungen gemeldet.

Die Signatur besteht aus drei Abschnitten: "Verwendung", "Optionen" und "Bedingungen". Nur der Abschnitt Verwendung ist erforderlich. Abschnittsgrenzen basieren auf Einrückungen, wie Blöcke in Python. Andere Abschnitte werden von fish ignoriert, außer beim Drucken der Unterschrift für Hilfe.

Der Abschnitt Verwendung zeigt verschiedene Verwendungsmuster zum Aufrufen des Befehls. docopt.org beschreibt diese genauer, vorbehaltlich der Unterschiede im Fischgeschmack .

Das Literal "[Optionen]" in einem Verwendungsmuster ist ein Stellvertreter für den Abschnitt "Optionen". Für einzelne Optionen können Beschreibungen angegeben werden, die als Beschreibungen in den Registerkartenvervollständigungen erscheinen.

Der Abschnitt "Bedingungen" ist einzigartig für Docopt mit Fischgeschmack und legt zulässige Werte für Variablen fest. Geben Sie innerhalb des Abschnitts die Variable (einschließlich Klammern) an, gefolgt von mindestens zwei Leerzeichen und dann einer Argumentliste, die Subshells enthalten kann, identisch mit complete -a . Dies wird nur während der Tabulatorvervollständigung verwendet (der Abschnitt wird beim Drucken der Hilfe weggelassen.

Abgeleitete Bedingungen

Eine Variable kann abgeleitete Bedingungen haben, die auf einem Suffix ihres Namens basieren:

- *file -> only files
- *dir or *directory -> only directories
- *path -> any valid path (the destination does not have to exist, but intermediate directories do)
- *command or *cmd -> only commands (e.g. for sudo)

Beispiel: Usage: rmdir <directory> ... oder Usage: cat [<file> ...] werden nur zu Verzeichnissen bzw. Dateien vervollständigt. Die Syntaxhervorhebung überprüft auch diese Bedingungen. Dies macht es sehr einfach, ein allgemeines Verhalten bei der Vervollständigung von Tabs zu erreichen.

Argumentanalyse

Wenn eine Funktion eine Signatur hat, wird $argv entsprechend der Signatur geparst und die Variablen werden automatisch ausgefüllt. Dies basiert auf dem Design von

  • Optionen werden auf den entsprechenden Langnamen kanonisiert, falls vorhanden. Bindestriche werden durch Unterstriche ersetzt und dann wird opt_ vorangestellt, zB --foo => $opt_foo . Der Wert wird auf 1 gesetzt.
  • Ein Unterbefehl wie checkout entspricht der Variablen $cmd_checkout .
  • Der Name einer Variablen wird direkt verwendet. (Dies bedeutet, dass Sie bestimmte Variablennamen wie <status> , aber Variablennamen haben keinen Einfluss auf die Aufrufsyntax, so dass dies keine Belastung darstellt).

Beispiele für diese Signatur:

Usage: cowsay [options] [<message>...]
Options: -e, --eye <eyestr>          Specify eye string
         -f, --cow-file <cowname>    Specify cow file name

laufen mit:

cowsay -e XX --cow-file dragon hello world [<message>...]

führt zu den folgenden funktionsbezogenen Variablen und Werten:

  • $opt_eye = 1
  • $opt_cow_file = 1
  • $eyestr = XX
  • $Kuhname = Drache
  • $message = hallo world <- Liste der Länge 2

Natürlich wird $argv auch auf die vollständige Liste der Argumente gesetzt.

Bevorzugen Sie set -q innerhalb der Funktion, um das Vorhandensein von Flags zu überprüfen.

Autoritativ vs unautoritativ

Funktionssignaturen respektieren die Optionen -A/--authoritative und -u/--unauthoritative zu complete , und wir werden diese Optionen auch zu function hinzufügen.

Wenn eine Funktion mit einer autoritativen Signatur aufgerufen wird, werden ihre Argumente mit den Verwendungsspezifikationen abgeglichen. Wenn die Übereinstimmung nicht perfekt ist (nicht erkannte Optionen oder fehlende/überzählige Argumente), wird die Funktion nicht ausgeführt und stattdessen die Hilfe (von der Signatur abgeleitet) ausgegeben. Auf diese Weise wird einer Funktion eine Validierung erspart.

Wenn die Signatur der Funktion nicht autorisierend ist, bemüht sich fish nach besten Kräften, ein Muster auszuwählen und Variablen basierend darauf zu füllen, und die Funktion wird ausgeführt.

Standardmäßig sind Funktionssignaturen autorisierend. Dieses Verhalten gilt nur für Funktionen, nicht für externe Befehle.

Mehrere Unterschriften

Ein Befehl kann mehrere Signaturen haben. Dies ist praktisch, um einen großen Befehl wie git in mehrere Signaturen aufzuteilen (zB eine für jeden Unterbefehl).

Das Verhalten ist, als ob die mehreren Signaturen zu einer einzigen zusammengeführt würden. Bei Mehrdeutigkeiten hat die zuletzt angegebene Signatur Vorrang.

Ich habe noch nicht viel über docopt gelesen, aber ich mag die Richtung. Ich bin jedoch neugierig, wie die generierten Tab-Vervollständigungswerte in dieses Framework passen? Zum Beispiel vervollständigt die Tab-Vervollständigung für git-add relevante Dateinamen und git-checkout vervollständigt Zweignamen. Müssen wir weiterhin die bestehenden complete Optionen verwenden, oder hat docopt eine Möglichkeit, das anzugeben?

git checkout Tab-Vervollständigung auf alte Weise:

complete --no-files --command git \
         --description Branch \
         --arguments '(__fish_git_branches)' \
         --condition '__fish_git_using_command checkout'

Neuer Weg:

complete --signature '
    Usage: git checkout [<branch>]
    Conditions:
        <branch>  (__fish_git_branches)
'

Oder arbeite noch ein bisschen daran:

complete --signature '
    Usage:
        git checkout [-q | --quiet] [<checkout_target>]
        git checkout -b <new_branch>

    Options:
        -q, --quiet   Quiet mode
        -b, --branch  Create a new branch

    Conditions:
        <checkout_target>  (__fish_git_branches) (__fish_git_tags) (__fish_git_modified_files)
'

Wie Sie sehen, gibt es viel weniger Boilerplate und die Unterstützung für Unterbefehle ist kostenlos - nichts von dieser __fish_git_using_command Angelegenheit (obwohl Git-Aliases es komplizieren werden).

Soo ... Ich mag die allgemeine Idee, aber es gibt ein paar Fälle, an die wir denken müssen:

  • busctls "gestuftes" Zeug (auch in ip ) - zuerst der Bus, dann das Objekt, dann die Methode, dann die Argumente. Die Reihenfolge ist hier wirklich wichtig, und die Vervollständigung für jedes Argument hängt von den Argumenten davor ab
  • Option-before-command - dh git --help checkout , aber auch systemctl --now [enable|disable|mask|unmask] - dies hat leicht die Möglichkeit, die Signatur zu sprengen

Ich verstehe auch nicht ganz, warum es "Bedingungen" heißt - es ist nicht wie das alte complete --condition ("-n"), sondern eher wie complete --argument ("-a") - warum ist es nicht? heißt es nicht "Argument"? Wie würde das mit willkürlichen Bedingungen funktionieren? Als zusätzliches "-n" außerhalb der Signatur? Werden tatsächlich willkürliche Bedingungen verwendet oder nur für Unterbefehls-Spielereien?

Könnten wir auch Argumentbeschreibungen oder Hinweise haben (#2201)?

@faho Vielen Dank, dass Sie sich die Zeit genommen haben, es zu lesen und Ihre nachdenkliche Antwort: Lächeln:

Die Unterstützung von docopt für geordnete Positionsangaben ist leistungsstark. Sie können zum Beispiel schreiben:

Usage:
      ip link show <device>
      ip addr [add | del] <ifaddr> dev <devname>
      ip route [ add | del | change | append | replace | monitor ] <route>

usw. und es wird herausfinden, welches Muster verwendet werden soll. Zum Beispiel würde ip link route als Fehler gemeldet.

Für busctl haben wir wohl:

Usage: busctl call <service> <object> <interface> <method>

Sie können für jede Variable separate Vervollständigungen angeben. Es gibt jedoch keinen natürlichen Weg, um die Vervollständigungen für <object> von denen in <service> <object> abhängig zu machen, außer auf commandline wie wir es heute tun.

Optionen können in Bezug auf Positionsangaben in argv beliebig neu angeordnet werden: docopt geht davon aus, dass git --help checkout und git checkout --help sind. Weißt du, ob es irgendwelche Befehle gibt, die das verletzen? (Ich würde sagen, sie benehmen sich schlecht, aber wir müssen sie vielleicht trotzdem unterstützen).

Ich sollte erwähnen, dass es auch -- um anzuzeigen, dass die verbleibenden Argumente alle Positionsangaben sind.

Ich denke, "Argumente" ist ein viel klarerer Name als "Bedingungen", danke für den Vorschlag.

Ich mag die Idee, Argumentbeschreibungen zu integrieren. Haben Sie Ideen, wie diese integriert werden könnten? Die Idee ist, es wie Manpages aussehen zu lassen, aber diese setzen hier keinen großen Präzedenzfall.

Eine Möglichkeit besteht darin, sie wie Kommentare aussehen zu lassen:

Usage: ln [options] <source_file> [<target_file>]
Arguments:
    <source_file>  # Linked-from file
    <target_file>  # New link file

oder ein realistisches Beispiel, das Argumente erfordert:

Usage: ssh [<user> | <hostname>] [<command_to_run>] [options]
Arguments:
    <hostname>  # Remote host name
        (__fish_print_hostnames)
        (
        #Prepend any username specified in the completion to the hostname
        echo (commandline -ct)|sed -ne 's/\(.*@\).*/\1/p'
        )(__fish_print_hostnames)

im Grunde würde der Hinweis in derselben Zeile stehen wie der Variablenname. Was denken Sie?

Die Unterstützung von docopt für geordnete Positionsangaben ist leistungsstark. Sie können zum Beispiel schreiben:

Groß!

However there's no natural way to make the completions for <object> depend on those in <service>

(github scheint zu denken, dass mein gesamter Kommentar ein Zitat ist, wenn ich das nicht als Code zitiere, sorry)

Ponys wünschen: Wie wäre es, die anderen Argumente in spezielle Variablen für die Vervollständigungsfunktionen zu legen, zB

Usage: busctl call <service> <object> <interface> <method>
Arguments:
    <service> (__fish_busctl_services)
    <object>  (__fish_busctl_objects $service)

Es kann ein Problem geben, dass "$service" mit einer anderen Variablen kollidiert. Eventuell ist auch eine spezielle Syntax möglich, zB

<object> (__fish_busctl_objects <service>)

Weißt du, ob es irgendwelche Befehle gibt, die das verletzen?

Wenn Sie nach einem schlecht erzogenen, nicht guten, seltsamen Syntax-CLI-Tool suchen, ist ip immer ein großartiges Beispiel: smile:.

$ ip -f inet addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
inet 127.0.0.1/8 scope host lo
   valid_lft forever preferred_lft forever
$ ip addr -f inet
Command "-f" is unknown, try "ip addr help".

Eine Möglichkeit ist, sie wie Kommentare aussehen zu lassen

Das sieht gut aus, aber es bedeutet natürlich, dass Sie vorsichtig sein müssen, wo Sie tatsächliche Kommentare platzieren. Ich habe auch daran gedacht, den Argumentnamen als Beschreibung zu verwenden, aber das würde mit den "Rückverweisen" kollidieren und bedeutet, dass Sie beim Schreiben der Deklaration möglicherweise mehrmals eine schöne Beschreibung eingeben müssen.

Bearbeiten: Fügen Sie die tatsächliche IP-Ausgabe hinzu.

Oh, wie wäre es auch mit doppelten Optionen (#1315) - einige Befehle wollen sie, wie pacman , zB pacman -Su aktualisiert Pakete, während pacman -Suu auch herunterstufen.

Oder aptitude moo , was bis zu (IIRC) sieben "-v" braucht.

Mann, denkst du an alles!

Gezählte Flags können mit der Syntax ... , zB:

Usage: rsync -v... 

Dies ermöglicht eine korrekte Syntaxhervorhebung und -vervollständigung.

Für das Schreiben von Funktionen können wir den Wert der Variablen einfach auf ihre Zählung setzen, dh rsync -vvv würde zu $opt_verbose = 3

Eine weitere Schwachstelle des aktuellen Systems habe ich gestern getroffen: "Argumente auflisten".

Einige Befehle benötigen für einige Optionen mehrere Werte, die normalerweise durch ein "," getrennt sind.

Z.B

pacman -Syu --ignore linux,bbswitch,nvidia

die alles außer den Paketen "linux" (der Kernel), "nvidia" und "bbswitch" (die Kernel-Module sind) aktualisieren. Das aktuelle System überlässt es dem einzelnen Skript, sich darum zu kümmern, in diesem Fall müsste es z

pacman -Syu --ignore linux,bbs<TAB> zu "linux,bbswitch", nicht nur "bbswitch".

Die gpg-Vervollständigungen boten früher bedingungslos jede Vervollständigung für sich und mit einem angehängten "," an, was zu einer riesigen Argumentsuppe führte (obwohl alle Maskierungszeichen nicht halfen).

Dann gibt es noch #368 und #369 – Ponysay ist sogar komisch, wenn man alle Ponys ignoriert.

Um meine eigene Frage zu beantworten: docopt.org hat:

 -i <file>, --input <file>   # with comma, without "=" sign

es scheint also bereits zu funktionieren und ist ziemlich intuitiv.

Leider denke ich, dass das nicht das tut, was Sie sich erhoffen. Das Komma ist nur ein Trennzeichen in der Docopt-Syntax. Dies bedeutet nicht, dass in den Argumenten ein Trennzeichen erscheint.

Verzeihen Sie mir einen "plus-oneish"-Kommentar, aber ich möchte nur sagen, dass das absolut fantastisch ist. Ich schreibe viele Shell-Skripte für dies und das, und es scheint, als ob jedes Skript klein beginnt und dann Optionen und Argumente erweitert. getopt und getopts sind in Ordnung, aber ich finde normalerweise, dass sie wollen und am Ende manuell parsen. Das sieht nach der ultimativen Lösung aus! Leistungsstark und dennoch einfach zu bedienen und spart so viel Zeit. Ich kann es kaum erwarten, dies in Fish zu verwenden!

@alphapapa Schön, dass du so denkst, ich auch! Meine Hoffnung ist, dass wir eine Sammlung von Docopt-Beschreibungen von Unix-Befehlen anhäufen, die schließlich ein Eigenleben entwickeln und zu einem Repository für maschinenlesbare Befehlszeilenverwendungsspezifikationen werden, die in vielen weiteren Situationen jenseits von Fisch verwendet werden können. Es ist schon albern, dass es das noch nicht gibt!

@ridiculousfish Hm, das ist eine interessante Idee. Es scheint, als ob die meisten davon bereits in -h/--help und Manpages enthalten sein sollten, aber ich denke, nicht alle Dienstprogramme sind so gut dokumentiert. Ich würde jedoch vorschlagen, diese Docopt-Beschreibungen für jedes einzelne vorzuladen, da es für mich wie ein Albtraum klingt, ein separates Repository auf dem neuesten Stand zu halten. D:

https://github.com/mbrubeck/compleat für meine eigene Referenz - ein Haskell-Versuch mit einer minimalistischeren Syntax.

Ich war nur etwas langsam, um dies zu verstehen, weil es eine Menge Komplexität hinzufügt. Ich hoffe, über Möglichkeiten nachzudenken, es zu vereinfachen.

Dies würde es ermöglichen, die Git-Integration viel vollständiger zu machen, und wenn niemand sonst einen Versuch macht, werde ich mir das ansehen. Aber im Moment ist es so umständlich, zumal Git ziemlich komplex ist.

@bucaran xiaq scheint nicht hier zu sein, dieses Problem ist 3 Jahre her.

@pickfire Vielleicht ist er mit Fisch gemacht und wechselte elbischen ? :Lachen:

Gibt es hier Updates?

Ich werde das nachholen, wenn wir 2.3.0 veröffentlichen. Sie können jetzt jedoch im Docopt-Zweig damit spielen, wenn Sie dazu neigen.

Irgendwelche Updates jetzt, da 2.3.0 draußen ist?

@gusmonod Was versuchst du genau zu tun?

Nun, ich dachte daran, ein Fisherman-Plugin zu schreiben, das dieselbe Funktion hat, um es in einem meiner Projekte zu verwenden, also wollte ich wissen, ob dies irgendwann im Hauptzweig zusammengeführt wird.

@gusmonod Das sollte helfen können.

Ich wollte wissen, ob das irgendwann im Hauptzweig zusammengeführt wird.

Es wird. Der docopt-Zweig lebt (zuletzt aktualisiert vor 3 Tagen) und das ist der Plan.

Sollten wir ein getopt() Äquivalent für Fischskripte implementieren? Diese Ausgabe ist seit vier Jahren offen. Wie das von @floam geöffnete Problem #3403 getopt für die Verwendung durch fish-Skripte implementieren. Das ist grenzwertig trivial. Es würde uns erlauben, unsere Fischskripte (Funktionen) so zu parsen, dass sie mit eingebauten Befehlen kompatibel sind. Wenn dies implementiert ist, kann sowohl das Parsen von eingebauten als auch von Funktions-Flags geändert werden.

Wäre es möglich, getopts.fish in Fish selbst aufzunehmen? Es funktioniert sehr gut. Der einzige Nachteil, den ich gefunden habe, ist, dass alle Argumente nach dem ersten Nicht-Optionsargument als Nicht-Optionsargumente behandelt werden, anstatt das typische Verhalten der Verwendung von -- zum Beenden der Optionsliste.

Ich bin sicherlich auch nicht gegen ein getopt Äquivalent. (Hinweis: Ich denke, getopt ist der Bash getopts Integration überlegen, da getopt sowohl lange als auch kurze Versionen von Optionen zulässt.)

@alphapapa , die Tatsache, dass das Skript wgetopt() Funktion kompatibel ist, spricht dagegen, es zu verwenden. Es sei denn, es kann leicht geändert werden, um mit der Version kompatibel zu sein, die von unseren eingebauten Befehlen verwendet wird. Persönlich würde ich es vorziehen, unsere wgetopt() Funktion einfach als eingebauten Befehl bereitzustellen, der von Fischskripten verwendet werden kann. Somit ist die Kompatibilität gewährleistet. Können Sie auch einen Link zu dem Skript angeben, auf das Sie sich bezogen haben, damit wir seine Eignung als alternative Lösung bewerten können?

@ridiculousfish , Wie wahrscheinlich ist es, dass die Docopt-Lösung beispielsweise in den nächsten sechs Monaten veröffentlicht wird? Wenn die Wahrscheinlichkeit gering ist, möchte ich ein neues Problem eröffnen, um einen getopt Befehl zu implementieren, der von Fischskripten verwendet werden kann. Dies zu implementieren sollte fast trivial sein und würde es Befehlen ermöglichen, die als Funktionen implementiert sind, sich gegenüber dem Flag-Parsing identisch mit den Built-Ins zu verhalten.

Ups, ich dachte, getopts.fish hier schon verlinkt. Es sieht so aus, als ob das aktuelle Zuhause dafür https://github.com/fisherman/getopts ist und es scheint aktualisiert worden zu sein, seit ich es das letzte Mal angeschaut habe, daher bin ich mir nicht sicher, ob der von mir erwähnte Nachteil noch zutrifft.

... ist das eine getopt Implementierung in awk ? Das ist erstaunlich.

Verschieben wir die getopt-Konversation in eine neue Ausgabe.

Äh...mein Fehler, ich hätte mir den Link genauer ansehen sollen. Es ist vom gleichen Autor, aber anscheinend hat er es in einer awk umgeschrieben. Es scheint viel einfacher zu sein, aber das, auf das ich mich bezog, ist das hier: https://github.com/alphapapa/bucket/blob/master/getopts.fish Ich weiß nicht, ob es ein kanonisches Zuhause für den Fisch gibt -native Version...

Ich habe entschieden, dass der in dieser Ausgabe befürwortete Ansatz und sein Vorgänger, Nr. 447, nicht praktikabel sind. Siehe Ausgabe #4190 für einen bescheideneren Vorschlag, der die Kompatibilität mit bestehenden eingebauten Befehlen beibehält und es trivial macht, das gleiche Verhalten in Fischskripten zu haben. Ich beabsichtige, diese Lösung in den nächsten ein oder zwei Tagen zusammenzuführen, es sei denn, jemand schreit "Stopp".

Eine DocOpt-basierte Lösung könnte ideal (dh perfekt) sein, könnte aber nur in einer Hauptversion durchgeführt werden. Und da dieses Thema seit mehr als vier Jahren offen ist, ist nicht absehbar, dass es jemals umgesetzt wird. Zumal die zuvor zugesagte Frist für die Implementierung einer DocOpt-basierten Lösung nun mehr als drei Monate überschritten ist.

Ich sehe den Sinn einer DocOpt-basierten Lösung nicht . Praktikabilität und Klarheit übertrumpfen die Ästhetik einer DocOpt-Lösung.

Ich habe vor, das irgendwann mal wieder aufzunehmen. Ich denke, mein erster Versuch war zu komplex, also möchte ich einen Weg finden, es einfacher zu machen.

Ich denke, die Idee ist fatal und die Python-Implementierung scheint tot zu sein, da sie seit mehr als zwei Jahren nicht aktualisiert wurde und immer noch nicht als gut genug für eine 1.0-Version angesehen wird. Siehe https://github.com/docopt/docopt/issues/371

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen