Emacs is not a mere sophisticated editor, it is an applied philosophy of programming (as defined in SICP together with best programming paradigms and standard programming idioms, a in a recursive process of developing a good-enough environment for text and source code editing, applied to itself.

It is a sacred symbol if you wish (along with Vi, which is a worthy sacred symbol of other sect) an idol which is made out of Lisp and machine code in the form of an executable binary. Like any religious symbols it should be treated with awe and respect - the program itself and its source code are both objects of worship (the principles they have embodied). This is how to think about some of the greatest programs produced by the best part of humanity.

Other religious symbols include MIT Scheme, SBCL, Erlang, etc.

Philosophy and principles

Emacs is an extensible environment for editing of texts. It is a Lisp engine, which happens to include an editor. Extensibility is the key concept, which means that it could be not merely customized (any editor is customize-able to some extent) but literally extended and adapted by the user for his or her specific needs. For this purpose it includes the most powerful DSL on the planet - a dialect of Common Lisp which is called Emacs Lisp.

One app to rule them all, one app to find them. 
One app to bring them all, and in Elisp bind them.

Unlike, say, Vim, which is fundamentally imperative, Emacs is more functional, if you will. Each session could be viewed (and recorded) as a sequence of function applications, which is exactly how it works. Each key is bound to a Lisp function, which uses primitive procedures, etc. Every Emacs session is a Lisp program. Literally.

Most of ordinary text characters are bound to this function

(self-insert-command N &optional C)

which inserts character C N times.

The combination Ctrl-p is bound to

(previous-line &optional ARG)

Type in the scratch buffer

(previous-line 1)

and press Ctrl-x Ctrl-e

Learning and understanding Emacs is, perhaps, a half of the journey for attaining a proper perspective of what programming is in principle (hint: applied science, like any other branch of engineering). So, lets start.

The basics

The combinations of key-strokes are called chords. These chords could be 3 strokes long, like Ctrl-x 5 2 or even longer.

Ctrl-x Ctrl-c
Ctrl-x Ctrl-f then Ctrl-g
Ctrl-x k then Ctrl-g
Ctrl-x b then Ctrl-g
Ctrl-x Ctrl-b then Ctrl-g
Alt-x then Ctrl-g

Ctrl-Space then Ctrl-n then Ctrl-w then Ctrl-y
Alt-f then Alt-f then Ctrl-Space then Alt-f then Alt-w then Ctrl-y

Some of these key sequences are historical artifacts - a tradition, such as Ctrl-x Ctrl-f while others are evolved for the sake of ergonomics, like the Ctrl-v/Alt-v duo.

Quick reference

Notice the patterns in these key sequences - they are not arbitrary or chaotic as it might seem to be. On the contrary they are logically grouped according to usage patterns and similarity. Similar things must look similar, different things - differently.

C-h c - describe key C-h k - help about key C-h f - help about command C-h v - help about variable
C-x C-c - exit Emacs M-x - enter command C-g - cancel command C-x u - undo
C-x C-f - open file C-x C-s - save file C-x C-w - write file as C-x k - kill buffer
C-x b - switch to buffer C-x C-b - list buffers C-x o - switch to other window
C-f - one character forward C-b - one character backward C-d - delete character backspace - erase character
M-f - one word forward M-b - one word backward M-d - delete word C-s - search
C-M-f - one s-expr forward C-M-b - one s-expr backward C-M-d - delete s-expr delete yanks
C-n - next line C-p - previous line
C-e - end of line C-a - beginning of line C-k - kill till end of line
M-e - end of sentence M-a - beginning of sentence M-k - kill till end of sentence
C-Space - set a mark C-w - kill M-w - copy C-y - yank
C-x C-x - exchange point and mark C-x h - mark-whole buffer M-h - mark paragraph C-M-h - mark s-expr
C-v - next page M-v - previous page C-M-v - scroll-down other window
M-> - end of buffer M-< - beginning of buffer
C-x 2 - horizontal split C-x 3 - vertical spit C-x 1 - close other window C-x 0 close window

Modes and packages

  • ivy + counsel

add to .emacs

(use-package ivy
  :ensure t
  :diminish ivy-mode
  :bind (("C-x b" . ivy-switch-buffer))
  (setq ivy-use-virtual-buffers t
        ivy-display-style 'fancy
        enable-recursive-minibuffers t)
  (global-set-key (kbd "C-c C-r") 'ivy-resume)
  (ivy-mode t))
(use-package counsel
  :ensure t
  :bind (("M-x" . counsel-M-x)
         ("C-c p" . counsel-rg)
         ("C-c n" . counsel-fzf))
  (global-set-key (kbd "M-x") 'counsel-M-x)
  (global-set-key (kbd "C-x C-f") 'counsel-find-file)

  (global-set-key (kbd "C-c g") 'counsel-git)
  (global-set-key (kbd "C-c j") 'counsel-git-grep)
  (global-set-key (kbd "C-c k") 'counsel-ag)
  (global-set-key (kbd "C-x l") 'counsel-locate)

(define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history)

  (global-set-key (kbd "C-h f") 'counsel-describe-function)
  (global-set-key (kbd "C-h v") 'counsel-describe-variable)
  (global-set-key (kbd "C-h l") 'counsel-find-library)
  (global-set-key (kbd "C-h i") 'counsel-info-lookup-symbol)
  (global-set-key (kbd "C-h u") 'counsel-unicode-char))
(use-package swiper
  :ensure t
  :after counsel
  :commands (swiper swiper-all)
  :bind (("C-s" . counsel-grep-or-swiper)
         ("C-r" . swiper)))
  • lsp-mode

add to .emacs (the new initialization procedure)

(use-package lsp-mode
  :ensure t
  (require 'lsp)
  (require 'lsp-clients)
  (add-hook 'programming-mode-hook 'lsp)
  (add-hook 'lsp-after-open-hook 'lsp-enable-imenu))

(use-package lsp-ui
  :ensure t
  :after lsp-mode
  (setq lsp-ui-sideline-enable t)
  (setq lsp-ui-doc-enable t)
  (setq lsp-ui-peek-enable t)
  (setq lsp-ui-peek-always-show t)
  (add-hook 'lsp-mode-hook 'lsp-ui-mode))

and then set up an appropriate language server

$ go get -u

and then add to .emacs

(use-package lsp-rust
  :after lsp-mode
  :ensure t)

(use-package lsp-go
  :after lsp-mode
  :ensure t)

(use-package lsp-haskell
  :ensure t
  :after lsp-mode
  (setq lsp-haskell-process-path-hie "hie-wrapper")
  (add-hook 'haskell-mode-hook 'lsp))

(use-package lsp-java
  :after lsp-mode
  :ensure t)

 (make-lsp-client :new-connection (lsp-stdio-connection "pyls")
                  :major-modes '(python-mode)
                  :server-id 'pyls))
  • wgrep, rg, fzf
    (use-package wgrep
      :ensure t)
    (use-package rg
      :ensure t
      :after wgrep
    (use-package ag
      :ensure t)
    (use-package fzf
      :ensure t)

Last modified 3 years ago Last modified on Dec 11, 2018, 11:54:29 AM
Note: See TracWiki for help on using the wiki.