Over the line

"Ένας σύντομος οδηγός για τον vim"

~17 min read in editors Translations: en

Ένα πολύ ωραίο thread σχετικά με τον vim editor βρίσκεται εδώ, όπου το μέλος imitheos έχει παραθέσει πολλά χρήσιμα tips. Στο παρόν post θα προσπαθήσω να τα συγκεντρώσω όλα μαζί. Όπως θα διαπιστώσετε είναι ΠΑΡΑ πολλά, οπότε grab a cup of coffee, open vim and start practicing!

Οι συχνότερες λειτουργίες πλήκτρων

Υπάρχουν εκατοντάδες λειτουργίες πλήκτρων και ανάλογα με την κατάσταση που είμαστε το ίδιο πλήκτρο εκτελεί διαφορετική λειτουργία. Τα παρακάτω είναι τα πιο απλά και πιο συχνά χρησιμοποιούμενα.

h : Μετακίνηση του δρομέα αριστερά.
j : Μετακίνηση του δρομέα κάτω.
k : Μετακίνηση του δρομέα πάνω.
l : Μετακίνηση του δρομέρα δεξιά.
i : Μας βάζει στην κατάσταση εισαγωγής με τον δρομέα πριν την υπάρχουσα θέση
I : Το ίδιο με i αλλά στην αρχή της γραμμής
a : Μας βάζει στην κατάσταση εισαγωγής με τον δρομέα μετά την υπάρχουσα θέση
A : Το ίδιο με a αλλά στο τέλος της γραμμής
ο : Μας βάζει στην κατάσταση εισαγωγής αφού αλλάξει γραμμή
O : Το ίδιο με o αλλά εισάγει πριν την προηγούμενη γραμμή
p : Επικόλληση των περιεχομένων του buffer μετά από τον δρομέα.
r : Αντικαθιστά ένα χαρακτήρα.
R : Αντικαθιστά πολλούς χαρακτήρες
u : undo
Ctrl+R : αναίρεση του undo (redo)
y : Αντιγραφή στο buffer
d : Διαγραφή
x : Διαγραφή χαρακτήρα μετά τον δρομέα
X : Το ίδιο με x αλλά πριν τον δρομέα
D : Διαγραφή από τον δρομέα μέχρι το τέλος της γραμμής
G : Μετακίνηση σε κάποια γραμμή ή στο τέλος του αρχείου
J : Ενώνει την γραμμή με την επόμενη
. : Εκτελεί την προηγούμενη εντολή

Εύρος εντολών

Πολλές εντολές δέχονται εύρος. Για παράδειγμα, αν πληκτρολογήσουμε 6x θα σβήσει 6 χαρακτήρες. Η εντολή 5G θα μας πάει στην 5η γραμμή. Οι εντολές y και d δέχονται και ένα όρισμα που δηλώνει την λειτουργία της εντολής. Τα πιο συχνά χρησιμοποιούμενα είναι w (μια λέξη), $ (μέχρι το τέλος της γραμμής) και d (μία γραμμή). Στην περίπτωση του y, αντί για το d έχουμε το y (μία γραμμή). Έτσι, έχουμε:

d$ : Διαγραφή μέχρι το τέλος της γραμμής (ίδιο με D)
5dw : Διαγραφή 5 λέξεων
yy : Αντιγραφή 1 γραμμής
3dd : Διαγραφή 3 γραμμών
d3d : Διαγραφή 3 γραμμών

Τα δύο τελευταία παραδείγματα βλέπουμε ότι κάνουν το ίδιο πράγμα ενώ έχουν διαφορετική σύνταξη. Το 3dd θα εκτελέσει τρεις φορές την εντολή dd σβήνοντας δηλαδή από μία γραμμή ενώ το d3d θα σβήσει 3 γραμμές.

Εντολές με βάση το παρελθόν

Άλλες εντολές μετακίνησης που χρησιμοποιούνται συχνά και έχουν βάση στο παρελθόν είναι:

Ctrl + B : Μια σελίδα πίσω
Ctrl + F : Μια σελίδα μπροστά
^ : Μετακίνηση στην αρχή της γραμμής
$ : Μετακίνηση στο τέλος της γραμμής
w : Μετακίνηση μια λέξη μπροστά
b : Μετακίνηση μια λέξη πίσω

Και αυτές παίρνουν ορίσματα εύρους π.χ 5$

Εντολές εύρεσης

/ : Εύρεση προς τα κάτω του ορίσματος που θέλουμε
? : Εύρεση προς τα πάνω
n : Εύρεση του επόμενου αποτελέσματος του
/ ή ? N : Εύρεση του επόμενου αποτελέσματος στην αντίθετη κατεύθυνση

Αυτές οι εντολές χρησιμοποιούνται στην κατάσταση εντολών (command mode).

Οι πιο συχνά χρησιμοποιούμενες εντολές στην κατάσταση ex

Αν στην κατάσταση εντολών πληκτρολογήσουμε : τότε μπαίνουμε στην κατάσταση ex. Το vim υποστηρίζει τις εντολές του παλαιότερου κειμενογράφου ex. Οι πιο συχνά χρησιμοποιούμενες είναι οι:

:! = Εκτέλεση ενός εξωτερικού προγράμματος.
:e = Φόρτωση ενός αρχείου
:g = Εκτέλεση εντολών για επιλεγμένα patterns
:n = Όταν έχουμε να επεξεργαστούμε πολλά αρχεία μας φορτώνει το επόμενο
:N = Ομοίως για το προηγούμενο
:q = Έξοδος από το vim
:q! = Αν δεν έχουμε σώσει τις αλλαγές μας, το vim γκαρίζει με το απλό q. Με το q! δηλώνουμε ότι ναι το ξέρω ότι δεν έχω σώσει. Άσε με να βγω
:r = Μας εισάγει ένα αρχείο στο υπάρχον
:s = Εύρεση και αντικατάσταση
:v = Το ίδιο με g αλλά για τις υπόλοιπες γραμμές
:w = Εγγραφή του αρχείου
:x = Το ίδιο με :wq (Σώσιμο + Έξοδος)

Η εντολή s

Μία αρκετά χρήσιμη εντολή είναι η :s

[εύρος]s/pattern για εύρεση/pattern για αντικατάσταση/[παράμετροι]

Το εύρος δηλώνει σε ποιες γραμμές θέλουμε να ενεργήσει η s. Αν δεν δηλώσουμε τίποτα θα ενεργήσει μόνο στην τρέχουσα γραμμή. Ο χαρακτήρας . σημαίνει την τρέχουσα γραμμή και ο χαρακτήρας % όλο το αρχείο. Παραδείγματα:

5,9s : Από την 5η γραμμή μέχρι την 9η
.,+5s: Από την τρέχουσα μέχρι τις επόμενες 5 γραμμές
%s: Όλο το αρχείο

Οι πιο συχνά χρησιμοποιούμενες παράμετροι είναι οι εξής:

c: Ζητά επιβεβαίωση για κάθε αλλαγή
g: Αντικατάσταση όλων των pattern σε κάθε γραμμή και όχι μόνο του πρώτου
i: Δεν κοιτάει κεφαλαία/πεζά

O χαρακτήρας διαχωρισμού των πεδίων μπορεί να είναι οτιδήποτε και δεν είναι απαραίτητο να είναι /. Ας πούμε ότι θέλουμε να αλλάξουμε σε ένα αρχείο το /usr σε /usr/local.

1) :%s/\/usr/\/usr\/local/g
2) :%s#/usr#/usr/local#g

Το πρώτο παράδειγμα χρησιμοποιεί κανονικά το / για διαχωριστικό. Έτσι πρέπει οπουδήποτε έχουμε / μέσα στο pattern μας να το κάνουμε quote χρησιμοποιώντας την backslash, ενώ στο δεύτερο παράδειγμα επειδή χρησιμοποιούμε το # για διαχωριστικό δεν χρειάζεται να κάνουμε τίποτα.

Η εντολή global

Ας πoύμε τώρα και για το global. Το global (:g) μας επιτρέπει να εκτελέσουμε μια συγκεκριμένη εντολή σε όσες γραμμές πληρούν κάποια προϋπόθεση. πχ

1) :g/emacs/d
2) :g/usr/s/sbin/bin/g
3) :v/vim/d

Η πρώτη εντολή θα ψάξει για γραμμές που έχουν την λέξη emacs και θα εκτελέσει την εντολή d. Δηλαδή θα διαγράψει όσες γραμμές έχουν την λέξη emacs. Η δεύτερη εντολή θα ψάξει για γραμμές που έχουν τη λέξη usr και θα εκτελέσει την εντολή s η οποία θα αλλάξει το sbin με το bin. Το συγκεκριμένο παράδειγμα είναι απλό και θα μπορούσε να γίνει και μόνο με την s. Η τρίτη εντολή θα βρει όσες γραμμές έχουν την λέξη vim και διαγράψει τις υπόλοιπες. Δηλαδή είναι το αντίστροφο της g.

H εντολή που μπορούμε να εκτελέσουμε πρέπει να είναι εντολή του ex. Για παράδειγμα αν θέλουμε να σβήσουμε 10 χαρακτήρες με την εντολή 10x αυτό δεν γίνεται. Αν θέλουμε να εκτελέσουμε μια εντολή του vim μπορούμε να χρησιμοποιήσουμε το πρόθεμα normal όπως φαίνεται παρακάτω:

:g/vim/normal 10x

Η παραπάνω εντολή λέει στο vim να σβήσει τους πρώτους 10 χαρακτήρες από κάθε γραμμή που περιέχει την λέξη vim.

Εκτελώντας εντολές μέσα από τον vim

Η εντολή :! μας επιτρέπει να δούμε την έξοδο κάποιας εντολής. Δηλαδή αν γράψουμε :!ls θα μας εμφανίσει τα αρχεία που υπάρχουν στον τρέχοντα κατάλογο. Εκτός από αυτό πολλές φορές θέλουμε και να επεξεργαστούμε την έξοδο της εντολής ή απλά να την εισάγουμε στο αρχείο μας. Αυτό μπορεί να γίνει αν συνδυάσουμε τις εντολές :r και :! π.χ

:r !ls

και έχουμε το αποτέλεσμα της ls κατευθείαν μέσα στο buffer μας.

Μπορούμε επίσης να κάνουμε και το αντίθετο. Αντί να εισάγουμε την έξοδο μιας εντολής στο buffer μας, να στείλουμε το buffer ως είσοδο μιας εντολής. Αυτό γίνεται με το πρόθεμα %

Hello World
:%!rev
dlroW olleH

Στο παραπάνω παράδειγμα, έχουμε "Hello World" και λέμε πάρτο και δωσ' το ως είσοδο στην εντολή rev η οποία αναποδογυρίζει την είσοδο της οπότε το buffer μας γίνεται dlroW olleH.

Ενεργοποίηση διάφορων επιλογών

Υπάρχουν πολλές επιλογές που μπορούν να δηλωθούν στο .vimrc ή κατά την διάρκεια του vim.

background (bg)

Όταν χρησιμοποιούμε το vim και όχι το gvim, μερικές φορές δεν λειτουργεί σωστά η αυτόματη ανίχνευση του φόντου του τερματικού με συνέπεια να μην φαίνονται καλά τα χρώματα. Για αυτό το λόγο μπορούμε να δηλώσουμε

set background=dark
ή
set background=light

hlsearch (hls)

Όταν ψάξουμε κάτι, το vim το τονίζει ώστε να φαίνεται εύκολα. Αν τελειώσουμε αυτό που θέλαμε να κάνουμε και δεν θέλουμε να βλέπουμε τονισμένο κείμενο στα υπόλοιπα αποτελέσματα απενεργοποιούμε αυτή την επιλογή με

:set nohls

Αν ψάξουμε κάτι νέο, τότε θα ενεργοποιηθεί αυτόματα πάλι.

list

Εμφανίζει $ στο τέλος κάθε γραμμής και ^I για κάθε tab, έτσι μπορεί να μας διευκολύνει να διακρίνουμε τα tab όταν έχουμε κώδικα.

listchars (lcs)

Η κανονική λειτουργία του list δεν είναι και πολύ χρήσιμη. Με την listchars μπορούμε να αλλάξουμε την λειτουργία της. Οι επιλογές που δέχεται είναι οι εξής:

eol:x Θα εμφανίζει τον χαρακτήρα x στο τέλος κάθε γραμμής
tab:xy Για κάθε tab θα εμφανίζει στην αρχή τον χαρακτήρα x και έπειτα τον χαρακτήρα y μέχρι να τελειώσει το tab
trail:x Θα εμφανίζει τον χαρακτήρα x για όσες spaces υπάρχουν στο τέλος της γραμμής
extends:x Όταν η γραμμή είναι μεγαλύτερη από ό,τι χωράει στην οθόνη θα εμφανίζει τον χαρακτήρα x για να μας δείξει ότι η γραμμή φεύγει εκτός οθόνης

Ένα παράδειγμα είναι το παρακάτω

set listchars=eol:$,tab:>-,trail:.
highlight SpecialKey ctermfg=red


1) printf("foo\n");
2)>------printf("foo\n");...$

Το αποτέλεσμα φαίνεται στην μορφή 2) όπου βλέπουμε ότι χρησιμοποιούνται 8άρια tabs και ότι στο τέλος ξέφυγαν 3 spaces που πρέπει να σβήσουμε από τον κώδικα.

textwidth (tw)

Αν δηλωθεί ορίζει το μέγεθος κάθε γραμμής. Αν επιχειρήσουμε να περάσουμε το όριο αυτό θα γίνει αυτόματα wrap στην επόμενη γραμμή. Κανονικά είναι απενεργοποιημένη γιατί έχει νόημα σε κώδικα και όχι οπουδήποτε. Για να την ενεργοποιήσουμε σε συγκεκριμένο τύπο αρχείων μπορούμε να χρησιμοποιήσουμε τις autocommands του vim. π.χ

autocmd FileType c setlocal textwidth=78

Η παραπάνω εντολή λέει ότι αν το αρχείο που έχουμε φορτώσει είναι αρχείο C, τότε θέσε μέγιστο όριο γραμμής τους 78 χαρακτήρες. Η setlocal θέτει την παράμετρο μόνο για το τοπικό buffer. Αν είχαμε ανοίξει πολλά αρχεία και χρησιμοποιούσαμε την set τότε θα έθεται την tw και για εκείνα το οποίο δεν θέλουμε.

c_space_errors

Αυτή δεν είναι παράμετρος του vim αλλά του syntax highlighter της C. Αν δηλωθεί, τότε θα εμφανίζει τα spaces που βρίσκονται στο τέλος με κόκκινο. Πρέπει να δηλωθεί πριν φορτωθεί ο syntax highlighter π.χ

let c_space_errors = 1 syntax on

] και λειτουργεί ανεξάρτητα της list και μόνο σε C αρχεία. Η list είναι πιο εύχρηστη.

Registers

The quick brown fox jumps over the lazy dog
Τρεία πουλάκια κάθονταν.

Ας υποθέσουμε ότι έχουμε το παραπάνω κείμενο. Θέλουμε να αντιγράψουμε 50 γραμμές πιο κάτω το κείμενο με την αλεπού, οπότε πηγαίνουμε τον δρομέα πάνω του και πληκτρολογούμε yy για να αντιγραφεί η γραμμή. Τώρα μένει να πάμε το δρομέα εκεί που θέλουμε και να πατήσουμε p για να γίνει η επικόλληση. Βλέπουμε όμως ότι το τρία το έχουμε γράψει λάθος οπότε πληκτρολογούμε x και σβήνουμε το έψιλον. Αφού έχουμε μετακινηθεί 50 πιο κάτω πληκτρολογούμε p και βλέπουμε έκπληκτοι και νευριασμένοι ότι γίνεται επικόλληση το έψιλον που σβήσαμε.

Κάθε εντολή που πραγματοποιεί αλλαγές τις εισάγει σε κάποιο register (κάτι σαν buffer). Οπότε με την εκτέλεση της x το αποτέλεσμα της yy έπαψε να υπάρχει.

Εκτός από τον default register το vi μας επιτρέπει να χρησιμοποιήσουμε 26 ακόμη registers με ονόματα a-z. Για να προσπελάσουμε τον κάθε register χρησιμοποιούμε το ".

Οπότε στην παραπάνω περίπτωση μπορούμε αντί για yy να δώσουμε "ayy οπότε το αποτέλεσμα θα μπει στον a register και δεν θα χαθεί όταν σβήσουμε το έψιλον. Έπειτα για να γίνει η επικόλληση δίνουμε "ap.

Marks

Στο προηγούμενο μήνυμα είπαμε ότι αν εκτελέσουμε πχ 5dd θα σβήσουμε 5 γραμμές. Μπορεί όμως να μην ξέρουμε πόσες ακριβώς είναι οι γραμμές και εννοείται πως δεν θα κάτσουμε να μετράμε. Εδώ έρχονται τα marks τα οποία μας επιτρέπουν να μαρκάρουμε μια περιοχή και να εκτελούμε εντολές πάνω της. Τα marks είναι πάλι 26 με ονόματα a-z αλλά αυτή τη φορά χρησιμοποιούμε το ' (μονό εισαγωγικό).

Ας υποθέσουμε ότι αυτό που μόλις έγραψα ήταν κείμενο στο vi. Ο δρομέας είναι στο Στο και πληκτρολογούμε ma. Αυτό λέει ότι μαρκάρισε την γραμμή ως a. Έπειτα πηγαίνουμε το δρομέα στη γραμμή Τα marks. Αν πληκτρολογήσουμε y'a θα αντιγράψει τις 6 αυτές γραμμές, ενώ με d'a μπορούμε να τις σβήσουμε.

Τα marks είναι χρήσιμα αλλά η Visual κατάσταση δίνει μεγαλύτερη εποπτεία οπότε δεν πολύ χρησιμοποιούνται.

Backreferences και Patterns

Αυτό δεν είναι καθαρά vim αλλά και το sed και πολλά εργαλεία έχουν την ίδια σύνταξη. Είναι τεράστιο κεφάλαιο αλλά επειδή αναφέραμε την εντολή s πρέπει να αναφέρουμε και τα backreferences.

Οι πιο βασικοί μεταχαρακτήρες που ισχύουν σε patterns είναι οι ακόλουθοι.

. = Οποιοσδήποτε χαρακτήρας
* = Ο προηγούμενος χαρακτήρας μπορεί να υπάρχει όσες φορές θέλει
^ = αρχή της γραμμής
$ = τέλος της γραμμής

Παραδείγματα:

H.llo = Hallo, Hbllo, Hello κτλ
^Hello = Η γραμμή αρχίζει με Hello.
World$ = Η γραμμή τελειώνει με World
H.*o = Οποιαδήποτε λέξη αρχίζει με H και περιέχει o
      (Το . λέει οποιοσδήποτε χαρακτήρας και το * όσες φορές
      θέλει ο προηγούμενος οπότε πιάνει τα πάντα)

Τα backreferences χρησιμοποιούνται όταν θέλουμε να κρατήσουμε ένα μέρος του pattern. Δηλώνονται με τα \( και \)

Ο Κώστας είναι ψηλός και ο Γιώργος είναι ψηλός

Θέλουμε να αλλάξουμε την παραπάνω πρόταση ώστε να λέει ο Γιώργος είναι πολύ ψηλός. Η κλασική εντολή θα ήταν

s/ψηλός/πολύ ψηλός/

Σε αυτή την περίπτωση όμως θα αλλάξει τον Κώστα ή με g και τον Κώστα. Άρα τι εντολή να βάλουμε; Εδώ θα χρησιμοποιήσουμε τα backreferences δηλαδή τις αναφορές.

s/\(Γιώργος.*\) ψηλός/\1 πολύ ψηλός/

Το Γιώργος.* ψηλός σημαίνει ψάξε για μια φράση που αρχίζει με την λέξη Γιώργος, μετά ακολουθεί οτιδήποτε και τελειώνει στη λέξη ψηλός. Οι quoted παρενθέσεις λένε ότι το κομμάτι αυτό το χρειάζομαι οπότε έχε το υπ' όψιν σου και θα στο ζητήσω κάποια στιγμή. Αυτό όλο θα το αντικαταστήσεις με την φράση \1 πολύ ψηλός, όπου \1 σημαίνει η πρώτη αναφορά που σου ζήτησα. Δηλαδή η φράση Γιώργος είναι ψηλός αντικαθίσταται με την φράση Γιώργος είναι πολύ ψηλός

Απόκρυψη (δίπλωση) πληροφοριών με την foldmethod

Το vim μάς επιτρέπει να αποκρύπτουμε (διπλώνουμε) πληροφορίες για ευκολότερη ανάγνωση. Αυτό χρησιμεύει σε μεγάλα κείμενα με πολλαπλές ενότητες. Η παράμετρος που δηλώνει την μέθοδο που θα χρησιμοποιηθεί για το δίπλωμα είναι η foldmethod. Κανονικά όταν τρέχουμε το vim είναι επιλεγμένη η manual για αυτό και δεν γίνεται κανένα δίπλωμα. Ακόμη, υπάρχουν οι indent,syntax,expr,marker.

Η expr δέχεται ως όρισμα μια εντολή της αρεσκείας μας με βάση την οποία ορίζει το δίπλωμα. Είναι πολύ δυνατή αλλά δεν χρησιμοποιείται πολύ συχνά.

Η indent και η syntax έχουν παρόμοια λειτουργία στις περισσότερες περιπτώσεις. Ας δούμε για παράδειγμα τον παρακάτω κώδικα:

#include <stdio.h>
#include <stdlib.h>

int fact(int n);

int main(void)
{
        int i;
        int k;

        for (i = 1; i < 8; i++) {
                k=fact(i);
                printf("Factorial of %d = %d\n",i,k);
        }
        return 0;
}

int fact(int n)
{
        int res = 0;
        if (n >= 0) {
                if (n <= 1)
                        res = 1;
                else
                        res = fact(n-1) * n;
        }
        return res;
}

Αν εκτελέσουμε :set foldmethod=indent αυτή θα διπλώσει τον κώδικα μας με βάση την κάθε βαθμίδα indentation και θα προκύψει το εξής:

#include <stdio.h>
#include <stdlib.h>

int fact(int n);

int main(void)
{
+--  8 lines: int i;-------------------
}

int fact(int n)
{
+--  8 lines: int res = 0;----------

}

Όπως ήταν αναμενόμενο μας έκλεισε όλες τις δηλώσεις με βάση το indentation. Η μέθοδος αυτή λειτουργεί για οποιοδήποτε κείμενο χρησιμοποιεί indentation.

Αντίθετα η syntax χρειάζεται να έχει δηλωθεί η σύνταξη του κάθε τύπου αρχείου για να λειτουργήσει, το vim όμως έχει ενσωματωμένες συντάξεις για πάρα πολλούς τύπους αρχείων. Ας δούμε τώρα πόσο διαφορετική θα είναι αυτή η μέθοδος.

#include <stdio.h>
#include <stdlib.h>

int fact(int n);

int main(void)
+-- 10 lines: {-----------------------

int fact(int n)
+-- 10 lines: {-----------------------

Εδώ βλέπουμε ότι αναγνωρίζεται η σύνταξη της C. Έτσι γνωρίζει ότι έχουμε δηλώσει κάποιες συναρτήσεις και γι' αυτό μας κρύβει όλη την συνάρτηση, οπότε οπτικά είναι καλύτερο για μεγάλους κώδικες.

Κακά τα ψέμματα, τα αποτελέσματα και με τις δύο μεθόδους ήταν άθλια. Δεν μπορείς να δεις τίποτα. Σε αυτό παίζει ρόλο η επιλογή foldlevel η οποία ορίζει από ποια βαθμίδα και έπειτα θα γίνεται το δίπλωμα. Κανονικά έχει την τιμή 0 οπότε διπλώνονται όλες οι δηλώσεις. Οι περισσότεροι χρήστες βρίσκουν για κώδικα την τιμή 1 ως βέλτιστη, η οποία διπλώνει δηλώσεις από την 2η βαθμίδα και έπειτα. Ας δούμε τι αποτέλεσμα θα έχει αυτό στις δύο προηγούμενες περιπτώσεις.

indent

#include <stdio.h>
#include <stdlib.h>

int fact(int n);

int main(void)
{
        int i;
        int k;

        for (i = 1; i < 8; i++) {
+---  2 lines: k=fact(i);---------
        }
        return 0;
}

int fact(int n)
{
        int res = 0;
        if (n >= 0) {
+---  4 lines: if (n <= 1)-----------
        }
        return res;
}

Τώρα το αποτέλεσμα είναι πολύ καλύτερο. Έχουμε μια ιδέα τι κάνει η κάθε συνάρτηση και αποκρύπτονται πχ οι λεπτομέρειες του for. syntax

#include <stdio.h>
#include <stdlib.h>

int fact(int n);

int main(void)
{
        int i;
        int k;

+---  4 lines: for (i = 1; i < 8; i++) {------
        return 0;
}

int fact(int n)
{
        int res = 0;
+---  6 lines: if (n >= 0) {-------------------
        return res;
}

Όπως και πριν το αποτέλεσμα της syntax είναι καλύτερο οπτικά γιατί γνωρίζει τις ιδιαιτερότητες της C.

Συνδυασμοί πλήκτρων Όλες οι εντολές αναδίπλωσης ξεκινούν με z.

zo = Άνοιγμα του fold στη θέση του δρομέα
zO = Άνοιγμα του fold καθώς και αυτών που βρίσκονται μέσα σε αυτό
zc = Κλείσιμο του fold στη θέση του δρομέα
zC = Κλείσιμο του fold καθώς και αυτών που βρίσκονται μέσα σε αυτό
za = Εναλλαγή της κατάστασης του fold (Άνοιγμα/Κλείσιμο)
zA = Εναλλαγή της κατάστασης και αυτών που βρίσκονται μέσα
zj = Μετακίνηση του δρομέα στο επόμενο fold
zk = Μετακίνηση του δρομέα στο προηγούμενο fold
zi = Εναλλαγή της κατάστασης foldenable με συνέπεια το άνοιγμα ή κλείσιμο όλων των folds
zM = Θέτει στην foldlevel την τιμή 0 κλείνοντας ουσιαστικά όλα τα folds
zR = Θέτει στην foldlevel την μέγιστη τιμή ανοίγοντας ουσιαστικά όλα τα folds
zm = Μειώνει την foldlevel κατά 1 κλείνοντας μια βαθμίδα από folds
zr = Αυξάνει την foldlevel κατά 1 ανοίγοντας μια βαθμίδα από folds

Ας δούμε τώρα και την τρίτη μέθοδο που είναι η marker. Εδώ επιλέγουμε πως θέλουμε να γίνει δίπλωμα μόνο όπου υπάρχουν οι markers {{{ και }}}. Αυτή η μέθοδος έχει το καλό ότι επιλέγουμε εμείς να κάνουμε folding μόνο εκεί που θέλουμε να γίνει. Δεν χρησιμοποιείται πάρα πολύ σε κώδικα αλλά συνήθως σε αρχεία που δεν έχουν κάποια σύνταξη ή indentation.

# {{{ Γεια σου κόσμε
echo Hello World
# }}}

/* {{{ Γεια σου κόσμε */
printf("Hello World\n");
/* }}} */

Τα παραπάνω είναι δύο παραδείγματα για shell και C. Το κείμενο που βάζουμε μετά τον {{{ marker θα εμφανίζεται ως περιγραφή όταν το fold είναι κλειστό.

Υπάρχουν αρκετοί στους οποίους οι μέθοδοι indent και syntax δεν αρέσουν γιατί δυσκολεύουν αντί να ευκολύνουν στη συγγραφή κώδικα. Υπάρχουν όμως περιπτώσεις που βολεύει η χρήση των markers όπως π.χ. στα αρχεία εκκίνησης του zsh. Για παράδειγμα ένα αρχείο zshrc μπορεί να φαίνεται ως εξής:

+-- 36 lines: Δήλωση του prompt ---------------------

+-- 57 lines: Λειτουργίες πλήκτρων -------------------

+-- 64 lines: Δήλωση μεταβλητών --------------------

+-- 41 lines: Δήλωση συντομεύσεων (aliases) ----
κτλ

Έτσι, όταν θέλoυμε να αλλάξουμε ή να προσθέσουμε κάτι δεν χρειάζεται να ψάχνουμε μέσα σε 700 γραμμές. Απλά πηγαίνουμε στην κατηγορία που θέλουμε και ανοίγουμε το fold.

Καλά και χρυσά τα folds, αλλά δεν μπορούμε κάθε φορά που ανοίγουμε ένα αρχείο να γράφουμε :set foldmethod=τάδε. Για αυτό το λόγο, το vim υποστηρίζει τα λεγόμενα modelines που είναι γραμμές οι οποίες λένε στο vim ποιες παραμέτρους να ενεργοποιήσει για το συγκεκριμένο αρχείο.

[κείμενο]<κενό>vim:παράμετροι
[κείμενο]<κενό>vim:set παράμετροι: [κείμενο]

Αυτές είναι οι δύο μορφές που μπορούμε να χρησιμοποιήσουμε για να δηλώσουμε την modeline. Το vim ψάχνει ένα αριθμό γραμμών στην αρχή και στο τέλος του αρχείου για πιθανά modelines, έτσι μπορούμε να την δηλώσουμε είτε στην αρχή είτε στο τέλος του αρχείου μας.

Πιθανά παραδείγματα

# vim:filetype=zsh:foldmethod=marker

Όπως αναφέρθηκε πιο πάνω μπορεί να χρησιμοποιηθεί στα αρχεία του zsh. Ο τύπος του αρχείου θα αναγνωριζόταν αυτόματα αλλά καλό είναι να τον δηλώνουμε. Όπως βλέπουμε στην σύνταξη, η πρώτη μορφή δεν επιτρέπει κείμενο στο τέλος, οπότε σε συγκεκριμένες περιπτώσεις πρέπει να χρησιμοποιηθεί η δεύτερη μορφή.

/* vim:filetype=c:foldmethod=syntax *ΛΑΘΟΣ*
/* vim:set filetype=c:foldmethod=syntax */ *ΣΩΣΤΟ*

Οι modelines χρησιμοποιούνται για να δηλώσουμε οτιδήποτε παραμέτρους θέλουμε να ισχύουν για το συγκεκριμένο αρχείο μας και όχι μόνο για το folding. Έτσι, για λόγους ασφαλείας, δεν διαβάζονται όταν ο χρήστης είναι ο root. Αν ανοίξουμε ένα αρχείο ως root, θα πρέπει να εκτελέσουμε :set foldmethod=τάδε ακόμη και αν υπάρχει modeline.

Η εντολή colorcolumn

Για προγραμματισμό, παρόμοια και εξίσου χρήσιμη είναι και η colorcolumn. Πολλά IDE έχουν μια (πράσινη συνήθως) κατακόρυφη γραμμή που δηλώνει τα όρια του κώδικα για παράδειγμα 80 στήλες. Η colorcolumn κάνει ακριβώς το ίδιο. Το μόνο κακό είναι ότι λόγω της φύσης του vim έχει πλάτος ένα χαρακτήρα οπότε είναι λίγο χοντροκομμένη και μπορεί να κουράζει κάποιους. Μπορεί εύκολα να χρησιμοποιηθεί μόνο σε αρχεία προγραμματισμού.

autocmd FileType c setlocal textwidth=78
autocmd FileType c setlocal colorcolumn=+1

Πχ. σε αρχεία γλώσσας C να χρησιμοποιούνται το πολύ 78 στήλες (από τη μάνα του το vim δεν πειράζει τον κώδικα αλλά τα σχόλια αναδιπλώνονται αυτόματα αν περάσουν τις 78 στήλες) και να χρωματιστεί η στήλη textwidth+1 δηλαδή η 79.

Τοποθεσία κέρσορα

:hi CursorLine   cterm=NONE ctermbg=lightgrey
:hi CursorColumn cterm=NONE ctermbg=lightgrey
:nnoremap <Leader>c :set cursorline! cursorcolumn!<CR>

Με τον συγκεκριμένο κώδικα γίνονται 3 πράγματα: 1) το highlight είναι γκρι 2) ΔΕΝ είναι υπογραμμισμένο 3) ΔΕΝ είναι ενεργοποιημένο, αλλά μπορεί πολύ εύκολα να ενεργοποιηθεί/απενεργοποιηθεί πατώντας \c.

Ελληνικός ορθογράφος

Αν η διανομή μας έχει πακέτο με το Ελληνικό αρχείο ορθογραφίας του vim, τότε απλά το εγκαθιστούμε, Αν όχι, τότε πρέπει να το δημιουργήσουμε με βάση μία λίστα λέξεων. Πολλές διανομές εγκαθιστούν λίστες λέξεων για Ελληνικά για aspell, myspell, αλλά ας υποθέσουμε ότι δεν έχουμε τέτοιο πακέτο οπότε ας το κατεβάσουμε.

mkdir foo; cd foo
wget https://extensions.services.openoffice.org/e-files/1411/2/el_gr_v110.oxt
unzip el_gr_v100.oxt

Τα αρχεία που μας ενδιαφέρουν είναι το el_GR.dic που είναι η λίστα με τις λέξεις και το el_GR.aff που έχει διάφορα χαρακτηριστικά των Ελληνικών. Έπειτα τρέχουμε το vim για να δημιουργήσουμε το αρχείο και τρέχουμε

:mkspell el el_GR

Η εντολή θα δημιουργήσει ένα αρχείο el.utf-8.spl ή el.iso8859-7.spl ανάλογα με το encoding που έχoυμε με βάση τα αρχεία .aff και .dic που έχουν πρόθεμα el_GR. Έπειτα απλά πρέπει να το βάλουμε στο σωστό μέρος.

mkdir -p ~/.vim/spell
mv el.utf-8.spl ~/.vim/spell

Από εδώ και πέρα έχουμε Ελληνικό ορθογράφο ο οποίος ενεργοποιείται με

:set spell spelllang=el

Τέλος μπορούμε να έχουμε ταυτόχρονα 2 λεξικά ενεργοποιημένα (πχ ελληνικό - αγγλικό)

:set spell spelllang=el,en

Για το λόγο αυτό παράξαμε παραπάνω την «precompiled» μορφή ώστε το vim να αναγνωρίζει γρήγορα μια λέξη και να μπορούμε να έχουμε φορτωμένα πολλά λεξικά. Ουσιαστικά η mkspell κάνει το αρχείο binary για να γίνεται πιο γρήγορα το matching.

Παράδειγμα .vimrc

Τα διπλά αυτάκια " δηλώνουν σχόλια.

"Με την autoread αν το αρχείο έχει αλλάξει από το άνοιγμα του αλλά δεν
"έχει γίνει κάποια αλλαγή από εμάς, τότε διαβάζει ξανά αυτόματα το αρχείο.
"Το lazyredraw δεν σχεδιάζει ξανά την οθόνη κατά την εκτέλεση των macros.

set autoread
set lazyredraw
set nomodeline
set nobackup        "δεν κάνει αυτόματα backups
set viminfo="NONE"  "απενεργοποιεί το .viminfo

"Απενεργοποίηση του mouse
 if has('mouse')
     set mouse=a
 endif

"Σκοτεινό φόντο και εμφάνιση των tabs και των τελικών spaces σε κώδικα.
set background=dark
set listchars=eol:$,tab:>-,trail:.
highlight SpecialKey ctermfg=red
let c_space_errors = 1

"Διάφορες custom λέξεις και patterns που θέλω να είναι τονισμένες.
syntax match TadeName "Pattern"
highlight match TadeName ctermfg=tadexroma

"Όταν διαβάζω αρχεία που βρίσκονται μέσα στο /var/log δηλαδή logs να πηγαίνει
"αυτόματα στο τέλος του αρχείου. Μέσα στον /var/log όμως το Slackware έχει
"και άλλους καταλόγους όπως π.χ τον κατάλογο με τις πληροφορίες των πακέτων.
"Εκεί δεν θέλω να με πηγαίνει στο τέλος. Παλαιότερα είχα regexp αλλά από μια
"έκδοση και μετά δεν έπαιζε οπότε μετράω τις / που υπάρχουν στο όνομα.
"Αν χαλάσει το match, να το κάνω stridx(s:name,'/',9)
autocmd BufReadPost /var/log/*
\ let s:name = expand("<afile>:p") |
\ if match(s:name,'/',0,4) == -1 |
\   exe "normal G" |
\ endif |
\ unlet! s:name

"Μερικές φορές θέλω να κάνω επικόλληση κάτι χωρίς όμως να χαλάσει η δομή του.
"Το vim παρέχει την επιλογή paste για αυτό. Έτσι με το F10 αλλάζω την επιλογή.
"Επίσης το F2 ενεργοποιεί/απενεργοποιεί την list ώστε να βλέπω σε κώδικα αν
"έχω ξεχάσει κενά ή tabs και το F8 απενεργοποιεί την hlsearch όταν έχω βρει
"αυτό που θέλω και δεν θέλω να βλέπω πλέον τα highlights.
"Key Mappings
set pastetoggle=<F10>
nmap <silent> <F2> :set list!<cr>
imap <silent> <F2> <esc>:set list!<cr>a
nmap <silent> <F8> :set hls!<cr>

"Τα leader και localleader είναι κάποια εικονικά πλήκτρα για την εύκολη χρήση
"συνδυασμών. Κανονικά είναι ρυθμισμένα να χρησιμοποιούν το backslash αλλά
"μπορούμε να αλλάξουμε την τιμή τους. Οι καρτέλες δεν έχουν και πολύ νόημα
"σε X τερματικά μια και υποστηρίζουν και αυτά καρτέλες αλλά είναι χρήσιμες στην
"κονσόλα.

"Αλλαγή των πλήκτρων leader από το default \
"let mapleader = ','
"let maplocalleader = ','

"Αποθήκευση αρχείου
nmap <leader>w :w<cr>

"Μεταφορά στο προηγούμενο/επόμενο buffer
nmap <leader>n :bn<cr>
nmap <leader>p :bp<cr>

"Άνοιγμα νέας καρτέλας
nmap <leader>to :tabnew<cr>
"Κλείσιμο τρέχουσας καρτέλας
nmap <leader>tc :tabclose<cr>
"Μεταφορά στην προηγούμενη/επόμενη καρτέλα
nmap <leader>tn :tabnext<cr>
nmap <leader>tp :tabprev<cr>

"Κατάργηση των βελακίων ώστε να γίνουν συνήθεια τα hjkl.
"Τα απενεργοποιούμε μόνο στην normal κατάσταση
"γιατί στην insert και στην command δεν υπάρχουν εναλλακτικές (εκτός από macros).

if &encoding == "utf-8"
  nnoremap <Left>     :echoerr "Το h αγκάθια έχει?"<cr>
  nnoremap <Down>     :echoerr "Το j αγκάθια έχει?"<cr>
  nnoremap <Up>       :echoerr "Το k αγκάθια έχει?"<cr>
  nnoremap <Right>    :echoerr "Το l αγκάθια έχει?"<cr>
  nnoremap <PageUp>   :echoerr "Το Ctrl-B αγκάθια έχει?"<cr>
  nnoremap <PageDown> :echoerr "Το Ctrl-F αγκάθια έχει?"<cr>
endif

"Για συγγραφή latex
"assign keyboard commands while using the greek keyboard:
map Α A
map Β B
map Ψ C
map Δ D
map Ε E
map Φ F
map Γ G
map Η H
map Ι I
map Ξ J
map Κ K
map Λ L
map Μ M
map Ν N
map Ο O
map Π P
map Q Q
map Ρ R
map Σ S
map Τ T
map Θ U
map Ω V
map W W
map Χ X
map Υ Y
map Ζ Z
map α a
map β b
map ψ c
map δ d
map ε e
map φ f
map γ g
map η h
map ι i
map ξ j
map κ k
map λ l
map μ m
map ν n
map ο o
map π p
map q q
map ρ r
map σ s
map τ t
map θ u
map ω v
map ς w
map χ x
map υ y
map ζ z

Credits

Τα credits στους imitheos, arkara, tsigarid. Όποιος κατάφερε και διάβασε μέχρι εδώ είναι ήρωας...