Πρόσφατα χρειάστηκε να προσθέσω tab συμπλήρωση σε ένα script μου και βρήκα τη λειτουργικότητα πολύ ενδιαφέρουσα.
Σε αυτό το άρθρο θα εξοικειωθείτε με τη διαδικασία προσθήκης tab συμπλήρωσης στα script σας στη γραμμή εντολών του Bash.
Τι είναι η tab συμπλήρωση (bash completion);
Η tab συμπλήρωση είναι μια λειτουργικότητα μέσω της οποίας το Bash επιτρέπει στους χρήστες να πληκτρολογήσουν τις εντολές τους πιο εύκολα και γρήγορα. Αυτό το πετυχαίνει με το να παρουσιάζει πιθανές επιλογές ως συνέχεια της εντολής όταν οι χρήστες πατούν το tab
πλήκτρο καθώς την γράφουν.
$ git<tab><tab>
git git-receive-pack git-upload-archive
gitk git-shell git-upload-pack
$ git-s<tab>
$ git-shell
Πως δουλεύει;
Το script συμπλήρωσης είναι κώδικας που χρησιμοποιεί την συστημική bash εντολή complete
για να ορίσει ποιες προτάσεις συμπλήρωσης θα εμφανιστούν για ένα δεδομένο εκτελέσιμο πρόγραμμα.
Η φύση των προτάσεων αυτών ποικίλει από απλές στατικές έως περίπλοκες και δυναμικές επιλογές.
Γιατί να ασχοληθώ;
Είναι καλό να παρέχεται αυτή η λειτουργικότητα στους χρήστες των script:
- για να διευκολύνεται η πληκτρολόγηση κειμένου όταν μπορεί να συμπληρωθεί αυτόματα
- για να μπορούν να βλέπουν ποιες είναι οι πιθανές συνέχειες στις εντολές που πληκτρολογούν και
- για την αποφυγή λαθών και για την βελτίωση της εμπειρίας τους κρύβοντας τις μη διαθέσιμες και εμφανίζοντας τις διαθέσιμες επιλογές βάσει του τι έχουν ήδη πληκτρολογήσει
Ας ξεκινήσουμε
Να τι θα κάνουμε σε αυτό το βοήθημα.
Αρχικά, θα δημιουργήσουμε ένα πολύ απλό εκτελέσιμο script που θα το πούμε dothis
. Αυτό θα είναι το script που στη συνέχεια θα προσθέσουμε τη λειτουργικότητα για την tab συμπλήρωση.
Το μόνο που θα κάνει το script είναι να εκτελεί την εντολή που βρίσκεται σε μια συγκεκριμένη θέση στο ιστορικό των εντολών του χρήστη. Τη θέση της εντολής στο ιστορικό θα την δέχεται σαν παράμετρο κατά την εκτέλεση. Για παράδειγμα, η παρακάτω εντολή θα εκτελέσει την εντολή ls -a
δεδομένου ότι η τελευταία βρισκεται στη θέση 235
στο ιστορικό εντολών του χρήστη:
dothis 235
Στη συνέχεια θα δημιουργήσουμε το script tab συμπλήρωσης που θα εμφανίζει τις εντολές μαζί με τη θέση τους, από το ιστορικό εντολών του χρήστη
και τέλος θα το συνδέσουμε με το πρόγραμμα dothis
που προανέφερα.
$ dothis <tab><tab>
215 ls
216 ls -la
217 cd ~
218 man history
219 git status
220 history | cut -c 8-
Συγκεντρωθείτε bash
και τα καταφέρουμε με την πρώτη.
Δημιουργία του εκτελέσιμου προγράμματος
Δημιουργήστε ένα αρχείο με το όνομα dothis
στο φάκελο που επιθυμείτε και προσθέστε τον παρακάτω κώδικα:
if [ -z "$1" ]; then
echo "No command number passed"
exit 2
fi
exists=$(fc -l -1000 | grep ^$1 -- 2>/dev/null)
if [ -n "$exists" ]; then
fc -s -- "$1"
else
echo "Command with number $1 was not found in recent history"
exit 2
fi
Σημειώσεις:
- Πρώτα ελέγχουμε αν το πρόγραμμα κλήθηκε με παράμετρο
- Στη συνέχεια ελέγχουμε αν ο συγκεκριμένος αριθμός αντιστοιχεί σε κάποια από τις τελευταίες 1000 εντολές του ιστορικού του χρήστη.
- αν ναι τότε την εκτελούμε με χρήση της εντολής
fc
- διαφορετικά εμφανίζουμε ένα μήνυμα λάθους
- αν ναι τότε την εκτελούμε με χρήση της εντολής
Μετατρέψτε το script σε εκτελέσιμο με την παρακάτω εντολή:
chmod +x ./dothis
Θα εκτελούμε συχνά αυτό το script σε αυτό το βοήθημα οπότε συνιστώ να το μεταφέρετε σε ένα φάκελο που ανήκει στην μεταβλητή PATH του περιβάλλοντός σας ωτε να μπορούμε να το προσπελάσουμε από παντού απλά πληκτρολογώντας dothis
.
Το δικό μου το έβαλα στο home bin
πληκτρολογώντας:
install ./dothis ~/bin/dothis
Μπορείτε να κάνετε το ίδιο δεδομένου ότι έχετε φάκελο ~/bin
ο οποίος εμπεριέχεται στην PATH
μεταβλητή σας.
Δοκιμάστε να δείτε ότι δουλεύει:
dothis
Θα έπρεπε να δείτε αυτό:
$ dothis
No command number passed
Done.
Δημιουργία του script tab συμπλήρωσης
Δημιουργήστε ένα αρχείο με όνομα dothis-completion.bash
. Από εδώ και στο εξής θα αναφέρομαι στο αρχείο αυτό με τον όρο script συμπλήρωσης.
Αφού του προσθέσουμε κώδικα, θα εκτελέσουμε την εντολή source
για να το “ενεργοποιήσουμε”.
Θα εκτελούμε την source
σε αυτό το αρχείο κάθε φορά που αλλάζουμε το περιεχόμενό του ώστε να ισχύουν οι αλλαγές.
Θα συζητήσουμε επιλογές ώστε να να γίνεται η ενεργοποίηση αυτή κάθε φορά που ανοίγει νέα bash κονσόλα αργότερα.
Στατική συμπλήρωση
Υποθέστε ότι το dothis
υποστήριζε μια στατική λίστα από παραμέτρους, για παράδειγμα:
τώρα
αύριο
ποτέ
Θα χρησιμοποιήσουμε την εντολή complete
για να καταχωρήσουμε αυτή τη λίστα ως επιλογές για tab συμπλήρωση. (Για να χρησιμοποιήσουμε τη σωστή ορολογία, θα χρησιμοποιήσουμε την εντολή complete
για να ορίσουμε τις προδιαγραφές συμπλήρωσης (compspec) για το πρόγραμμά μας.)
Προσθέστε αυτά στο script συμπλήρωσης.
#/usr/bin/env bash
complete -W "τώρα αύριο ποτέ" dothis
Τι κάναμε με τη χρήση της παραπάνω εντολής complete
:
- χρησιμοποιήσαμε την επιλογή
-W
(wordlist) για να παρέχουμε τη λίστα που θα χρησιμοποιηθεί για συμπλήρωση - ορίσαμε σε ποιο πρόγραμμα αυτή η λίστα θα παρέχεται για tab συμπλήρωση (η τελευταία παράμετρος:
dothis
)
“Ενεργοποιήστε” το αρχείο (δεν βρήκα πιο δόκιμο όρο για να περιγράψω τη σημασία της εκτέλεσης της εντολής “source”):
source ./dothis-completion.bash
Τώρα προσπαθήστε να πατήσετε το πλήκτρο tab δύο φορές όπως παρακάτω:
$ dothis <tab><tab>
αύριο ποτέ τώρα
Προσπαθήστε ξανά αφού βάλετε και ένα τ
:
$ dothis τ<tab><tab>
τώρα
Magic! Οι επιλογές συμπλήρωσης φιλτράρονται αυτόματα ώστε να εμφανιστούν μόνο αυτές που ξεκινούν από τ
.
Σημείωση: Οι επιλογές συμπλήρωσης δεν εμφανίζονται με τη σειρά που τις ορίσαμε στη λίστα λέξεων, ταξινομούνται αυτόματα.
Υπάρχουν πολλές άλλες επιλογές πέραν της -W
που χρησιμοποιήσαμε προηγουμένως. Οι περισσότερες παράγουν συμπληρώσεις με στατικό τρόπο, εννοώντας ότι δεν επεμβαίνουμε δυναμικά στο φιλτράρισμα τους.
Για παράδειγμα, αν θέλαμε να έχουμε ως tab συμπληρώσεις για το εκτελέσιμο dothis
τους φακέλους που βρίσκονται στον τρέχων φάκελο, θα αλλάζαμε την εντολή ως εξής:
complete -A directory dothis
Πατώντας το tab μετά το dothis
, θα λαμβάναμε μια λίστα σαν την παρακάτω:
$ dothis <tab><tab>
dir1/ dir2/ dir3/
Βρείτε ολόκληρη τη λίστα με τις διαθέσιμες επιλογές εδώ.
Δυναμική tab συμπλήρωση
Θέλουμε να παράγουμε τις προτάσεις συμπλήρωσης για το εκτελέσιμο script μας με την ακόλουθη λογική:
- αν ο χρήστης πατήσει το tab αμέσως μετά την εντολή, θα δείχνουμε τις τελευταίες 50 εκτελεσθείσες εντολές μαζί με τον αριθμό που αντιστοιχεί στη θέση τους στο ιστορικό
- αν ο χρήστης πατήσει το tab αφού έχει πληκτρολογήσει και έναν αριθμό τότε θα εμφανίζουμε όλες τις εντολές των οποίων η θέση στο ιστορικό του, είναι ή ξεκινά με αυτόν τον αριθμό
- αν ο χρήστης πατήσει το tab αφού έχει πληκτρολογήσει και έναν αριθμό και υπάρχει μόνο μια εντολή με θέση που είναι ή ξεκινά με τον αριθμό αυτό τότε θα συμπληρώσουμε απευθείας όλο τον αριθμό (αν έχετε μπερδευτεί μην ανησυχείτε, θα ξεκαθαρίσουν όλα παρακάτω)
Ας ξεκινήσουμε με το να ορίσουμε μια μέθοδο που θα εκτελείται κάθε φορά που ο χρήστης θα “ζητά” προτάσεις συμπλήρωσης για την εντολή dothis
(πατώντας το tab). Αλλάξτε το script συμπλήρωσης ως εξής:
#/usr/bin/env bash
_dothis_completions()
{
COMPREPLY+=("τώρα")
COMPREPLY+=("αύριο")
COMPREPLY+=("ποτέ")
}
complete -F _dothis_completions dothis
Σημειώστε τα παρακάτω:
- χρησιμοποιήσαμε την επιλογή
-F
στην εντολήcomplete
ορίζοντας ότι η_dothis_completions
είναι η μέθοδος που θα παρέχει τις προτάσεις συμπλήρωσης για τοdothis
εκτελέσιμο - η
COMPREPLY
είναι μια μεταβλητή τύπου πίνακα που χρησιμοποιείται για να αποθηκεύει τις προτάσεις συμπλήρωσης - ο μηχανισμός συμπλήρωσης χρησιμοποιεί τη συγκεκριμένη μεταβλητή για να εμφανίσει τα περιεχόμενά της ως προτάσεις συμπλήρωσης
Τώρα, ενεργοποιήστε το script συμπλήρωσης και κατόπιν δοκιμάστε να πατήσετε tab μετά το εκτελέσιμο dothis
:
$ dothis <tab><tab>
αύριο ποτέ τώρα
Τέλεια. Παράγουμε τις ίδιες προτάσεις συμπλήρωσης όπως πριν που χρησιμοποιήσαμε την επιλογή -W
. Ή μήπως όχι; Δοκιμάστε το παρακάτω:
$ dothis ποτ<tab><tab>
αύριο τώρα ποτέ
Όπως βλέπετε, παρόλου που έχουμε πληκτρολογήσει ποτ και μετά ζητήσαμε προτάσεις συμπλήρωσης πατώντας το tab
, οι διαθέσιμες προτάσεις συμπλήρωσης παραμένουν οι ίδιες, αφιλτράριστες και τίποτα δε συμπληρώνεται αυτόματα (κανονικά θα έπρεπε κατευθείαν να συμπληρωθεί η λέξη ποτέ
χωρίς καν να εμφανιστούν προτάσεις συμπλήρωσης αφού είναι η μόνη επιλογή που ξεκινά από ποτ
).
Γιατί συμβαίνει αυτό;
- Τα περιεχόμενα της μεταβλητής
COMPREPLY
εμφανίζονται πάντα. Η μέθοδος είναι υπεύθυνη να προσθέτει/αφαιρεί προτάσεις από εδώ και στο εξής. - Αν η
COMPREPLY
μεταβλητή είχε μόνο ένα στοιχείο τότε η λέξη θα συμπληρωνόταν αυτόματα στην εντολήdothis
. Εφόσον η τρέχουσα υλοποίησή μας πάντα αποθηκεύει στη μεταβλητή τις ίδιες τρεις λέξεις, αυτό δε θα συμβεί.
Θα μας σώσει η compgen
: μια συστημική εντολή που παράγει προτάσεις συμπλήρωσης υποστηρίζοντας σχεδόν όλλες τις επιλογές που υποστηρίζει και η συστημική εντολή complete
που χρησιμοποιούσαμε ως τώρα (πχ. -W
για λίστα λέξεων, -d
για φακέλους) και φιλτράρει τις προτάσεις βάσει του τι έχει ήδη πληκτρολογηθεί από το χρήστη.
Και πάλι, μην ανησυχείτε αν έχετε μπερδευτεί, τα πάντα θα ξεκαθαρίσουν παρακάτω.
Πληκτρολογήστε τα παρακάτω στη γραμμή εντολών για να κατανοήσετε καλύτερα τη κάνει η compgen
:
$ compgen -W "τώρα αύριο ποτέ"
αύριο
τώρα
ποτέ
$ compgen -W "τώρα αύριο ποτέ" τ
τώρα
$ compgen -W "τώρα αύριο ποτέ" α
αύριο
Οπότε τώρα μπορούμε να χρησιμοποιήσουμε την compgen
αλλά πρέπει να βρούμε πρώτα τι έχει πληκτρολογήσει ο χρήστης μετά το dothis
.
Η λειτουργικότητα tab συμπλήρωσης ευτυχώς παρέχει μεταβλητές που σχετίζονται με την συμπλήρωση που είναι υπό εκτέλεση. Παραθέτω τις πιο σημαντικές:
COMP_WORDS
: ένας πίνακας με όλες τις λέξεις που έχουν πληκτρολογηθεί μετά από το όνομα του εκτελέσιμου στο οποίο έχει συνδεθεί τοcompspec
(στην περίπτωσή μας: όλες τις λέξεις που έχουν πληκτρολογηθεί μετά τοdothis
)COMP_CWORD
: ένας αριθμός που δείχνει σε ποια θέση του πίνακαCOMP_WORDS
βρίσκεται ο κέρσορας - με άλλα λόγια, σε ποια λέξη ήταν ο κέρσορας όταν πατήθηκε το tabCOMP_LINE
: ολόκληρη η τρέχουσα εντολή
Για να προσπελάσουμε την λέξη που πληκτρολογήθηκε αμέσως μετά το dothis
αρκεί να χρησιμοποιήσουμε την τιμή του COMP_WORDS[1]
Αλλάξτε το script συμπλήρωσης ξανά:
#/usr/bin/env bash
_dothis_completions()
{
COMPREPLY=($(compgen -W "τώρα αύριο ποτέ" "${COMP_WORDS[1]}"))
}
complete -F _dothis_completions dothis
Ενεργοποιήστε το και ορίστε:
$ dothis
αύριο τώρα ποτέ
$ dothis α
αύριο
Τώρα, αντί των λέξεων τώρα, αύριο, ποτέ, Θα θέλαμε να δούμε τους αριθμούς που είναι στην ουσία οι θέσεις των εντολών από το ιστορικό του χρήστη.
Η εντολή fc -l
ακολουθούμενη από έναν αρνητικό αριθμό -n
εμφανίζει τις τελευταίες n εντολές που εκτελέστηκαν.
Οπότε θα την χρησιμοποιήσουμε ως εξής:
fc -l -50
εμφανίζοντας τις τελευταίες 50 εντολές μαζί με τον αριθμό της θέσης τους στο ιστορικό. Ο μόνος χειρισμός που πρέπει να κάνουμε είναι να αντικαταστήσουμε τα tabs με κενά διαστήματα ώστε να εμφανίζονται σωστά από τον μηχανισμό των συμπληρώσεων του Bash.
sed
βόηθα μας.
Αλλάξτε το script συμπλήρωσης ως εξής:
#/usr/bin/env bash
_dothis_completions()
{
COMPREPLY=($(compgen -W "$(fc -l -50 | sed 's/\t//')" -- "${COMP_WORDS[1]}"))
}
complete -F _dothis_completions dothis
Ενεργοποιήστε το script συμπλήρωσης και δοκιμάστε στη γραμμή εντολών:
$ dothis <tab><tab>
632 source dothis-completion.bash 649 source dothis-completion.bash 666 cat ~/.bash_profile
633 clear 650 clear 667 cat ~/.bashrc
634 source dothis-completion.bash 651 source dothis-completion.bash 668 clear
635 source dothis-completion.bash 652 source dothis-completion.bash 669 install ./dothis ~/bin/dothis
636 clear 653 source dothis-completion.bash 670 dothis
637 source dothis-completion.bash 654 clear 671 dothis 6546545646
638 clear 655 dothis 654 672 clear
639 source dothis-completion.bash 656 dothis 631 673 dothis
640 source dothis-completion.bash 657 dothis 150 674 dothis 651
641 source dothis-completion.bash 658 dothis 675 source dothis-completion.bash
642 clear 659 clear 676 dothis 651
643 dothis 623 ls -la 660 dothis 677 dothis 659
644 clear 661 install ./dothis ~/bin/dothis 678 clear
645 source dothis-completion.bash 662 dothis 679 dothis 665
646 clear 663 install ./dothis ~/bin/dothis 680 clear
647 source dothis-completion.bash 664 dothis 681 clear
648 clear 665 cat ~/.bashrc
Καθόλου κακό.
Έχουμε ένα πρόβλημα ωστόσο. Προσπαθήστε να πληκτρολογήσετε έναν αριθμό όπως τον βλέπετε στις προτάσεις συμπλήρωσης και πατήστε το tab ξανά.
$ dothis 623<tab>
$ dothis 623 ls 623 ls -la
...
$ dothis 623 ls 623 ls 623 ls 623 ls 623 ls -la
Αυτό συμβαίνει γιατί στο script συμπλήρωσής μας χρησιμοποιήσαμε την τιμή της ${COMP_WORDS[1]}
ώστε να ελέγχουμε την πρώτη πάντα λέξη που πληκτρολογήθηκε μετά το dothis
(ο αριθμός 623
στην παραπάνω απόσπασμα). Οπότε ο μηχανισμός συμπλήρωσης συνεχίζει να προτείνει ξανά και ξανά την ίδια επιλογή πατώντας το tab.
Για να το διορθώσουμε αυτό, δε θα επιτρέπουμε κανένα είδος συμπλήρωσης να λάβει χώρα αν τουλάχιστον μια λέξη έχει ήδη συμπληρωθεί. Θα προσθέσουμε λοιπόν μια συνθήκη ελέγχοντας το μέγεθος της προαναφερθείσας COMP_WORDS
μεταβλητής.
#/usr/bin/env bash
_dothis_completions()
{
if [ "${#COMP_WORDS[@]}" != "2" ]; then
return
fi
COMPREPLY=($(compgen -W "$(fc -l -50 | sed 's/\t//')" -- "${COMP_WORDS[1]}"))
}
complete -F _dothis_completions dothis
Ενεργοποιήστε το script συμπλήρωσης και ξαναδοκιμάστε.
$ dothis 623<tab>
$ dothis 623 ls -la<tab> # Επιτυχία, δεν συμβαίνει συμπλήρωση εδώ
Υπάρχει ωστόσο και κάτι άλλο που δε μας αρέσει. Θέλουμε να εμφανίζουμε τις θέσεις μαζί με τις αντίστοιχες εντολές ώστε να βοηθήσουμε τους χρήστες να αποφασίσουν ποια είναι η εντολή που θέλουν να εκτελέσουν αλλά όταν υπάρχει μόνο μια πρόταση συμπλήρωσης και ο μηχανισμός τη συμπληρώνει αυτόματα, δεν θα έπρεπε να συμπληρώνεται και η εντολή παρά μόνο ο αριθμός.
Με άλλα λόγια, το dothis
δέχεται μόνο έναν αριθμό και δεν έχουμε προσθέσει ελέγχους για περισσότερες παραμέτρους. Όταν μέθοδος που υπολογίζει τις προτάσεις συμπληρώσεων βρίσκε μόνο ένα αποτέλεσμα τότε θα πρέπει να πετσοκόψουμε (trim :D) το λεκτικό που περιέχει τον αριθμό και την εντολή ώστε να μείνει μόνο ο αριθμός.
Για να το πετύχουμε αυτό, θα κρατήσουμε το αποτέλεσμα τις εντολής compgen
σε μια μεταβλητή τύπου πίνακα, και αν το μέγεθος της είναι 1 τότε θα επεξεργαστούμε το μοναδικό στοιχείο της ώστε να μείνει μόνο ο αριθμός. Διαφορετικά θα αφήσουμε την μεταβλητή ως έχει.
Αλλάξτε το script συμπλήρωσης ως εξής:
#/usr/bin/env bash
_dothis_completions()
{
if [ "${#COMP_WORDS[@]}" != "2" ]; then
return
fi
# keep the suggestions in a local variable
local suggestions=($(compgen -W "$(fc -l -50 | sed 's/\t/ /')" -- "${COMP_WORDS[1]}"))
if [ "${#suggestions[@]}" == "1" ]; then
# if there's only one match, we remove the command literal
# to proceed with the automatic completion of the number
local number=$(echo ${suggestions[0]/%\ */})
COMPREPLY=("$number")
else
# more than one suggestions resolved,
# respond with the suggestions intact
COMPREPLY=("${suggestions[@]}")
fi
}
complete -F _dothis_completions dothis
Αυτόματη ενεργοποίηση του script tab συμπλήρωσης
Αν θέλετε να ενεργοποιήσετε τις συμπληρώσεις για το εκτελέσιμο μόνο για εσάς, το μόνο που χρειάζεται να κάνετε είναι να προσθέσετε της παρακάτω εντολή στο αρχείο σας ~/.bashrc
:
source <path-to-your-script>/dothis-completion.bash
Αν θέλετε να τις ενεργοποιήσετε για όλους τους χρήστες τότε μπορείτε να αντιγράψετε το script συμπλήρωσης στο φάκελο /etc/bash_completion.d/
και θα φορτώνεται αυτόματα από το Bash.
Τελειοποίηση του script συμπλήρωσης
Μερικά επιπλέον βήματα για καλύτερα αποτελέσματα.
Εμφανίζοντας κάθε πρόταση συμπλήρωσης σε νέα γραμμή
Στο script συμπλήρωσης που χρειάστηκε να δημιουργήσω, επίσης έπρεπε να εμφανίζω προτάσεις που αποτελούνταν από δύο τμήματα. Ήθελα να εμφανίζω το πρώτο τμήμα με το εξ ορισμού χρώμα των γραμμάτων της κονσόλας και το δεύτερο τμήμα με γκρι χρώμα ώστε να φαίνεται ότι ήταν απλά βοηθητικό κείμενο. Στο παράδειγμά μας, θα ήταν ωραίο να παρουσιάζουμε τους αριθμούς με το εξ ορισμού χρώμα αλλά το χρώμα των εντολών να ήταν κάτι λιγότερο χτυπητό στο μάτι.
Δυστυχώς, αυτό δεν είναι δυνατόν (τουλάχιστον για την ώρα) γιατί ο μηχανισμός συμπλήρωσης εμφανίζει τις προτάσεις ως καθαρό κείμενο και οι οδηγίες χρώματος δεν εφαρμόζονται (για παράδειγμα, αυτό \e[34mουρανός
θα εμφανιζόταν ακριβώς όπως το βλέπετε και όχι η λέξη ουρανός σε μπλε χρώμα).
Αυτό που μπορούμε ωστόσο να κάνουμε για να βελτιώσουμε την εμπειρία των χρηστών (ή όχι :D) είναι να εμφανίζουμε την κάθε πρόταση συμπλήρωσης σε νέα γραμμή. Ο τρόπος για να το κάνουμε αυτό δεν είναι ο προφανής γιατί δεν μπορούμε απλά να προσθέσουμε στο τέλος κάθε πρότασης τον χαρακτήρα αλλαγής γραμμής αφού ο μηχανισμός συμπλήρωσης δεν θα τον μεταφράσει σε αλλαγή γραμμής αλλά θα τον δείξει ως κείμενο (\n
).
Θα ακολουθήσουμε ένα μάλλον hackish τρόπο και θα προσθέτουμε κενά στο τέλος κάθε πρότασης συμπλήρωσης, τόσα ώστε το τελικό πλήθος των χαρακτήρων της πρότασης (με τα κενά) να είναι ίσο με το πλήθος των χαρακτήρων που χωρά η κάθε γραμμή της κονσόλας.
printf
βόηθα μας.
Αλλάξτε το script συμπλήρωσης ως εξής:
#/usr/bin/env bash
_dothis_completions()
{
if [ "${#COMP_WORDS[@]}" != "2" ]; then
return
fi
local IFS=$'\n'
local suggestions=($(compgen -W "$(fc -l -50 | sed 's/\t//')" -- "${COMP_WORDS[1]}"))
if [ "${#suggestions[@]}" == "1" ]; then
local number="${suggestions[0]/%\ */}"
COMPREPLY=("$number")
else
for i in "${!suggestions[@]}"; do
suggestions[$i]="$(printf '%*s' "-$COLUMNS" "${suggestions[$i]}")"
done
COMPREPLY=("${suggestions[@]}")
fi
}
complete -F _dothis_completions dothis
Ενεργοποιήστε το και δοκιμάστε:
dothis <tab><tab>
...
499 source dothis-completion.bash
500 clear
...
503 dothis 500
Done.
Προσαρμόσιμη συμπεριφορά
Στην περίπτωσή μας, ορίσαμε καρφωτά να εμφανίζονται οι τελευταίες 50 εκτελέσιμες εντολές όταν πατιέται το tab χωρίς να έχει πληκτρολογηθεί κάποιος αριθμός. Θα ήταν καλύτερο να αφήνουμε το χρήστη να επιλέγει πόσες θέλει να είναι αυτές οι εντολές (π.χ. οι τελευταίες 100) και αν δεν έχει ορίσει την επιθυμία του τότε εξ ορισμού να δείχνουμε τις τελευταίες 50,
Για να το πετύχουμε αυτό, θα ελέγχουμε την τιμή μιας μεταβλητής από το περιβάλλον του χρήστη, ας πούμε DOTHIS_COMPLETION_COMMANDS_NUMBER
.
Αλλάξτε για τελευταία φορά το script συμπλήρωσης:
#/usr/bin/env bash
_dothis_completions()
{
if [ "${#COMP_WORDS[@]}" != "2" ]; then
return
fi
local commands_number=${DOTHIS_COMPLETION_COMMANDS_NUMBER:-50}
local IFS=$'\n'
local suggestions=($(compgen -W "$(fc -l -$commands_number | sed 's/\t//')" -- "${COMP_WORDS[1]}"))
if [ "${#suggestions[@]}" == "1" ]; then
local number="${suggestions[0]/%\ */}"
COMPREPLY=("$number")
else
for i in "${!suggestions[@]}"; do
suggestions[$i]="$(printf '%*s' "-$COLUMNS" "${suggestions[$i]}")"
done
COMPREPLY=("${suggestions[@]}")
fi
}
complete -F _dothis_completions dothis
Ενεργοποιήστε το και δοκιμάστε:
export DOTHIS_COMPLETION_COMMANDS_NUMBER=5
$ dothis <tab><tab>
505 clear
506 source ./dothis-completion.bash
507 dothis clear
508 clear
509 export DOTHIS_COMPLETION_COMMANDS_NUMBER=5
Χρήσιμοι σύνδεσμοι
- Το script συμπλήρωσης που ήταν η αφορμή για να γράψω αυτό το άρθρο (
goto
) - Το script συμπλήρωσης του Git
- Bash Reference Manual: Programmable Completion
- Bash Reference Manual: Programmable Completion Builtins
- Bash Reference Manual: A Programmable Completion Example
- Bash Reference Manual: Bash Variables
Κώδικας και σχόλια
Μπορείτε να βρείτε τον κώδικα από αυτό το άρθρο στο GitHub.
Για feedback, σχόλια, λάθη κ.λπ. παρακαλώ ανοίξτε ένα issue στο αποθετήριο.
Μεγάλο άρθρο, φωτογραφία γάτας
Να σας συστήσω των debugger μου.
Αυτό ήταν. Τελειώσαμε. Καλή συνέχεια.