EMACS:in alkeet – osa 2

EMACS:in alkeet – Osa 2

Viime blogikirjoituksen päätteeksi saatiin laitettua Emacsiimme kuntoon puitteet automaattiselle  pakettien asennukselle käynnistyksen yhteydessä ja otettiin käyttöön Helm-paketti editorin käytettävyyden parantamiseksi. Jatketaan tutustumalla yksinkertaisiin ja yleisiin keinoihin, joilla käytettävyyttä voi parantaa entisestään.

Viimeistellään aluksi viime kerralla init.elissä aloittamamme Helm-säädöt. Tällä hetkellä näppäinoikotie C-x b sidotaan oletuksena komentoon helm-mode-switch-to-buffer, kun helm-mode otetaan käyttöön. Sidotaan se kuitenkin hieman edistyneempään komentoon helm-mini, joka osaa näyttää erikseen viimeisimmät tiedostot ja antaa myös mahdollisuuden luoda uuden bufferin: 

(use-package helm

  :ensure t

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

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

     ("C-x b" . helm-mini))

  :init (helm-mode 1))

Komento helm-mini on näppärä buffereiden vaihtamiseen ja uusien bufferien luomiseen.

Lisäksi korjataan pari rasittavaa Helmin oletuskäyttäytymistä. Ensinnäkin tiedostoja tai buffereita selatessa tabulaattorin painallus tuo ärsyttävästi näkyviin toimintavalikon automaattisen täydennyksen sijaan. Linux-terminaaleihin tottunut tuleekin painelleeksi sitä erehdyksessä vähän väliä enterin sijaan. Täydennyskomento on sen sijaan Helmissä sidottu näppäinyhdistelmään C-z. Vaihdetaan nämä komennot päittäin siten, että tabulaattori täydentää ja C-z tuo esiin toimintavalikon:

(use-package helm

  :ensure t

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

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

     ("C-x b" . helm-mini)

     :map helm-map 

     ("<tab>" . helm-execute-persistent-action)

     ("C-z" . helm-select-action))

  :init (helm-mode 1))

Yllä asetamme avainsanaparametrin map arvoon helm-map. Se rajaa listassa seuraavat näppäinoikotiesidonnat ainoastaan Helm-komentojen, kuten helm-find-filesin, kontekstiin. C-z ei siis aja komentoa helm-select-action muulloin kuin jonkin helm-bufferin ollessa esillä. 

Muokataan vielä pari näppäinoikotietä helm-find-files-komennon kontekstissa. Tällä hetkellä, jos polkuja selatessamme painamme backspacea ja sen jälkeen yritämme painaa tabia, toimintavalikko avautuu jälleen ärsyttävästi. Tämä johtuu siitä, että Helm ketjuttaa pinnan alla backspacen painallukseen muita näppäinyhdistelmiä, minkä serauksena sitä painettuamme omat näppäinasetuksemme lakkaavat toimimasta.

Yliajetaan backspace-näppäimen käytös sitomalla se vain yhden merkin poistamiseen eli komentoon helm-ff-delete-char-backward. Backspacesta käytetään Emacsissa usein merkintää <DEL>.

(use-package helm

  :ensure t

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

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

     ("C-x b" . helm-mini)

     :map helm-map 

     ("<tab>" . helm-execute-persistent-action)

     ("C-z" . helm-select-action)

     :map helm-find-files-map

     ("<DEL>" . helm-ff-delete-char-backward))

  :init (helm-mode 1))

Voimme vielä hiukan hienostella. Yhden hakemiston siirtyminen polussa ylöspäin onnistuu tällä hetkellä vasemmalla nuolinäppäimellä, mutta sinne sormet taipuvat hiukan hankalasti. Emme myöskään halua sitoa backspacea hakemistopolussa ylöspäin siirtymiseen, sillä se poistaisi mahdollisuuden korjata tiedostopolkua merkki kerrallaan. Sidotaan hakemistopolussa ylöspäin siirtyminen eli helm-find-files-up-one-level sen sijaan näppäinyhdistelmään Ctrl + backspace.

(use-package helm

  :ensure t

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

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

     ("C-x b" . helm-mini)

     :map helm-map 

     ("<tab>" . helm-execute-persistent-action)

     ("C-z" . helm-select-action)

     :map helm-find-files-map

     ("<DEL>" . helm-ff-delete-char-backward)

     ("C-<backspace>" . helm-find-files-up-one-level))

  :init (helm-mode 1))

Koska Helmin alkuperäisissä asetuksissa käytetään <DEL>:iä ja <backspace>:a ristiin, meidänkin on tehtävä niin, jotta alkuperäinen näppäinyhdistelmä yliajautuu oikein.

Nyt Helm alkaa olla jo kohtalaisen miellyttävä käyttää, joten voimme keskittyä tähdellisempiin asioihin.

Editori aina valmiina

Seuraavaksi säädetään Emacs ajautumaan daemonina eli taustaprosessina. Tässä etu on muun muassa se, että vaikka sattuisimme sulkemaan Emacsin, voimme avata sen uudelleen ja kaikki bufferimme säilyvät koskemattomina. Se on hyvä tapa välttää yllättävän usein tapahtuvia vahinkoja, jotka ovat sitä harmittavampia, mitä enemmän avonaisia buffereita editoriin alkaa kertyä. Toiseksi se mahdollistaa Emacsin aukaisemisen useaan kertaan ilman, että editorin hyödyntämät paketit on ladattava ja aktivoitava uudelleen.

Useimmissa Linux-jakeluissa, kuten Ubuntussa, voimme asettaa Emacsin käynnistymään käyttöjärjestelmän käynnistyksen yhteydessä systemd:n avulla. Tämä tapahtuu luomalla seuraavan asetustiedoston polkuun ~/.config/systemd/user/emacs.service:

[Unit]

Description=Emacs text editor

Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/




[Service]

Type=forking

ExecStart=/usr/bin/emacs --daemon

ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)"

Environment=SSH_AUTH_SOCK=%t/keyring/ssh

Restart=on-failure




[Install]

WantedBy=default.target

Lyhykäisyydessään tämä tiedosto mahdollistaa Emacs-daemonin käynnistämisen ja sen sulkemisen systemd:n kautta. Kun Emacs-daemon on kerran käynnistetty, se käynnistyy uudelleen automaattisesti myös koneen uudelleen käynnistymisen jälkeen. Emacsin versiosta 26.1 lähtien tämä tiedosto tulee Emacsin asennuksen mukana eikä sitä tarvitse luoda erikseen.

Nyt voimme ottaa systemd-yksikkömme käyttöön komennolla:

systemctl enable --user emacs

 Ja käynnistää Emacs-daemonin komennolla:

systemctl start --user emacs

Jos daemonin haluaa sammuttaa, esimerkiksi init.el-muutosten testaamiseksi uudelleen käynnistettäessä, se tapahtuu komennolla:

systemctl stop --user emacs

Ohjeet vastaavan toiminnallisuuden toteuttamiseen muilla käyttöjärjestelmillä sekä Linux-jakeluilla, jotka eivät tue systemd:n user-konfiguraatioita, löytyvät täältä: https://www.emacswiki.org/emacs/EmacsAsDaemon.

Nyt Emacs käynnistetään asiakasohjelmana komennolla emacsclient -c. Voimme vielä yksinkertaistaa komentojen muistamista kirjoittamalla .bashrc-tiedostoon muutaman aliaksen:

alias emc="emacsclient -c &"

alias start-emacs="systemctl start --user emacs"

alias stop-emacs="systemctl stop --user emacs"

Tällä hetkellä menetämme kuitenkin vielä kaikki avaamamme tiedostot, jos tietokone on tarvetta käynnistää uudelleen. Tämän ongelman välttämiseksi käytetään automaattista Emacs-työpöydän tallentamista. Se varastoi editorin sulkemishetkellä datan Emacs-työpöydän sisällöstä omaan tiedostoonsa, jonka Emacs voi myöhemmin lukea, kun se avataan uudelleen.

Aktivoidaan automaattinen tallentaminen asettamalle päälle desktop-save-mode:

(desktop-save-mode 1)

Tämä moodi ei toimi ihan suoraan sulavasti yhdessä Emacs-daemonin kanssa. Daemon ei nimittäin osaa reagoida prompteihin, joita Emacs esittää käyttäjälle työpöydän tallennuksen ja lukitun työpöydän lataamisen yhteydessä. Lisätään muutama komento, joilla daemon saadaan automaattisesti tallentamaan työpöytä tietokoneen sulkeutuessa ja lataamaan se, kun tietokone jälleen avataan:

(setq desktop-save t)

(setq desktop-path '("~/.emacs.d/"))

(setq desktop-load-locked-desktop t)

Tässä asetamme Emacsin tallentamaan työpöydän kyselemättä aina, kun Emacs suljetaan. Lisäksi asetamme  työpöydän tallentumaan aina suoraan .emacs.d-hakemiston alle. Määräämme myös, että lukittukin työpöytä ladataan, kun Emacs käynnistetään. Tietokonetta sulkiessa daemon näet tapaa jättää työpöydän lukituksi, minkä jälkeen se ei ilman tätä asetusta saa sitä enää auki, kun tietokone on käynnistynyt uudelleen.

Lisäksi voimme säätää aikaväliä, jolla Emacs tallentaa työpöydä tiheämmäksi kuin oletusarvona käytettävä 30 sekuntia:

(setq desktop-auto-save-timeout 5)

Lopuksi korjataan vielä yksi pieni häiritsevä seikka. Emacs olisi mukava saada käynnistymään automaattisesti koko ruudulle. Se onnistuu seuraavalla komennolla:

(add-to-list 'default-frame-alist '(fullscreen . maximized))

Git gud

Tähän mennessä olemme lähinnä perehtyneet siihen, miten Emacsin käytettävyyttä voi parantaa. Vielä on kuitenkin jäänyt hämärän peittoon, mitä todellisia etuja sillä on muihin editoreihin ja IDE:ihin nähden. Tämän havainnollistamiseksi tutustumme seuraavaksi magit-pakettiin, joka on äärimmäisen tehokas Git-käyttöliittymä Emacsiin. Asennamme magitin use-packagea hyödyntäen:

(use-package magit

  :ensure t

  :bind (("C-x g" . magit-status)))

Yllä luomme myös hyödyllisen näppäinoikotien komennolle magit-status, joka lienee magitin käytetyin komento. 

Pysäytetään nyt Emacs-daemon komennolla stop-emacs, käynnistetään se uudelleen komennolla start-emacs ja avataan client komennolla emc. Testataan näppäinyhdistelmää C-x g. Magit kysyy Git-repositoriota, joten liikutaan hakemistorakenteessa sellaisen juureen. Eteen pitäisi avautua seuraavan kaltainen näkymä:

 

Magit-status-näkymä Buutter-repositoriosta.

Repositoriopolkua selatessa saattaa muuten huomata, että C-<backspace>-yhdistelmä ei toimikaan tässä Helm-näkymässä. Tämän saa korjattua lisäämällä Helm-näppäinoikoteihin vielä yhden mäppäyksen helm-read-file-mapin alle:

(use-package helm

  :ensure t

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

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

     ("C-x b" . helm-mini)

     :map helm-map 

     ("<tab>" . helm-execute-persistent-action)

     ("C-z" . helm-select-action)

     :map helm-find-files-map

     ("<DEL>" . helm-ff-delete-char-backward)

     ("C-<backspace>" . helm-find-files-up-one-level)

     :map helm-read-file-map

     ("<DEL>" . helm-ff-delete-char-backward)

     ("C-<backspace>" . helm-find-files-up-one-level))

  :init (helm-mode 1))

Magitin käyttämiseen löytyy useita tutoriaaleja ja cheat sheettejä, joten erinäisiä näppäinoikoteitä ei käydä syvällisesti läpi tässä. Niiden opettelussa menee pieni hetki, mutta sen jälkeen Gitin kanssa työskentely on takuulla sujuvampaa ja tehokkaampaa kuin komentoriviltä käsin. Esittelen muutaman yleisen käyttötapauksen kuvien kera, jotka valaisevat paketin hyödyllisyyttä.

Magitissa on helppo siirtää tiedostoja staging-alueelle ja takaisin yhdellä napin painalluksella. Commitoiminen puolestaan onnistuu näppäinyhdistelmällä c-c ja sen jälkeen C-c:

Magitin commit-näkymä.

Tämän jälkeen S-p (shift + p) aukaisee push-valikon, josta pushaaminen onnistuu p-näppäimellä. Näin add-commit-push-workflow onnistuu hyvin nopeasti muutaman näppäimen painalluksella!

Myös pushaaminen onnistuu Magitissa hyvin näppärästi.

Muita hyvin olennaisia valikkoja Magitissa ovat muun muassa b-näppäimestä aukeava branch-valikko. Uusien branchien luominen ja niiden välillä loikkiminen onkin hyvin helppoa. Myös rebase-valikkoa tulee käytettyä hyvin usein.

Kaikki branch-toiminnot löytyvät yhden napin takaa.

Sama pätee rebase-toimintoihin.

Myös Git-logia voi tarkastella helposti näppäinyhdistelmällä l-l. Jokaisen commitin kohdalta voi aukaista sitä vastaavan diffin. Näppäinyhdistelmillä d-s ja d-u voi puolestaan katsella stagingin ja stagingiin kuulumattomien muokattujen tiedostojen diffiä.

Magitin lokinäkymä.

Staging-alueen diff-näkymä.

Päivitykset kuntoon

Koska olemme asentaneet Emacsiin jo pari pakettia, tutustutaan vielä, miten paketit saadaan päivittymään automaattisesti. Tätä varten voimme käyttää auto-package-update-pakettia. Konfiguraatioasetus auto-package-update-maybe päivittää paketit Emacsin käynnistyksen yhteydessä.

(use-package auto-package-update

  :ensure t

  :config (auto-package-update-maybe))

Voimme lisäksi määritellä auto-package-updatelle muutaman muunkin konfigurointiasetuksen. Asettamalla muuttujan auto-package-update-delete-old-versions arvoon true vanhentuneet paketit poistetaan automaattisesti. Muuttujalla auto-package-update-interval voidaan puolestaan säätää automaattisten päivitysten vähimmäisaikaväliä vuorokausina. Oletusasetus on seitsemän päivää.

(use-package auto-package-update

  :ensure t

  :config (setq auto-package-update-delete-old-versions t

               auto-package-update-interval 4)

  (auto-package-update-maybe))

Kaiken päätteeksi init.elimme näyttää seuraavalta:

(require 'package)

(add-to-list

 'package-archives

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




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




;; desktop-save settings

(desktop-save-mode 1)

(setq desktop-save t)

(setq desktop-path '("~/.emacs.d/"))

(setq desktop-load-locked-desktop t)

(setq desktop-auto-save-timeout 5)




;; miscellaneous settings

(add-to-list 'default-frame-alist '(fullscreen . maximized))




;; automatic package installation

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

  (package-refresh-contents)

  (package-install 'use-package))




;; auto updates

(use-package auto-package-update

  :ensure t

  :config (setq auto-package-update-delete-old-versions t

     auto-package-update-interval 4)

  (auto-package-update-maybe))




;; external package configurations

(use-package helm

  :ensure t

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

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

     ("C-x b" . helm-mini)

     :map helm-map

     ("<tab>" . helm-execute-persistent-action)

     ("C-z" . helm-select-action)

     :map helm-find-files-map

     ("<DEL>" . helm-ff-delete-char-backward)

     ("C-<backspace>" . helm-find-files-up-one-level)

     :map helm-read-file-map

     ("<DEL>" . helm-ff-delete-char-backward)

     ("C-<backspace>" . helm-find-files-up-one-level))

  :init (helm-mode 1))




(use-package magit

  :ensure t

  :bind (("C-x g" . magit-status)))

 

Komentojen järjestystä on muokattu hieman loogisemmaksi ja muutamia kommentteja lisätty.

Nyt Emacsin paketit asentuvat ja päivittyvät automaattisesti, sen perustoimintojen käytettävyyttä on kohennettu ja se pysyy jatkuvasti päällä muistaen avaamamme tiedostot myös uudelleenkäynnistyksen jälkeen. Lisäksi olemme asentaneet siihen tehokkaan Git-käyttöliittymän. Ensi osassa juttusarjaa perehdymme koodin editointia helpottaviin kikkoihin käyttäen esimerkkikielenä Pythonia. 

2 thoughts on “EMACS:in alkeet – osa 2

Vastaa

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