Prologue

I have known about Emacs since the late 1990s. I have used Emacs as a primary code editor since about 2001. A lot of XEmacs back then, when XEmacs was more fancy than GNU Emacs. Then back to GNU Emacs when it caught up.

It is not an exclusive marriage. I am also a vim user. I always reach for vim for configuration files, to search for a few lines to change, add or delete and then quit the editor. I gladly learn new vim tricks. Still, Emacs accompanies me when I need to stare at my editor for longer, when I need to think. Ironically, I sometimes edit snippets in my Emacs’ init.el using vim.

I like Emacs (and vim, incidentally) for two reasons.

The first is that it works remotely. It serves me everything I am used to over remote SSH or mosh connections, even over miles-high, spotty sattelite links. I want the confidence to not get interrupted if I accidentally damage or lose my computer. I travel a lot. I rarely bring my files with me; they stay on a server and I log in remotely to work.

The second one is that it will remain there until I die. I observe my peers struggle with learning new muscle memory and troubleshoot editor discomforts every 3-10 years, as fashions ebb and flow. This extends into weeks, if not months of cumulative wasted hours of life. Emacs let me spend that time just once, when I was younger. Over the years, I have used the spared time to enrich my life in other ways.

These two reasons, alone, made me skip over Eclipse, IntelliJ, NetBeans, JetBrains, VStudio, Atom, Sublime, VSCode, GoLand and many others. None of them offered me productivity gains that would significantly offset the time I’ve spared not learning them, as they came, and eventually will go down, through history.

Disclaimer: Your Mileage May Vary

Emacs’ default (non-customized) configuration is pretty decent. I recommend it to new learners.

My policy is and remains to not change editor configurations unless there is a reason. My usual reason is to accelerate or simplify actions that I notice I am performing often already.

So my current customizations are just that: things that make my life easier. Yours may need something else.

The simple things

I use Emacs in text terminals and I know my shortcuts. I value an extra line of text in the window.

(menu-bar-mode 0)

I find myself measuring the width of items horizontally. Syntax errors also mention column numbers. It is annoying that Emacs does not show the column number by default.

(column-number-mode 1)

As I switch back and forth between my editor and other things, I want to quickly remind myself where my cursor is positioned. I do this by highlighting the current line.

(global-hl-line-mode 1)

When I edit prose, and the format requires paragraphs to fit on a single line of the output file, I want my editor to wrap properly at word boundaries.

(global-visual-line-mode 1)

Many tools choke when there is excess whitespace characters, or when they are in the wrong place. It is also common for coding styles to encourage a line width limit.

(global-whitespace-mode 1)
;; see the apropos entry for whitespace-style
(setq
   whitespace-style
   '(face ; viz via faces
     trailing ; trailing blanks visualized
     lines-tail ; lines beyond
                ; whitespace-line-column
     space-before-tab
     space-after-tab
     newline ; lines with only blanks
     indentation ; spaces used for indent
                 ; when config wants tabs
     empty ; empty lines at beginning or end
     )
   whitespace-line-column 100 ; column at which
        ; whitespace-mode says the line is too long
)

Matching parentheses, braces, etc.

(show-paren-mode 1)

A recent discovery: swiper.

(require 'swiper)
(global-set-key "\C-s" 'swiper)
(global-set-key "\C-r" 'swiper-backward)

Let’s edit some Go code!

The standard Emacs tab width is 8 spaces. That doesn’t work with Go.

(add-mode-hook 'go-mode-hook (lambda ()
    (setq tab-width 4)))

Yasnippet automatically inserts code templates when I write a word and press the tab key. It predefines most of the common Go templates, including the dreadful if err != nil { .... It is also necessary to fully support code completions as demonstrated below.

(require 'yasnippet)
(yas-global-mode 1)

Flycheck is one of the two main packages for code checks in the background. The other one is Flymake. I use Flycheck because it allows me to define a custom “advanced” checker (see below).

(require 'flycheck)
(global-flycheck-mode 1)

Another recent discovery: Emacs now has support for the Language Server Protocol (LSP). Beware that the go-lsp server running in the background still contains a memory leak as of this writing. I use ulimit in my shell to stop processes from consuming more than 50% of physical RAM; this kills an unbehaving go-lsp and Emacs simply restarts it as needed.

(require 'lsp-mode)
(add-hook 'go-mode-hook #'lsp)

Go is one of these languages that mandate a particular code layout. To prevent non-normalized code from reaching version control, I auto-format on every save.

(add-hook 'before-save-hook 'gofmt-before-save)

Advanced Go tricks

Part of my work is concerned with optimizing Go for performance. This includes paying attention about where memory gets allocated. Neither the LSP mode nor the standard flycheck linters help with this. However, we can create a new flycheck linter.

The key idea is to run the go-build linter with the command go build -gcflags -m to activate reporting of the results of optimizations. My linter shows me which variables escape to the heap, and also informs me of which functions get inlined.

(flycheck-define-checker go-build-escape
  "A Go escape checker using `go build -gcflags -m'."
  :command ("go" "build" "-gcflags" "-m"
            (option-flag "-i" flycheck-go-build-install-deps)
            ;; multiple tags are listed as "dev debug ..."
            (option-list "-tags=" flycheck-go-build-tags concat)
            "-o" null-device)
  :error-patterns
  (
   (warning line-start (file-name) ":" line ":"
          (optional column ":") " "
          (message (one-or-more not-newline) "escapes to heap")
          line-end)
   (warning line-start (file-name) ":" line ":"
          (optional column ":") " "
          (message "moved to heap:" (one-or-more not-newline))
          line-end)
   (info line-start (file-name) ":" line ":"
          (optional column ":") " "
          (message "inlining call to " (one-or-more not-newline))
          line-end)
  )
  :modes go-mode
  :predicate (lambda ()
               (and (flycheck-buffer-saved-p)
                    (not (string-suffix-p "_test.go" (buffer-file-name)))))
  :next-checkers ((warning . go-errcheck)
                  (warning . go-unconvert)
                  (warning . go-staticcheck)))

(with-eval-after-load 'flycheck
   (add-to-list 'flycheck-checkers 'go-build-escape)
   (flycheck-add-next-checker 'go-gofmt 'go-build-escape))

I’ve also always found Go excessively verbose. Since Emacs 24, there is a minor mode prettify-symbols-mode which performs substitutions on the output window. I am using this aggressively for Go.

(add-hook
 'go-mode-hook
 (lambda ()
   (push '("error" . ?) prettify-symbols-alist)
   (push '("err" . ?) prettify-symbols-alist)
   (push '("exists" . ?) prettify-symbols-alist)
   (push '(":= range" . ?) prettify-symbols-alist)
   (push '("ok" . ?) prettify-symbols-alist)
   (push '("==" . ?) prettify-symbols-alist)
   (push '(":=" . ?) prettify-symbols-alist)
   (push '(">=" . ?) prettify-symbols-alist)
   (push '("<=" . ?) prettify-symbols-alist)
   (push '("<-" . ?) prettify-symbols-alist)
   (push '("!=" . ?) prettify-symbols-alist)
   (push '("..." . ?) prettify-symbols-alist)
   (push '("nil" . ?) prettify-symbols-alist)
   (push '("make" . ?&) prettify-symbols-alist)
   (push '("new" . ?&) prettify-symbols-alist)
   (push '("context.Context" . ?) prettify-symbols-alist)
   (push '("ctx" . ?) prettify-symbols-alist)
   (push '("mu" . ?) prettify-symbols-alist)
   (push '("&&" . ?) prettify-symbols-alist)
   (push '("||" . ?) prettify-symbols-alist)
   (push '("!" . ?¬) prettify-symbols-alist)
   (push '("interface{}" . ?) prettify-symbols-alist)
   (push '("struct{}" . ) prettify-symbols-alist)
   ))
(global-prettify-symbols-mode 't)

It would be nice to also be able to abbreviate more aggressively, for example using the following:

(push '("err != nil" . ?) prettify-symbols-alist)
(push '("func(err error) error" . "∆→∆") prettify-symbols-alist)
(push '("func(ctx context.Context) error" . "◇→∆") prettify-symbols-alist)
(push '("func(" . "λ(") prettify-symbols-alist)
(push '("tree." . ?🌲) prettify-symbols-alist) ; for cockroachdb

unfortunately this runs into a current bug in the implementation of prettify-symbols-mode which prevents substitutions spanning multiple font-face types.

Other items of potential interest

  • Magit is absolutely unmissable for everything Git-related.
  • Flyspell does spell checks for me, and I prefer to use aspell as back-end.
  • Company helps for text completion when LSP does not.
  • I have Helm configured for menu lists and it kicks in to fuzzy-search files inside a project. I tried Ivy for this purpose as well, but it is still a bit young for my taste. However, I took swiper from the Ivy project for in-buffer searches.

The full init.el

Here it is, also to be downloaded via this link.

Beware before reusing this configuration file:

  • you should not run someone else’s software unless you understand what it does. For all you know, there could be a virus hidden in there.
  • This was made for GNU Emacs 27. Unsure about previous versions or other Emacs flavors.
  • This requires a number of Emacs packages to be already installed. See the list at the bottom. You may need to run go-projectile-install-tools at least once. I also use the external spell checker aspell.
  • I use a non-standard overload of gofmt-command which requires a non-standard program to be installed at a non-standard location. Unless you do this, the gofmt integration (and gofmt-on-save) will break.
;; This is free and unencumbered software released into the public domain.
;;
;; Anyone is free to copy, modify, publish, use, compile, sell, or
;; distribute this software, either in source code form or as a compiled
;; binary, for any purpose, commercial or non-commercial, and by any
;; means.
;;
;; In jurisdictions that recognize copyright laws, the author or authors
;; of this software dedicate any and all copyright interest in the
;; software to the public domain. We make this dedication for the benefit
;; of the public at large and to the detriment of our heirs and
;; successors. We intend this dedication to be an overt act of
;; relinquishment in perpetuity of all present and future rights to this
;; software under copyright law.
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
;; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
;; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
;; OTHER DEALINGS IN THE SOFTWARE.
;;
;; For more information, please refer to <http://unlicense.org/>

;; who-am-i?
; used by git, mail, etc.
(setq user-mail-address "yourmail@example.com")
(setq user-full-name "Your Esteemed Full Name")

;;;;;;;;;;;;;;;;;;;;;;; Productivity ;;;;;;;;;;;;;;;;;;;;;

;;(prefer-coding-system 'utf-8-unix) ; encoding for input and writing files
;;(global-font-lock-mode 't) ; enable syntax highlighting by default
(column-number-mode 't) ; show current column in status bar

(global-whitespace-mode) ; enable whitespace handling by default
(setq
  whitespace-style ; see (apropos 'whitespace-style)
  '(face ; viz via faces
    trailing ; trailing blanks visualized
    lines-tail ; lines beyond whitespace-line-column visualized
    space-before-tab
    space-after-tab
    newline ; lines with only blanks visualized
    indentation ; spaces used for indent when config wants tabs
    empty ; empty lines at beginning or end or buffer
    )
  whitespace-line-column 100) ; column at which whitespace-mode says the line is too long

;; Spell check - install "aspell" and aspell dictionaries.
(setq
  ispell-program-name "aspell"
  ispell-extra-args '("--sug-mode=ultra"))

;;;;;;;;;;;;;;;;;;;;;;;; Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Where to install things from.
(require 'package)
(add-to-list 'package-archives
                         '("melpa" . "http://melpa.milkbox.net/packages/") t)

;; A separate directory to store custom Lisp code.
(setq load-path
          (append (list "~/.emacs.d/lisp") load-path))


;;;;;;;;;;;;;;;;;;;;;;;; Project mgt ;;;;;;;;;;;;;;;;;;;;;;;;;

;; Advanced per-language checks.
(require 'flycheck)
(global-flycheck-mode 1)
(setq flycheck-checker-error-threshold 1000) ; for large go files and the escape checker

;; Advanced git interface.
(require 'magit)
(setq magit-fetch-modules-jobs 16)

;; Navigation inside code project
(require 'projectile)
(projectile-mode "1.0")

;; Helm: incremental completion and selection narrowing inside menus/lists
(require 'helm)
(require 'helm-config)
(require 'helm-projectile)
(helm-mode 1)
(helm-projectile-on)

(setq helm-split-window-inside-p            t ; open helm buffer inside current window, not occupy whole other window
      helm-move-to-line-cycle-in-source     t ; move to end or beginning of source when reaching top or bottom of source.
      helm-ff-search-library-in-sexp        t ; search for library in `require' and `declare-function' sexp.
      helm-scroll-amount                    8 ; scroll 8 lines other window using M-<next>/M-<prior>
      helm-ff-file-name-history-use-recentf t
      helm-echo-input-in-header-line t)

(require 'company) ; code completion framework
(require 'compile) ; per-language builds
(require 'yasnippet)
(yas-global-mode 1)

(require 'lsp-mode) ; language server
;;(add-hook 'lsp-mode-hook 'lsp-ui-mode) ; display contextual overlay
;;(with-eval-after-load 'flycheck
;;  (add-to-list 'flycheck-checkers 'lsp-ui))
(require 'company-lsp)
(push 'company-lsp company-backends)

;; Note: do not use 'lsp-ui-flycheck; this replaces the "advanced"
;; Go checkers including our custom escape checker below.

;;;;;;;;;;;;;;;;;;;;;;;; Python ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Requires: anaconda, company

(add-hook 'python-mode-hook 'anaconda-mode)
(add-hook 'python-mode-hook 'anaconda-eldoc-mode)
(eval-after-load "company"
  '(add-to-list 'company-backends 'company-anaconda))
(eval-after-load "company"
  '(add-to-list 'company-backends '(company-anaconda :with company-capf)))
(add-hook 'python-mode-hook #'lsp)

;;;;;;;;;;;;;;;;;;;;;;;; Go ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 'go-projectile)
(go-projectile-tools-add-path)
(setq go-projectile-tools
  '((gocode    . "github.com/mdempsky/gocode")
    (golint    . "golang.org/x/lint/golint")
    (godef     . "github.com/rogpeppe/godef")
    (errcheck  . "github.com/kisielk/errcheck")
    (godoc     . "golang.org/x/tools/cmd/godoc")
    (gogetdoc  . "github.com/zmb3/gogetdoc")
    (goimports . "golang.org/x/tools/cmd/goimports")
    (gorename  . "golang.org/x/tools/cmd/gorename")
    (gomvpkg   . "golang.org/x/tools/cmd/gomvpkg")
    (guru      . "golang.org/x/tools/cmd/guru")))

;;(require 'company-go) ; obsolete with company-lsp
(require 'go-mode)
(add-hook 'go-mode-hook #'lsp)
(add-hook 'go-mode-hook (lambda ()
  (company-mode) ; enable company upon activating go
  ;;(set (make-local-variable 'company-backends) '(company-go))

  ;; Code layout.
  (setq tab-width 2 indent-tabs-mode 1) ; std go whitespace configuration
  (add-hook 'before-save-hook 'gofmt-before-save) ; run gofmt on each save

  ;; Shortcuts for common go-test invocations.
  (let ((map go-mode-map))
    (define-key map (kbd "C-c a") 'go-test-current-project) ;; current package, really
    (define-key map (kbd "C-c m") 'go-test-current-file)
    (define-key map (kbd "C-c .") 'go-test-current-test)
    )

  ;; Fix parsing of error and warning lines in compiler output.
  (setq compilation-error-regexp-alist-alist ; first remove the standard conf; it's not good.
        (remove 'go-panic
                (remove 'go-test compilation-error-regexp-alist-alist)))
  ;; Make another one that works better and strips more space at the beginning.
  (add-to-list 'compilation-error-regexp-alist-alist
               '(go-test . ("^[[:space:]]*\\([_a-zA-Z./][_a-zA-Z0-9./]*\\):\\([0-9]+\\):.*$" 1 2)))
  (add-to-list 'compilation-error-regexp-alist-alist
               '(go-panic . ("^[[:space:]]*\\([_a-zA-Z./][_a-zA-Z0-9./]*\\):\\([0-9]+\\)[[:space:]].*$" 1 2)))
  ;; override.
  (add-to-list 'compilation-error-regexp-alist 'go-test t)
  (add-to-list 'compilation-error-regexp-alist 'go-panic t)
  ))


;; CockroachDB-style Go formatter from github.com/cockroachdb/crlfmt.
;; This is also symlinked as ~/.emacs.d/gotools/bin/goimports.
(setq gofmt-command "~/src/go/bin/crlfmt")
(setq gofmt-args '("-tab" "2"))

;; Bonus: escape analysis.
(flycheck-define-checker go-build-escape
  "A Go escape checker using `go build -gcflags -m'."
  :command ("go" "build" "-gcflags" "-m"
            (option-flag "-i" flycheck-go-build-install-deps)
            ;; multiple tags are listed as "dev debug ..."
            (option-list "-tags=" flycheck-go-build-tags concat)
            "-o" null-device)
  :error-patterns
  (
   (warning line-start (file-name) ":" line ":"
          (optional column ":") " "
          (message (one-or-more not-newline) "escapes to heap")
          line-end)
   (warning line-start (file-name) ":" line ":"
          (optional column ":") " "
          (message "moved to heap:" (one-or-more not-newline))
          line-end)
   (info line-start (file-name) ":" line ":"
          (optional column ":") " "
          (message "inlining call to " (one-or-more not-newline))
          line-end)
  )
  :modes go-mode
  :predicate (lambda ()
               (and (flycheck-buffer-saved-p)
                    (not (string-suffix-p "_test.go" (buffer-file-name)))))
  :next-checkers ((warning . go-errcheck)
                  (warning . go-unconvert)
                  (warning . go-staticcheck)))

(with-eval-after-load 'flycheck
   (add-to-list 'flycheck-checkers 'go-build-escape)
   (flycheck-add-next-checker 'go-gofmt 'go-build-escape))

;;;;;;;;;;;; Personal preferences ;;;;;;;;;;;;;;;;;;;;;;;

(menu-bar-mode 0)
(show-paren-mode t) ; highlight matching open and close parentheses
(global-hl-line-mode) ; highlight current line
(global-visual-line-mode t) ; wrap long lines
(setq split-window-preferred-function
  'visual-fill-column-split-window-sensibly) ; wrap at window boundary

(require 'ido)
(require 'ido-vertical-mode)
(ido-mode) ; intelligent C-x C-f
(ido-vertical-mode)
(setq magit-completing-read-function 'magit-ido-completing-read)

(require 'swiper) ; better interactive search
;; Predefined: ((kbd "M-g g") 'goto-line)
;; Predefined: (kbd "C-c r t")  rectangle insert
;; Predefined: ((kbd "C-x c i") 'helm-semantic-or-imenu)
;; Predefined: ((kbd "C-x c /") 'helm-find)

(global-set-key (kbd "C-c <left>")  'windmove-left)
(global-set-key (kbd "C-c <right>") 'windmove-right)
(global-set-key (kbd "C-c <up>")    'windmove-up)
(global-set-key (kbd "C-c <down>")  'windmove-down)
(global-set-key "\M-#" 'query-replace-regexp)
(global-set-key "\M-," 'flyspell-goto-next-error)
(global-set-key "\M- " 'set-mark-command)
(global-set-key "\M-*" 'pop-tag-mark)
(global-set-key "\M-x" 'helm-M-x)
(global-set-key "\C-s" 'swiper)
(global-set-key "\C-r" 'swiper-backward)
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
(global-set-key (kbd "C-x f") 'helm-projectile-find-file)
(global-set-key (kbd "M-y") 'helm-show-kill-ring)
(global-set-key (kbd "C-x b") 'helm-mini)
(global-set-key (kbd "C-x c o") 'helm-occur)
(global-set-key [f9] 'projectile-test-project)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(add-hook 'go-mode-hook (lambda ()
  (go-guru-hl-identifier-mode) ; higlight all occurrences of identifier at point
  (local-set-key (kbd "M-.") #'godef-jump) ; M-. is jump-to-definition
  (define-key projectile-command-map (kbd "G") 'vc-git-grep)
  ))

;; Indent 4 spaces by default. Use the "BSD" style for C-like languages.
(setq c-default-style
      (quote ((java-mode . "java")
              (awk-mode . "awk")
              (other . "bsd")))
      c-basic-offset 4)

;; Use 4 spaces for one tab visually.
(setq tab-width 4)

;; Clearer colors on a dark background.
(custom-theme-set-faces 'user
 '(error ((t (:foreground "Pink" :underline t :weight bold))))
 '(warning ((t (:foreground "DarkOrange" :underline t :weight bold)))))

;; Agressive symbol substitution for Go.
(add-hook
 'go-mode-hook
 (lambda ()
   (push '("!=" . ?) prettify-symbols-alist)
   (push '("!" . ?¬) prettify-symbols-alist)
   (push '("&&" . ?) prettify-symbols-alist)
   (push '("||" . ?) prettify-symbols-alist)
   (push '("..." . ?) prettify-symbols-alist)
   (push '(":= range" . ?) prettify-symbols-alist)
   (push '(":=" . ?) prettify-symbols-alist)
   (push '("<-" . ?) prettify-symbols-alist)
   (push '("<<" . ?«) prettify-symbols-alist)
   (push '("<=" . ?) prettify-symbols-alist)
   (push '("==" . ?) prettify-symbols-alist)
   (push '(">=" . ?) prettify-symbols-alist)
   (push '(">>" . ?») prettify-symbols-alist)
   (push '("String" . "𝓢") prettify-symbols-alist)
   (push '("context.Context" . ?) prettify-symbols-alist)
   (push '("ctx" . ?) prettify-symbols-alist)
   (push '("err" . ?) prettify-symbols-alist)
   (push '("error" . ?) prettify-symbols-alist)
   (push '("exists" . ?) prettify-symbols-alist)
   (push '("interface{}" . ?) prettify-symbols-alist)
   (push '("make" . ?&) prettify-symbols-alist)
   (push '("mu" . ?) prettify-symbols-alist)
   (push '("new" . ?&) prettify-symbols-alist)
   (push '("make" . ?&) prettify-symbols-alist)
   (push '("nil" . ?) prettify-symbols-alist)
   (push '("ok" . ?) prettify-symbols-alist)
   (push '("string" . "𝓢") prettify-symbols-alist)
   (push '("struct{}" . ) prettify-symbols-alist)
   (push '("func" . "λ") prettify-symbols-alist)
   ;; The following are interesting but trigger a display bug --
   ;; prettify-symbols-alist misbehaves when the start and end faces
   ;; are different.
   ;; See: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=39390
   ;;
   ;; (push '("func(" . "λ(") prettify-symbols-alist)
   ;; (push '("err != nil" . ?∆) prettify-symbols-alist)
   ;; (push '("func(err error) error" . "∆→∆") prettify-symbols-alist)
   ;; (push '("func(ctx context.Context) error" . "◇→∆") prettify-symbols-alist)
   ;; (push '("tree." . ?🌲) prettify-symbols-alist) ; for cockroachdb
   ))
(global-prettify-symbols-mode 1)
(setq prettify-symbols-unprettify-at-point t)


;; Additional suggestions - http://steve.yegge.googlepages.com/effective-emacs
;; 1) swap capslock and control
;;   osx: preference panel, keyboard, special keys
;; 2) M-x without meta
;(global-set-key "\C-x\C-m" 'execute-extended-command)
;(global-set-key "\C-c\C-m" 'execute-extended-command)
;; 3) C-w is backward-kill-word, not backspace
;(global-set-key "\C-w" 'backward-kill-word)
;(global-set-key "\C-x\C-k" 'kill-region)
;(global-set-key "\C-c\C-k" 'kill-region)
;; 4) use incremental search for navigation
;; 5) use temp buffers (C-x b, then new name)
;; 6) master buffer and window commands
;; C-x 1,2,3,o
;; C-x +  balance-windows
;; C-x C-b list-buffers


;; end .emacs additions

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(package-selected-packages
   '(yasnippet-snippets magit python-mode yasnippet helm-lsp company-lsp lsp-ui flycheck-rust flycheck-plantuml flycheck-tcl go-guru go-rename emacsql emacsql-sqlite erc-image helm-projectile visual-fill-column bison-mode company-anaconda pycomplete pymacs yaml-tomato yaml-mode tuareg switch-window protobuf-mode neotree markdown-mode gotest godoctor go-projectile dirtree company-go clojars auto-complete))
 '(split-window-preferred-function 'visual-fill-column-split-window-sensibly))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(error ((t (:foreground "Pink" :underline t :weight bold))))
 '(warning ((t (:foreground "DarkOrange" :underline t :weight bold)))))

Reminder to self, keyboard shortcuts

;; C-x f          -- fuzzy file search in project
;; C-x c /        -- fuzzy file search in current directory
;; C-c p G        -- helm git grep from current directory (save: C-x C-s)
;; C-u 1 C-c p G  -- helm git grep from project root
;;
;; M-%            -- query-replace
;; M-#            -- query-replace-regexp
;;
;; M-.            -- go to definition (also: C-c C-o j)
;; M-*            -- navigate back
;; C-c C-o r      -- list referrers
;; C-x c i        -- list definitions in current file
;;
;; C-c .          -- run Go test at point
;; C-c a          -- run all Go tests in package and sub-packages
;;
;; C-x g          -- magit menu
;; P - f p        -- push w/ force
;;
;; M-y            -- show kill ring
;; C-x r t        -- insert rectangle interactive
;; C-x r k        -- kill rectangle
;; C-x r y        -- yank rectangle
;;
;; C-x 3          -- split window vertically
;; C-x +          -- balance windows
;;
;; C-x (          -- start defining macro
;; C-x )          -- end macro definition
;; C-x C-k r      -- apply-macro-to-region-lines

Acknowledgements

The animations were produced using vokoscreen.

Like this post? Share on: TwitterHacker NewsRedditLinkedInEmail


Raphael ‘kena’ Poss Avatar Raphael ‘kena’ Poss is a computer scientist and software engineer specialized in compiler construction, computer architecture, operating systems and databases.
Comments

So what do you think? Did I miss something? Is any part unclear? Leave your comments below.


Keep Reading


Reading Time

~12 min read

Published

Category

Programming

Tags

Stay in Touch