Τετάρτη, Ιανουαρίου 19, 2011

vi stories (και κανά-δυο tips)

Πρώτη επαφή με τον vi, κάποια χρόνια πριν, στο εργαστήριο των ΛΣ ΙΙ. "Όποιος δεν ξέρει να χειρίζεται vi στο τέλος του εξαμήνου, κόβεται αυτόματα." Ακολούθησε ένα γενικό στραβομουτσούνιασμα στην αίθουσα και 20κάτι άτομα πάλευαν για τους επόμενους μήνες να συνηθίσουν τα τρία modes του vi.

Για κάποιο λόγο, μόνο εγώ είχα ενθουσιαστεί - και μάλλον ήταν ο λόγος που κάποιοι με κοιτούσαν περίεργα. Απαξιώ όμως, για αυτό και έκατσα και ασχολήθηκα με τον vi (και τον vim - vi improved) και εκτός μαθήματος, και αργότερα και εκτός σχολής. Κατέληξα να βγάλω όλη την πτυχιακή του master σε vi - σετάρισμα των router, scripting, γράψιμο του thesis report παρέα με LaTeX (άλλη ταλαιπωρία από κει, αποτελεσματικό όμως).

Είμαι σίγουρος ότι σε αυτό το σημείο οι περισσότεροι κουνάτε το κεφάλι σας αποδοκιμαστικά. Haters gonna hate, απαξιώ.

Το θέμα είναι όμως ότι όσο δύστροπος και unfriendly μπορεί να είναι ο vi, είναι ένας ελαφρύς αλλά ΠΟΛΥ ισχυρός text editor από μόνος του, πριν ακόμα βάλεις plugins ή τον παραμετροποιήσεις. Αυτό ακριβώς είναι που τον κάνει 1η επιλογή σε άτομα που πρέπει να δουλεύουν σε διαφορετικά συστήματα. Δεν έχει σημασία αν δουλεύω στο Macbook μου, στον Debian server, στο χακαρισμένο με OpenWRT Linksys, στον Bifrost/Linux router, στο FreeBSD μηχάνημα - ο vi είναι εκεί, με τα ίδια shortcuts, με το ίδιο functionality. ΟΚ ίσως όχι το ίδιο ακριβώς functionality, τα desktop συστήματα συνήθως έχουν vim και όχι απλό vi, αλλά δεν πειράζει να σου λείψουν μερικές υπερ-προχωρημένες λειτουργίες πάνω στο embedded σύστημα του bluetooth handsfree σου (λέμε τώρα). Υπάρχει σχεδόν παντού και για αυτό ακριβώς τον θεωρώ ως το πρώτο πράγμα που πρέπει να μαθαίνει ένας εκκολαπτόμενος sysadmin ή network engineer.

Νταξ, μην αρχίσετε οι πιστοί της Εκκλησίας του Emacs τις επιθέσεις. Έτυχε να μάθω πρώτα vi και δεν έτυχε να ασχοληθώ ποτέ με Emacs, αυτό είναι όλο. Φαντάζομαι ότι τα ίδια περίπου ισχύουν και για τον Emacs, αν και έχω την εντύπωση ότι υπάρχει μεγαλύτερη δυνατότητα παραμετροποίησης μεν, μικρότερο portability δε.

Σύντομο ανέκδοτο: ο technical supervisor της πτυχιακής στο μάστερ είναι linux guru παλιάς κοπής και Emacs ninja - όταν βλέπεις στο X-mailer field "Emacs+κάποιοplugin", ΞΕΡΕΙΣ. Όταν με είδε πρώτη φορά να κάνω edit ένα configuration file σε vi, ψιλοχλώμιασε. "No, no, don't use that, it's no good." Την άλλη βδομάδα, άρχισα να κουβαλάω μαζί μου την αγαπημένη μου κούπα του καφέ, The Mug of Vi References, η οποία καθόταν επιδεικτικά δίπλα στο πληκτρολόγιο. Δεν νομίζω ότι έχω ξαναδεί άνθρωπο να προσπαθεί να αγνοήσει κάτι με τέτοια αποτυχία. Είμαστε κι εμείς, αλλά είστε κι εσείς...

Ναι, η εκμάθηση του vi είναι μανίκι, αλλά οι πραγματικοί λόγοι είναι δύο μόνο.
α) Τα operation modes και η λογική τους είναι λίγο περίεργη (ακολουθεί σύντομο tutorial στο τέλος), τελείως διαφορετική από την WYSIWYG λογική απεχθών προγραμμάτων όπως Notepad, Word κλπ. Ο κόσμος στραβώνει.
β) Ο κόσμος δεν κάθεται να μάθει keyboard shortcuts. Θα επιλέξω αυτή την παράγραφο με το mouse, θα κάνω δεξί κλικ, θα κάνω κλικ στο copy κλπ κλπ. Μόλις μάθεις να δουλεύεις αποκλειστικά με πληκτρολόγιο, δύσκολα γυρνάς πίσω.

Πιστεύω ότι σαν χρήστης vi έχω δρόμο ακόμα - είμαι ένας μικρός vi padawan. Το functionality που παρέχει είναι ατέλειωτο και ο vim, ο οποίος αναπτύσσεται ενεργά, προσθέτει συνεχώς καινούρια χαρακτηριστικά. Δεν θα απαριθμήσω features - δεν ξέρω ούτε τα μισά. Θα γράψω όμως μερικά tips που μπορούν να βοηθήσουν τους αρχάριους.

- Με :set number εμφανίζεται αρίθμηση των γραμμών στα αριστερά, πολύ χρήσιμο για όλες τις λειτουργίες που θέλουν πλήθος γραμμών (π.χ. 13dd). Όσοι έχετε Vim 7.3, :set rnu για σχετική αρίθμηση - ο αριθμός δίπλα από την γραμμή δείχνει την σχετική απόσταση από την γραμμή του κέρσορα.

- Το find and replace all matches γράφεται :%s/old_text/new_text/g

- Αυτό κάπου το είδα πρόσφατα, αλλά δεν θυμάμαι που. Τα :help! και :Ni! επιστρέφουν εξυπνάδες :)

- Προσωρινή έξοδος στο shell με :sh. Ιδιαίτερα χρήσιμο όταν έχω κάνει 5-10-50 αλλαγές σε ένα αρχείο, κάνω :w και μου λέει Read-only. Drop to shell με :sh, αλλαγή δικαιωμάτων ή remount του δίσκου ως writable και επιστροφή στο vi γράφοντας exit.

- :make για να αρχίσει η εκτέλεση του make, σύμφωνα με το makefile που έχεις ετοιμάσει. Έχω ένα μικρό makefile για το LaTeX, για να μου ετοιμάζει και ανοίγει το pdf.
 # makefile
pdf: thesis.tex
pdflatex --shell-escape --synctex=1 thesis.tex
evince thesis.pdf (ή open thesis.pdf για MacOSX)
- Πατάς m και ένα γράμμα για να αφήσεις bookmark (mark κατά το vi manual) στην γραμμή που είσαι εκείνη την στιγμή. Επιστροφή με ' ("μονό αυτάκι") και το γράμμα. Δηλαδή, ma για να μαρκάρεις με a την γραμμή, πας 23.000 γραμμές κώδικα (τσσσσ) παρακάτω, αντιγράφεις κάτι, 'a για να επιστρέψεις εκεί που ήσουν. Και φυσικά, άλλο το ma, άλλο το mb, άλλο το mc, άλλο το mA κ.ο.κ. ;)

- Η ταπεινή τελεία επαναλαμβάνει το τελευταίο edit του αρχείου. Όταν λέμε edit, εννούμε ό,τι έκανες στην τελευταία φορά που μπήκες σε insert mode. Αναίρεση φυσικά με undo (πλήκτρο u).

- Το προηγούμενο tip είναι και ο λόγος που θα πρέπει να μάθεις από νωρίς μια καλή συνήθεια: να επιστρέφεις πάντα σε command mode. Δηλαδή, πατάς i για να μπεις σε insert mode, γράφεις αυτό που θες, πάτα Esc για να βγεις από insert mode σε command mode. Μην μετακινείσαι με βελάκια 40 σειρές πιο κάτω ενώ είσαι ακόμα σε insert mode, γιατί αν χρειαστεί να κάνεις undo, θα το μετανιώσεις - θα φύγουν όλες οι αλλαγές από τότε που μπήκες στο insert mode. Ναι, είναι σπαστικό στην αρχή αυτό το πράγμα, αλλά αν πρέπει να κρατήσεις ένα tip από όλα αυτά, είναι αυτό εδώ.

- Indentation μιας γραμμής με >> (προσθέτει ένα επίπεδο indentation). Προφανώς με << φεύγει ένα indentation level. Φυσικά, όπως και στις περισσότερες εντολές του vi, μπορείς να ορίσεις ομάδα γραμμών, π.χ. 4>> για να κάνεις indent την γραμμή που είσαι και τις τρεις επόμενες. Και αν δεν σου κάνει ένα indentation level, πάτα την τελεία για επανάληψη της εντολής ;)

- Syntax highlighting με :set syntax=on.

- Search κάνεις με το /, πχ /wordtofind. Προχωράς στο επόμενο match με n. Επίσης, βοηθάει το :set hlsearch (κάνει highlight τα αποτελέσματα) και το :set incsearch (κάνει LIVE highlight τα αποτελέσματα όπως οι πιο πρόσφατοι browsers, δηλαδή την ώρα που γράφεις το search term). Λίγοι έχουν πάρει χαμπάρι ότι σαν tribute στον vi, το / χρησιμοποιείται και στον Firefox για search. Μεταξύ μας, πολύ πιο βολικό από το Ctrl/Cmd+F.

- Που είναι η άλλη άκρη της παρένθεσης; :set showmatch για να σου δείχνει αυτόματα το άλλο άκρο παρένθεσης ή bracket όταν ο κέρσορας περνάει πάνω από ένα τέτοιο.

- Σου αρέσουν αυτά τα options για showmatch, hlsearch κλπ; Βάλτα στο αρχείο .vimrc που (πρέπει να) βρίσκεται στο home dir σου. Όταν θα ξανανοίξεις τον vi, θα είναι ήδη ενεργοποιημένα.

ΥΓ: vi-vi-vi, the number of the beast :P
-----------------

Υπεραπλουστευμένο vi operation modes tutorial.

Δεν είναι τόσο άσχημα τα πράγματα, βασικά τα operation modes του vi είναι πολύ εύκολα, απλά δεν είναι όπως στους τυπικούς text editors. Θα το πάω συγκριτικά με το notepad για να έχουμε κάποια σημεία αναφοράς.

Περίληψη:

insert mode: γράφω κείμενο
command mode: δίνω εντολές με shortcuts
command line mode: δίνω εντολές γράφοντας όλο το command και τα parameters
Το βασικό mode λειτουργίας του vi είναι το command mode!

Λίιιιιγο πιο αναλυτικά:

Κατά vi, υπάρχουν τρία modes λειτουργίας: command, insert και command line modes. Στο notepad υπάρχει μόνο το insert mode. Και στους δύο editors είναι το mode στο οποίο ό,τι πληκτρολογείς εισάγεται στο κείμενο. Για το notepad, είναι το default mode λειτουργίας.

Στο notepad, αν πατήσεις ctrl+κάποιο γράμμα, θα κάνει μια δουλειά. Θα εκτελέσει μια εντολή. Αφήνεις το ctrl και συνεχίζεις να γράφεις. Στον vi, αυτό λέγεται command mode, αλλά έχει αρκετές διαφορές. Για να πας από insert mode σε command mode, πατάς το Esc ΜΙΑ ΦΟΡΑ. Δεν το κρατάς πατημένο. Πλέον, ό,τι πατήσεις είναι εντολή. Αν πατήσεις δύο φορές d, θα σου σβήσει την γραμμή που είχε τον κέρσορα. Μπορείς να δώσεις πολλές εντολές, την μία μετά την άλλη. Για να πας πάλι σε insert mode, δίνεις μια εντολή εισαγωγής κειμένου (i, a ή o).

Δεν είναι τόσο περίεργο τώρα που το σκέφτεσαι, έτσι; Ε είναι λίγο, γιατί το command mode είναι το default του vi - όταν τον ξεκινάς, ο vi αρχίζει ΠΑΝΤΑ σε command mode. Άρα με τον που ανοίγεις, πρέπει να πατήσεις π.χ. i για να αρχίσεις να γράφεις. Και πάλι όμως, δεν είναι πυρηνική φυσική, έτσι;

Στο notepad νομίζω υπάρχει ένας συνδυασμός πλήκτρων (Ctrl+F10; Alt+F10; θα σε γελάσω) ο οποίος σε πηγαίνει στο menu bar, εκεί που έχεις τα File, Edit κλπ. Εκεί πλέον μπορείς να πλοηγηθείς με τα βελάκια μέχρι να βρεις το search and replace, να βάλεις την λέξη που θες να αλλάξεις και να πατήσεις το ok. Σε γενικές γραμμές, δεν θα έλεγες ότι αυτό είναι μια υπολειτουργία του "command mode" του notepad;

Στο command mode του vi πατάς το : για να σου εμφανίσει μια σειρά στο κάτω μέρος της οθόνης όπου γράφεις μια πιο περίπλοκη εντολή μέχρι να την ολοκληρώσεις και να πατήσεις enter για να εκτελεστεί. Ένα παράδειγμα; :w filename και Enter για να σώσεις (write) το αρχείο με το όνομα filename. Αυτό λέγεται command line mode.

Ναι, οι διαφορές command και command line mode είναι μικρές και να σου πω την αλήθεια, ούτε εγώ κάθομαι να τα πολυξεχωρίσω. Είναι πιο εύκολο (και ίσως πιο "υγιές") να τα θεωρήσεις ένα και να τελειώνεις. Απλά, στο command mode, οποιοδήποτε πλήκτρο πατήσεις, εκτελείται μια εντολή (πχ το u είναι undo), ενώ στο command line mode πρώτα συνθέτεις την εντολή και μετά την "τρέχεις" πατώντας το enter.

7 σχόλια:

atmosx είπε...

Εντάξει είσαι Geek, το ξέρουμε :-P

Κι εγώ χρησιμοποιώ το VI(m) κι έχω μάλιστα κι ένα αρκετά extended .vimrc . Πολλά από αυτά που γράφεις δεν τα ήξερα και την έχω πατήσει ουκ ολίγες φορές με τα δικαιώματα, κυρίως σε OSX. Οπότε το :sh (drop-shell) θα φανεί χρήσιμο!

Αν θες κάνε ένα post το .vimrc σου :-)

sidenote: Ο emacs δεν είναι «απλά ένας ακόμη editor», είναι ένα (γαμημένο) λειτουργικό σύστημα, απλά όταν το τρέχεις ανοίγει τον editor by default!

dtsomp είπε...

Χαχαχ πήρα επιτέλους το geek badge :D

Το quote που βλέπω συνήθως (από κάτι κακοήθεις viάκηδες, σα δεν ντρέπονται) είναι το "Emacs is a great operating system but they forgot the text editor".

Το .vimrc μου είναι τελείως βασικό:

syntax on
set hlsearch
set background=black
set sw=3
set ai
set showmode
set ruler
set showmatch

Συνήθως ξεχνάω να το μεταφέρω από μηχάνημα σε μηχάνημα, οπότε πολλές φορές δεν έχω καν vimrc...

markos.charatzas είπε...

Παρόλο που χρησιμοποιώ vi χρόνια, δεν έχω κάτσει να ασχοληθώ επί της ουσίας. Ξέρω τα βασικά που αναφέρεις στο post αλλά ως εκεί.

Συνήθως η χρήση είναι να κάνω edit κάτι στα γρήγορα από console, κανά search and replace, κανα regex, over the network.

Πραγματικά θα ήθελα να δω από κοντά έναν developer να το χρησιμοποιεί.(τους ζηλεύω)

Δε νομίζω όμως ότι θα μπορούσα να το χρησιμοποιώ ως IDE π.χ.

papajohn είπε...

Το προβλημα που εγω εχω με το vi, emacs και τα συναφη, δεν ειναι στα προγραμματα αυτα καθεαυτα. Αυτα κανουν καλα την δουλεια τους και εχουν συγκεκριμενο κοινο.

Εγω αυτο που τονιζω όμως ειναι οτι η αναγκη να μη χρησιμοποιεις ποντίκι και να κανεις τα πάντα με με το πληκτρολόγιο έχει αλλη μια αιτία που ο linux κοσμος αρεσκεται στο να παραλείπει: τα GUI προγραμματα στο linux ΔΕΝ ΔΟΥΛΕΥΟΥΝ. Πχ, για τους δικους μου ανωμαλους λόγους θέλω να χρησιμοποιώ GUI editor για να γράφω latex. Ο καλύτερος τρόπος που έχω βρει ειναι το Kile. Ε, το γαμωKile πετάει 2 segmentation faults τη μέρα. Παρομοια, αν θελω να σετάρω το μηχανημα μου, το γραφικο εργαλειο δεν δουλευει ποτε. Και σε όλους linxάδες εξηγω το προβλημα, δεν αποδεχονται οτι τα γραφικα εργαλεία ειναι ΓΤΠ, αλλα αντιθετα μου λένε χρησιμοποιήσε CLI γιατι ειναι πιο γρηγορο. Οχι, θα χρησιμοποιησω CLI γιατι το απραδεκτο λειτουργικο που χρησιμοποιω δεν εχει αλλη εναλακτική.

dtsomp είπε...

@markos Δεν νομίζω ότι κάνω πολύ διαφορετική δουλειά από αυτό που περιγράφεις. Έχω να κάνω κυρίως με configuration files και shell scripts. Όσες φορές έγραψα C/C++/Java, έπαιξα με IDEs. Δεν ξέρω ΚΑΜΙΑ γλώσσα τόσο καλά ώστε να μην χρησιμοποιώ syntax correcting, documentation κλπ.

@papajohn Κάτι παρόμοιο σκεφτόμουν χτες. Υπάρχει τέτοιο UI inconsistency στον σχεδιασμό των desktop Linux εφαρμογών που καταλαβαίνεις ότι είναι εφαρμογές "από engineers για engineers". Οι Linux developers απλά δεν ενδιαφέρονται και για αυτό δεν θα γίνει ποτέ mainstream desktop OS.

Π.χ. στο OSX όλες οι εφαρμογές ακολουθούν το UI guide της Apple με αποτέλεσμα να υπάρχει μια ομοιομορφία. Σε ΟΛΕΣ τις εφαρμογές, το Cmd+, θα σου βγάλει τα Preferences. Την version της εφαρμογής και το κουμπάκι για update τα βρίσκεις μέσα στο μενού [Ονομα-Εφαρμογής]. Σε linux, αυτό είναι άπιαστο όνειρο, παρόλο που μιλάμε για άτομα που έχουν τυποποιήσει το format των CLI arguments.

xpan είπε...

Θεωρώ πως ένας κομπιουτεράς που σέβεται τον εαυτό του πρέπει να γνωρίζει vim. Όχι σε βάθος άλλα για να κάνει τα βασικά και λίγο περισσότερα. Ο λόγος είναι οτι τρέχει παντού και υπάρχει παντού. Θες να κάνεις remote login σε κάποιον σερβερ και να πειράξεις τα settings; Θες να γράψεις γρήγορο κώδικα; Αλλάζεις υπολογιστές συχνά λόγω δουλειάς (γραφείο, σπίτι, κλπ); Για όλα αυτά υπάρχει ο vim.

Όμως θεωρώ πως τα σύγχρονα IDEs (eclipse, netbeans, pycharm, π.χ.) προσφέρουν πολύ περισσότερα καλούδια για να "χτίσεις" μια εφαρμογή. Αν και λατρεύω το vim δεν μπορώ να με φανταστώ να αναπτύσσω ένα web applications όπου θα πρέπει να παντρέψω css, html, javascript, jquery, json, python, sql, κλπ. Γίνεται άλλα η διαδικασία είναι τόσο επίπονη που δε συμφέρει.

ΤΖΩΤΖΙΟΥ είπε...

Πρωτοχρησιμοποίησα vi το 1987 (το πώς και το γιατί είναι μεγάλη ιστορία). Σιχτίρισα που δεν ήξερα πώς να βγω, και κατέληξα στο Ctrl-Z και kill %1. Έκτοτε, η σχέση μας βελτιώθηκε :)

Για ένα απλό chmod, δεν βγαίνω στο shell, αλλά δίνω
:!chmod u+w %
διότι το % αντικαθίσταται από το τρέχον όνομα αρχείου.

Τα marks είναι χρησιμότατα, ειδικά όταν συνειδητοποιήσεις ότι δεν είναι μόνο σε line level, αλλά και character level (αν χρησιμοποιήσεις backquote αντί για quote). Στο δε vim, υπάρχει και το ειδικό mark . που σημειώνει την τελευταία αλλαγή στο αρχείο.

Πολύ χρήσιμα είναι και τα buffers για κόψε-ράψε (προλογίζουμε με " και μετά ένα γράμμα κατά τα marks). Τον καιρό του απλού vi δεν υπήρχε τρόπος να κάνεις copy-paste μεταξύ αρχείων παρά μόνο με buffers.

Όταν συνειδητοποιήσεις ότι η λογική είναι [εντολή][κίνηση], τότε αρχίζεις να μπαίνεις στο νόημα. Πχ όταν είσαι στην αρχή της κλήσης μιας function και πατήσεις c% , αλλάζεις όλη την κλήση, μαζί με το όνομα και τα arguments που εσωκλείονται σε παρένθεση. Ή cj για να αλλάξεις την τρέχουσα γραμμή μαζί με την επόμενη. Ή d3w για να σβήσεις τρεις λέξεις. Ή >'a για να κάνεις indent από την τρέχουσα γραμμή μέχρι την μαρκαρισμένη με το a.

Τρομερά χρήσιμο του vim είναι και το i ως motion. Πχ είσαι κάπου μέσα σε ένα string που ξεκινάει και τελειώνει με double quotes, οπότε με το ci" αλλάζεις όλο το κείμενο μεταξύ των double quotes.

Τι άλλο να πρωτοθυμηθώ τώρα… α, ναι, τι κάνει αυτό;-)

:g/^/m0