EMACS:in alkeet – osa 1

EMACS:in alkeet Osa 1

Nykypäivänä kehittyneet IDE-ympäristöt tarjoavat erinomaiset työkalut ammattimaiseen ohjelmointiin. Ihmetystä saattaa herättää, miksi joku enää turvautuisi Visual Studio Coden kaltaisten kevyiden, helposti konfiguroitavien tehoeditorien aikakaudella käyttäjältä tuhottomasti tunteja opetteluun vaativiin, vuosikymmeniä vanhoihin Emacsiin tai Vimiin.

Emacsia pari vuotta aktiivisesti käytettyäni sen edut ja haitat moderneihin editoreihin nähden alkavat seljetä. Konfigurointi ja sen harjoittelu kieltämättä vievät aikaa. Tehokasta käyttöä varten on opeteltava vähintään Lisp-ohjelmointikielen, tai tarkemmin sanottuna sen Emacs Lisp -murteen, alkeet. En ole vielä itsekään siinä pisteessä, että Elisp tulisi selkärangasta.

   

GNU Emacs (logo kuvassa) on kaikkein yleisimmin käytetty Emacsin versio. Sen on kehittänyt vapaiden ohjelmistojen GNU-projekti.

Toisaalta, kun asetusten säätäminen alkaa sujua, kehitysympäristön kustomoitavuus ja venyminen eri käyttötarkoituksiin on aivan omaa luokkaansa. Emacsista saa tehokkaan editorin ohjelmointikielelle kuin ohjelmointikielelle juuri omilla säädöillä varustettuna. Tämän lisäksi kaikki käyttämäni ohjelmat ja työkalut alkavat pikkuhiljaa valua Emacsin sisälle. Tällä hetkellä hyödynnän sitä editorin lisäksi muun muassa terminaalina, PDF-lukijana, Git-käyttöliittymänä ja REST-clienttinä. Kätevät näppäinoikotiet, näppärät bufferi-työkalut sekä ylimääräisten ikkunoiden väheneminen tuntuvat myös tehostavan jokapäiväistä työskentelyäni.

Koodin editoimisen tarvittavien perusasioiden opettelu ei vaadi Emacsin parissa erityisen paljoa aikaa. Muutamassa tunnissa pääsee takuulla alkuun. Tehokäytön omaksuminen on sen sijaan vuosien prosessi. 

Tässä juttusarjassa kokoan kokemuksiani, joilla Emacsista saa näppärämmän työvälineen ja sen oppimiskäyrää loivennettua. Näitä tekstejä kirjoittaessani opettelen toisaalta myös itse uusia taitoja editorin parissa.

Ensimmäisinä vinkkeinäni jaan pari aloittelijallekin helposti käyttöön otettavaa temppua, joilla oma arkeni on helpottunut. Olen testannut ne Emacsin versiolla 25.2.2 Ubuntu 18.04:llä. Samalla harjoitellaan lukemaan hieman Elispiä. Näppäinoikoteiden läpikäynti on sivuroolissa, sillä hyviä cheat sheettejä löytyy helposti Googlella.

Paketit perille

Emacsin sydämessä on sen alustustiedosto, joka konfiguroi editorin asetukset halutunlaisiksi, kun Emacs käynnistetään. Se on Elispillä kirjoitettu ohjelmatiedosto, joka sijoitetaan tavanomaisesti polkuun ~/.emacs.d/init.el. tai suoraan kotihakemiston juureen nimellä .emacs. Tässä blogissa käytämme ensimmäistä vaihtoehtoa.

Ensimmäiseksi init.elissä kannattaa ottaa käyttöön Emacsin package.el-pakettimanagerikirjasto. Kirjoitetaan tätä varten init.elin alkuun seuraava Lisp-koodirivi:

(require 'package)

Komento require lataa ja suorittaa annetun Lisp-tiedoston, jos sitä ei ole aikaisemmin ladattu. Tässä tapauksessa tiedosto on package.el, joka tulee Emacsin mukana versiosta 24 lähtien. 

Heittomerkki package-nimen edessä kertoo Emacsille, että haluamme välittää argumenttina require-funktiolle symbolin package evaluoimatta sitä ensin. Elispissä symboli on objekti, jolla on nimi. Ilman heittomerkkiä Emacs yrittäisi evaluoida package-nimisen muuttujan sisältämän arvon, mikä johtaisi virheeseen.

Emacsin pakettimanageri linkittyy automaattisesti GNU ELPA (Emacs Lisp Package Archive) -pakettiarkistoon. Lisätään pakettimanagerimme seuraamiin arkistoihin myös MELPA (Milkypostman’s Emacs Lisp Packet Archive) -arkisto, josta löytyy suuri joukko hyödyllisiä Emacs-yhteisön ylläpitämiä paketteja. Tämä tapahtuu kirjoittamalla seuraavat koodirivit:

(add-to-list
 'package-archives

 '("melpa" . "http://melpa.org/packages/"))

Komento add-to-list lisää argumenttina annettuun listaan uuden jäsenen. Tässä esimerkissä lisätään package-archives-listaan pisteellä erotettu arvopari “melpa” . “http://melpa.org/packages/”.

Kuten arvata saattaa, package-archives-lista sisältää kaikki Emacsin pakettimanagerille määritellyt pakettiarkistot. Arkistot tunnistetaan ID:n ja sijainnin perusteella. Koodissa pistearvoparimme kertookin, että tämän lisättävän pakettiarkiston ID on “melpa” ja sen sijainti annettu URL-osoite.

Lisätään koodiimme vielä komento package-initialize, joka lataa ja aktivoi kaikki Emacsiin asennetut paketit. Muuten asennetut paketit aktivoitaisiin vasta, kun init.el on suoritettu, emmekä voisi käyttää niiden sisältämiä komentoja ja muuttujia init.elissä. Kun aloitamme ensimmäistä kertaa Emacsin käytön, meillä on asennettuna vain joukko editorin sisäänrakennettuja paketteja, joten ainoastaan ne aktivoituvat. 

(package-initialize)

Emacsin versiosta 27 eteenpäin package-initialize-komento ajetaan init.elin alussa automaattisesti. Varmistetaan tarkistamalla package–initialized-totuusarvo, ettei paketteja yritetä aktivoida kahteen kertaan, jos satummekin siirtymään jossain vaiheessa uudempaan Emacs-versioon. Muokataan siis edellistä komentoa hieman:

(unless package--initialized (package-initialize))

Emacs-paketteja voi normaalisti asentaa komennolla M-x package-list-packages, valitsemalla listastaan haluamansa paketit i-napilla ja painamalla lopuksi x. Toinen vaihtoehto on asentaa yksittäinen paketti suoraan komennolla M-x package-install. Kirjoitetuissa Emacs-komennoissa M tarkoittaa meta-näppäintä, yleensä vasenta Altia tai Macilla Optionia. M-x on tavallinen tapa ilmoittaa Emacs-näppäinyhdistelmä, tässä siis alustasta riippuen esimerkiksi Alt+x. 

Komento package-list-packages avaa näkymän saatavilla olevista paketeista.

Seuraavaksi asennamme muutaman hyödyllisen paketin. Pakettien asentuminen on hyvä automatisoida Emacsin käynnistyksen yhteydessä siten, että kaikki init.elissä käytettävät ennestään asentamattomat paketit asentuvat automaattisesti. Näin voimme helposti siirtää init.el-tiedoston mille tahansa muulle koneelle ja ottaa käyttöön Emacs-asetuksemme lennosta ilman turhaa manuaalista pakettien asentelua.

Tätä toiminnallisuutta varten säädämme init.elin ensin käyttämään äärimmäisen hyödyllistä MELPA-arkiston pakettia nimeltä use-package. Se helpottaa kaikin tavoin muiden pakettien käyttöönottoa ja konfiguroimista.

Emme kuitenkaan asenna use-package-pakettia käsin vaan annamme init.elin hoitaa sen automaattisesti kirjoittamalla seuraavat komennot:

(unless (package-installed-p 'use-package)
  (package-refresh-contents)

  (package-install 'use-package))

Muuttuja package-installed-p sisältää totuusarvon, jota käytetään tarkistamaan, onko use-package-paketti jo asennettu. Jos ei ole, lataamme muistiin listan kaikista pakettiarkistojemme sisältämistä paketeista komennolla package-refresh-contents. Sen jälkeen asennamme use-package-paketin komennolla package-install. 

Tähän mennessä init.el-tiedostomme sisältää siis seuraavan koodin:

(require 'package)
(add-to-list

 'package-archives

 '("melpa" . "http://melpa.org/packages/"))

(unless package--initialized (package-initialize))

(unless (package-installed-p 'use-package)

  (package-refresh-contents)

  (package-install 'use-package))

Tarkastellaan pian, miten use-package-paketti auttaa muiden pakettien asentamisessa. Tässä vaiheessa on kuitenkin hyvä testata, miten Emacs reagoi käynnistäessä, jos init.elissä tapahtuu virhe. Kommentoidaan esimerkiksi package-initialize-rivi pois käyttäen puolipistettä:

;; (unless package--initialized (package-initialize))

Seurauksena Emacs antaa meille käynnistettäessä varoituksen ja virheen. Käynnistämällä ohjelman –debug-init-lipun kera saa virheestä lisätietoa.

Tämänkaltainen varoitus on vihje siitä, että jotain meni init.eliä suorittaessa pieleen.

Bufferinavigointia

Emacsissa keskeinen konsepti on bufferit, jotka toimivat ikään kuin muiden editorien välilehdet. Ne ovat tekstiobjekteja, joita voidaan näyttää Emacsin ikkunoissa. Esimerkiksi jokaisen avatun tiedoston sisältöä varten luodaan oma bufferinsa.

Hyvin nopeasti Emacsin käytön aloitettuaan huomaa, että bufferien välillä navigointi pelkin oletuskomennoin, kuten C-x b:tä käyttämällä, on tuskaisen kömpelöä. Esimerkiksi eri bufferi-vaihtoehtojen listaaminen edellyttää ylimääräistä TAB:n painallusta. Tässä muuten C viittaa vasempaan Ctrl-näppäimeen.

Helpottaaksemme bufferien välillä liikkumista, asennetaan seuraavaksi paketti nimeltä Helm. Helm on Emacs-ohjelmistokehys automaattisiin hakuihin ja tekstin täydennykseen. Voimme asentaa ja ottaa käyttöön Helm-paketin hyödyntämällä use-package-komentoa:

(use-package helm
  :ensure t)

Tässä :ensure t tarkoittaa, että use-package asentaa Helmin, jos sitä ei ole aikaisemmin asennettu. Näin varmistamme, että vaikka siirtäisimme init.el-tiedostomme kokonaan toiselle koneelle, Emacs asentaa Helm-paketin automaattisesti käynnistyksen yhteydessä. Kaksoispistenotaatiolla kerrotaan, että ensure on use-package-funktion avainsanaparametri.

Helmin sisältämät toiminnallisuudet ovat hyvin laajat ja monipuoliset, mutta helpotetaan arkeamme parilla yksinkertaisella tempulla. Ensin vaihdetaan normaali Emacsin komentojen listaus Helmin kehittyneemmäksi versioksi sitomalla näppäinyhdistelmä M-x komentoon helm-M-x. Asetetaan myös helm-mode käynnistymään aina Emacsin käynnistyessä. Tämän seurauksena yleisimmät Emacs-komennot käyttävät oletuksena Helm-täydennystä.

(use-package helm
  :ensure t

  :bind ("M-x" . helm-M-x)

  :init (helm-mode 1))

Kun Emacsin nyt käynnistää ja kokeilee näppäinyhdistelmää M-x, eron huomaa heti. Helm osaa rajata ehdotuksia käytettävissä olevista komennoista epämääräistenkin hakujen perusteella.

 

Jos package-list-packages-komento on unohtunut, sen löytää nyt helposti.

Myös C-x b:llä buffereiden vaihto ja seulonta toimii nyt merkittävästi siedettävämmin.

Buffereiden selaaminen ei vaadi enää tabin rämpytystä.

Sidotaan vielä yksi näppäinoikotie Emacsin oletustoiminnallisuutta avuliaampaan Helm-komentoon, nimittäin tiedostojen avaaminen, joka tapahtuu tavallisesti näppäinyhdistelmällä C-x C-f:

(use-package helm
  :ensure t

  :bind (("M-x" . helm-M-x)

     ("C-x C-f" . helm-find-files))

  :init (helm-mode 1))

Tämän jälkeen myös tiedostopolkujen selaamisesta muodostuu huomattavasti miellyttävämpää.

Nyt init.elin löytää helposti.

Tämän kaiken jälkeen init.elimme näyttää siis tältä:

(require 'package)
(add-to-list

 'package-archives

 '("melpa" . "http://melpa.org/packages/"))

(unless package--initialized (package-initialize))

(unless (package-installed-p 'use-package)

  (package-refresh-contents)

  (package-install 'use-package))

(use-package helm

  :ensure t

  :bind (("M-x" . helm-M-x)

     ("C-x C-f" . helm-find-files))

  :init (helm-mode 1))

Tähän mennessä ollaan saatu kuitenkin vasta pakettien asennus automatisoitua ja hieman parannettua Emacsin perustoimintojen, kuten bufferien vaihdon ja tiedostojen avaamisen, käytettävyyttä. Tutkitaan seuraavassa osassa, miten paketit saa myös päivittymään automaattisesti, parannellaan editorin käytettävyyttä lisää ja tutustutaan tehokkaan Git-käyttöliittymän tarjoavaan Magit-pakettiin.

Tilaa uutiskirjeemme, niin saat tiedon seuraavasta osasta: buutticonsulting.com/uutiskirje

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *