Introduzione all'uso di Emacs

Emacs è a torto ritenuto un programma troppo difficile. O troppo grosso. Effettivamente l'eseguibile è di dimensioni molto generose mentre il numero di comandi può confondere e spaventare. C'è però da dire che Emacs è anche dotato di una collezione di tool e di manuali on line tale da renderlo uno strumento di lavoro potente e versatile e, guardando bene, non così difficile da usare.

Questo è un piccolo testo introduttivo, che passa a volo di rondine su alcune caratteristiche di emacs legate allo sviluppo. Di programmi sì, ma anche di documenti sia di testo che in HTML o SGML.

Emacs per lo sviluppatore

Emacs è un editor particolarmente versatile. Piuttosto che contenere caratteristiche dedicate ad un certo scopo, la sua struttura è basata su un motore lisp, che permette di volta in volta di caricare e attivare tutta una serie di tool dedicati ad uno scopo specifico, e questo senza tuttavia compromettere la generalità del programma, che può nello stesso istante gestire testi scritti in linguaggi umani o di programmazione ed anche applicazioni delle più disparate, giochi inclusi.

In questo luogo osserveremo con più attenzione quelle caratteristiche che sono utili in particolare al programmatore, cominciando dalle più comuni e prevedibili, e passando via via alle altre. Non si farà di certo un corso completo, ma si indicherà cosa è possibile fare. L'help ipertestuale di Emacs (od una sua versione cartacea) saranno sicuramente in grado di descrivere con dovizia di particolari come accedere ad una certa funzionalità.

Estetica

Una delle cose che oramai ci si attende comunemente da un editor di programmazione è che sia in grado di decorare ed indentare il testo in conformità alla sintassi del linguaggio di programmazione in uso.

Mi riferisco all'indentazione automatica del testo ed alla colorazione dipendente dalla sintassi.

Queste decorazioni, anche se non indispensabili, rendono più facile il lavoro guidando l'occhio nel testo, tenendo ordinato il codice ed individuando a volte errori di battitura. Se infatti si scrive in maniera sbagliata un certo token è possibile che questo non venga colorato in maniera corretta, dando subito l'allarme al programmatore.

La cosa interessante è che non c'è un limite teorico alla tipologia di linguaggi per i quali Emacs è in grado di gestire correttamente questo procedimento. Infatti, a differenza degli editor di Microsoft, Borland ed anche Watcom, Emacs affida questa gestione a programmi in lisp ad hoc che attivano modi di editing dedicati ai vari linguaggi.

Si ha così un pascal-mode, un elisp-mode, un fortran-mode, uno shell-mode, un makefil-mode dedicato ai makefile. Ovviamente c'è anche un modo per l'HTML. E il C ? Per il C ed il C++ ora esiste un pacchetto molto furbo chiamato cc-mode che è adatto sia all'uno sia all'altro linguaggio, e se ciò non fosse ancora sufficente, cc-mode è in grado di gestire objective C e Java.

Emacs può essere istruito ad attivare automaticamente un certo modo in corrispondenza di certi suffissi, ma obbedisce tranquillamente alle direttive dell'operatore, senza pretendere di essere più furbo. Quindi se sbaglia a riconoscere un tipo di file, non c'è problema, è sempre possibile dirgli rapidamente "Zuccone, si fa così!".

Riguardo all'indentazione, Emacs è in grado di riformattare rapidamente ed automaticamente vaste aree di testo, ed al programmatore sono fornite tutte le informazioni necessarie per poter adattare ai suoi gusti il motore di indentazione. Usualmente, il carattere linefeed è associato all'indentazione automatica mentre il carattere newline è associato al tasto return e non produce questo effetto.

Editing

Emacs ha tutte le funzioni che vi aspettate da un buon editor. Movimento con i tasti funzione, gestione del mouse (dalla release 19), copia-incolla (anche con registri multipli), trasposizione di caratteri o parole.

Non so quanti altri editor siano in grado di effettuare spostamenti nel testo o selezioni basandosi su concetti come "lista", "sexp" (legati al prefisso Control Meta) o "corpo di una funzione", che Emacs può marcare con un solo comando (Control Meta h, o C-M-h).

Cosa sono una "lista" o una "sexp" per Emacs? Emacs parte dalle liste del LISP e generalizza. Una lista è un gruppo di parantesi bilanciate. Guardacaso un concetto comune a tutti i linguaggi che conosco. Sexp deriva da "s-expression", un termine antico del LISP che Emacs di nuovo generalizza ad ogni linguaggio. Una "sexp" diventa quindi una espressione scritta nella grammatica di un certo linguaggio.

Un paio di avvertenze. La prima riguarda le sexp che abbiamo appena visto. Linguaggi con notazione mista infissa/prefissa come il C rendono difficile la gestione perfetta di queste espressioni. Ad esempio, "foo + bar" viene considerata come 2 espressioni ("foo" e "bar") separate da un segno di interpunzione ("+"). Viceversa l'espressione "(foo + bar)" viene considerata come una espressione unica.

La seconda riguarda la selezione del corpo di intere funzioni. L'algoritmo attuale usa una regola euristica per ridurre i tempi di selezione del corpo di una funzione. Questa regola dice semplicemente che la parentesi più a sinistra apre una definizione di funzione. Questo richiede al programmatore qualche attenzione. Come non mettere una parentesi grafa aperta -o altro delimitatore di apertura- sul margine sinistro a meno che non apra il corpo di una funzione. Nel caso in cui questo delimitatore appare all'inizio della riga in una stringa, basta farlo precedere da un carattere di escape. Il compilatore è contento, emacs è contento.

Tutto quanto esposto finora è descritto dettagliatamente alla voce "Editing programs" del manuale di Emacs (sia in linea che cartaceo).

Meno tasti si premono...

Un'altro modo in cui Emacs può sveltire la scrittura del codice è la sua capacità di espandere abbreviazioni. Emacs di per se non ha abbreviazioni definite, ciascuno è libero di definirsi quelle che preferisce come preferisce. Ad esempio è possibili istruire Emacs in modo che scrivendo "if" lui introduca autonomamente un pezzetto di codice del tipo

if() {
} else {

}e poi salvare questra abbreviazione. Si può anche fare in modo che il comportamento sia questo nei modi relativi ai vari dialetti del C, mentre in pascal la stessa abbreviazione sia espansa con

if  then begin
end else begin
end;

mentre nei modi relativi alla scrittura di testi in linguaggi umani non ci sia alcuna espansione. La definizione può essere fatta mentre si scrive il testo nel quale si vogliono fare le abbreviazioni, oppure pianificando le abbreviazioni ed usando l'apposito comando edit-abbrevs. Le abbreviazioni così definite possono essere salvate in un file, e si possono avere più collezioni di abbreviazioni anche in relazione ad uno stesso modo. Il come usare questo strumento è lasciato alla fantasia di ciascuno.

E' inoltre possibile l'uso delle abbreviazioni dinamiche, che operano in maniera completamente differente dalle abbreviazioni dichiarate esplicitamente. Queste ultime infatti vengono attuate automaticamente da Emacs quando si inserisce uno spazio o un segno di interpunzione, e l'espansione è regolata dalla definizione. Con le abbreviazioni dinamiche invece l'utente richiede esplicitamente l'espansione dell'abbreviazione (di solito con M-/), ed Emacs espande l'abbreviazione ricercando nel testo precedente la parola da usare. E' anche possibile richiedere di vedere tutte le parole che potrebbero essere espanse partendo da una certa abbreviazione, esattamente come quado si opera la "completion" di un file con la bash.

La documentazione completa sull'uso delle abbreviazioni è ovviamente disponibile nel manuale on line di Emacs, alla voce "Abbrevs".

Una particolarità del motore di ricerca ed espansione si nota quando si elaborano file in cui si usano simboli che contengono un MIX di maiuscolo/minuscolo. In questo caso se la parte del simbolo da espandere è composta solo da lettere o maiuscole o minuscole, l'espansione avviene col case corrispondente. Se invece il simbolo da espandere contiene già un mix di maiuscole e minuscole, l'espansione avviene regolarmente.

Compilazione & grep

Emacs, in unione al gcc, offre le stesse opportunità di vari tool commerciali. E forse qualcosa di più, visto che non è legato ad un singolo linguaggio, ma si adatta a vari linguaggi. Una di queste opportunità è quella di saltare col cursore ad un errore di compilazione. Ma andiamo con ordine. Uno dei comandi disponibili in Emacs è compile. Con questo comando si avvia un processo che prima aggiorna i file su disco rispetto alle versioni nei buffer dell'editor (chiedendo conferma) e poi avvia una compilazione in un sottoshell di emacs. Il comando di compilazione di default è make -k, ma è possibile editarlo, ad esempio cambiandolo in gcc -o helloworld helloworld.c. L'output della compilazione viene caricato nel buffer *compilation*. A questo punto è possibile far sì che Emacs faccia visitare i vari luoghi dei sorgenti dove è stato rivelato un errore, basta portarsi su un certo messaggio di errore e premere Return o il tasto 2 del mouse. Alternativamente il comando C-x ''' (backquote) passa all'errore successivo, mentre '''C-u C-x   ricomincia a considerare gli errori dall'inizio del buffer.

Con lo stesso principio è possibile attivare un grep e poi visitare le varie linee individuate all'interno dei sorgenti. Il modo che permette i parsing degli errori è attivabile in un qualsiasi buffer come minor mode, compilation-minor-mode, che ridefinisce i comportamenti di Return e del tasto 2 del mouse come definito prima.

E' comunque possibile, con un po' di lavoro, integrare Emacs in IDE preesistenti o adattarlo a compilatori diversi dal gcc. Addirittura è possibile che non sia necessario alcuna modifica, dipende dalla similitudine tra i formati dei messaggi di errore.

Debug

Emacs è in grado di fare da shell per vari debugger, tra cui ovviamente GDB. Questo non solo ne semplifica l'uso, ma ne potenzia persino le capacità.

Il modo GUD (attivabile con M-x gdb|dbx|xdb|sdb|perldb a seconda del debugger che si intende usare) controlla infatti il debugger attraverso una pipeline. In questo modo gli è possibile per prima cosa aggiungere l'history al debugger, nonché permette di scrivere, attraverso il lisp di Emacs, delle macro di controllo. C'è il limite di un solo processo di debugging attivo alla volta per ogni istanza di Emacs lanciata.

GUD una volta attivato gestisce l'iterazione con il debugger in una finestra con un buffer simile a quello della shell (più o meno simile ad un X-terminal), inoltre mostra in un'altro buffer il sorgente della porzione di programma attiva con una freccia ( ==> ) a marcare la linea corrente.

Una delle comodità del modo GUD è che il sorgente è lì pronto ad essere modificato, non c'è necessità di chiudere il debugger e ricaricare il sorgente per effettuare delle modifiche. Attenzione che ovviamente GUD non è in grado di seguire le vostre modifiche e quindi si comporterà in maniera quasi certamente scorretta con il sorgente modificato.

Notare che la freccia di cui si parlava prima non fa parte del buffer del sorgente, compare solo a video.

unix di comandi come mettere un breakpoint nella linea in cui c'è il cursore, o di agevolare l'accesso a comandi di uso frequente come next e step, che vengono attivati con C-c C-n e C-c C-s . Nelle situazioni in cui C-c viene interpretato dal sistema prima di essere passato a Emacs è possibile aggirare l'ostacolo sostituento a C-c la sequenza C-x C-a. Sono disponibili in questa forma, con un keybinding mnemonico, tutti i comandi di controllo dell'esecuzione. GUD ovviamente è in grado di gestire la completion dei comandi di GDB ed anche i comandi propri del debugger della GNU che lavorano a livello di stack frame. Come già in altre parti, rimando al comodissimo manuale on line di Emacs per tutti i dettagli. E ricordo che essendo un programma in Emacs Lisp, GUD offre ovviamente degli "hook" per la personalizzazione.

Senza X11

Emacs può essere utilizzato con eguale profitto sia sotto X11 che su un terminale alfanumerico. Anzi in questo caso Emacs unisce a tutto questo le caratteristiche di utility come screen o le console virtuali di Linux. Inoltre permette di suddividere lo schermo in finestre ridimensionabili dinamicamente. Permette perciò l'editing del sorgente, la compilazione, il debug e quant'altro senza dover uscire e rientrare dall'editor. Al contrario tutte queste attività possono essere condotte contemporaneamente esattamente come accade lavorando sotto X11. Anzi, Emacs ha permesso tutto ciò prima dell'avvento dei terminali grafici, e la cosa ha una traccia nella nomenclatura degli oggetti di Emacs. Infatti chiama le finestre di X frames mentre il termine window indica una delle aree in cui viene suddiviso uno spazio di output alfanumerico, sia esso un terminale o una finestra di X11.

Conclusione

Gli hook sono delle liste di funzioni che vengono richiamate quando si verifica un certo evento, e sono comuni a molti modi.

Ogni programmatore ha le sue preferenze, così come le ha ogni utente. Gli autori di Emacs e dei vari pacchetti sanno bene questo e gli hook sono lo strumento con cui permettono a ciascuno di adattare il comportamento dei vari modi o la risposta a certi eventi senza dover andare a modificare il pacchetto standard, cosa di fondamentale importanza nelle situazioni in cui più utenti condividono le stesse librerie Emacs LISP.

Per esperienza personale posso dire che, anche lavorando in ambienti famigerati come Windows, Emacs è uno strumento che facilita e rende più piacevole il programmare, e a dispetto della sua veneranda età è ancora in grado di far sfigurare prodotti molto più noti e reclamizzati.

Appendice A

Lo strumento di cui si parla in questa appendice (i tags) è utile più in fase di manutenzione di un programma. Coi tags infatti è possibile spostarsi velocemente da un punto all'altro di lunghi sorgenti anche divisi in piu' moduli, per raggiugere la dichiarazione di un simbolo o per eseguirne una sostituzione coerente in tutti i file sorgente.

Il primo passo per l'uso dei tags è la creazione di un database apposito, chiamato più propriamente tabella dei tags. Questa viene effettuata con il comando etags, che fa parte della distribuzione standard di emacs (insieme a ctags da cui deriva). L'operazione è banale, può spesso risolversi anche solo in un

etags -o database -a *.c *.h 

oppure in una più raffinata

find . -name "*.[chCH]" -print | etags - 

A questo punto la tabella può essere utilizzata facendo ricerche o per ricerca diretta o tramite espressioni regolari, tutto con comandi brevissimi da impartire (del tipo M-. o M-C-.) che attivano il motore di ricerca. Il manuale, oltre ai comandi spiega chiaramente cosa viene riconosciuto come tag in un determinato tipo di sorgente. Nella documentazione della versione 19.33 vengono specificati i comportamenti relativi al LISP, Scheme, C/C++, Yacc/Bison, Fortran, Pascal, Perl, Prolog, Assembler e LaTeX). E' inoltre possibile creare tabelle di tags basate su espressioni regolari per un qualsiasi file di testo.

Appendice B

Forse di interesse minore al grande pubblico, ma utilissimo per i gruppi che lavorano su un certo progetto, è la gestione delle versioni. Unix e Gnu dispongono di loro pacchetti adatti allo scopo.

Emacs li arricchisce e li integra in sé, dimostrandosi ancora strumento potentissimo per il programmatore. Questa appendice parla in maniera introduttiva dei sistemi di VC e quindi descrive brevemente lo strato software offerto da Emacs.

Emacs è in grado di interagire con in pacchetti RCS, CVS e SCCS, dei quali il primo è un prodotto GNU e liberamente disponibile come Emacs. Questo implica anche che sia quello meglio supportato da Emacs. CVS è basato su RCS, è più potente (permette ad esempio lo sviluppo concorrente da parte di più persone), ma alcune tra le operazioni meno comuni devono essere eseguite manualmente chiamando CVS dalla linea di comando. SCCS è un prodotto proprietario e, tra l'altro, è il più debole dei tre. Il sistema di Version Control di Emacs supplisce ad alcune delle sue mancanze ma non a tutte.

Il controllo della versione opera principalmente come una biblioteca un po' particolare, dove l'utente può non solo prendere a prestito la copia del libro disponibile (il file), ma anche modificarlo. All'atto della resa l'utente segnala al sistema di controllo versione che sono avvenuti cambiamenti e questi vengono accolti come nuova versione conservata, mentre un log tiene conto dei vari cambiamenti. Emacs provvede automaticamente a fornire un buffer utilizzato come descrizione dei cambiamenti apportati. Ovviamente è possibile richiedere una particolare versione al sistema, che automaticamente la genererà partendo dal master file ed applicando solo i cambiamenti richiesti per QUELLA versione. Questo viene definito col termine inglese branching.

In emacs l'accesso può avvenire ad una particolare versione o alla versione corrente. Il comando di accesso (o check out) di una particolare versione C-x C-q (vc-toggle-read-only), se non riceve alcun parametro, opera sull'ultima versione che è stata registrata nel sistema di controllo della revisione.

Lo stesso comando serve per liberare il file e registrare i cambiamenti apportati. Può essere invocato con o senza paremetro, a seconda che si desideri o no fissare un certo numero di versione. Prima di registrare i cambiamenti Emacs vi chiede di inserire una descrizione dei cambiamenti apportati in un'opportuno buffer di editing. Da notare che il comando per terminare l'inserimento della descrizione avviene col inviando il comando C-c C-c, lo stesso che si usa per uscire da vari modi di editing particolare (picture mode, e-mail ed usenet posting...). E' possibile richiamare una descrizione precedente attraverso un meccanismo di history. Lo scopo principe è di facilitare l'uso di una stessa descrizione su tutti i cambiamenti apportati in una sessione di lavoro ad un progetto, cambiamenti che possono riguardare vari file e che quindi comportano la ripetuta richiesta di una descrizione degli stessi. Questi tra l'altro sono gli stessi comandi per l'history nel minibuffer di Emacs e nei buffer relativi a ftp, shelle telnet.

Nei sistemi come RCS che permettono solo l'accesso esclusivo ai file, questo comando pone e toglie il lock ai file che si intende modificare. In CVS, che permette l'accesso contemporaneo ai file, nessun lock viene posto in fase di lettura, mentre in fase di rilascio del file intervengono dei meccanismi di risoluzione dei conflitti che si generano quando due programmatori lavorano sullo stesso file.

La registrazione di un nuovo file avviene con C-x v i. A questo punto è possibile scegliere il sistema di controllo versione (che per default è RCS). Se non viene indicato alcun parametro, il file viene registrato con numero di versione 1.1. Con il flag vc-initial-comment si indica a Emacs se è il caso o no di inserire un commento iniziale al file.

Come altrove in Emacs è possibile tornare sui propri passi con dei comandi undo. In questo caso ne sono disponibili due versioni, una che permette di ricaricare una versione non modificata del file (annullando tutto l'editing precedente) ed una che permette di annullare l'ultima registrazione.

Usando RCS (ma non gli altri sistemi) è possibile far generare o aggiornare a VC (il pacchetto di controllo versione di Emacs) il log di tutti i cambiamenti effettuati, basandosi sui log interni del sistema di controllo versione. Il comando è C-x v a. Il log riporta autore e cambiamenti effettuati in quella sessione, per ciascun file coinvolto.

Infine è possibile creare un'istantanea del progetto ad un certo stadio con un semplice comando C-x v s NAME RET. Un'istantanea richiede pochissime risorse, solo quelle necessarie per una lista di nomi di file e di numeri di versioni.

Il modo VC non finisce qui e nemmeno i sistemi di controllo della versione, ma questo penso basti a dare un'idea di cosa Emacs può fare anche in questo campo.

Buon lavoro!

Gianozia Orientale: DEIEmacs (last edited 2009-05-27 15:34:40 by localhost)