UP | HOME

Emacs configuration for C++/CMake/git

Table of Contents

Intro

I hope this emacs configuration file will help explain a little elisp and how to write your own.

The most important take-away is understanding how emacs can help read and learn from other people's configurations. Once you know how to navigate the documentation you can pick apart any config file and expand your own

Note that I wrote this knowing no lisp at all - so if there are mistakes or you would like to make some suggestions I'd really appreciate you telling me by adding an issue on the github repo

General Settings

Hack for AppImage

There is some issue with the way the Emacs AppImage is setup so it interferes with git

(if (getenv "APPDIR") (setenv "LD_LIBRARY_PATH" nil))

Hide menu bars

(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)

Package managment

To begin extending Emacs we will want to be able to add external packages. Emacs comes with a built in package manager called package which we will use to get external package. We load it by using require and then we initialize it.

(require 'package)
(package-initialize)

To see more specifically what the require function does type C-h f require RET. You'll find that virtually every function will have some associted documentation.

Note the use of a leading quote before the word package; This tells emacs that the word package is a symbol. If you ommit the quote then emacs will try to evaluate package as a function and give you an error.

Next we need to tell the package manager where to look for new packages. There is a limited GNU-blessed repository called ELPA, but we will also want to add another larger repository called MELPA. To do that we we just need to add it to the list called package-archives
To look up a variable, use C-h v [variable] RET So type C-h v package-archives RET to see what it's for

(setq package-archives '(("gnu"   . "http://elpa.emacs-china.org/gnu/")
                         ("melpa" . "http://elpa.emacs-china.org/melpa/")))

This C-h [something] [something] pattern repeats for a lot of features. To see the complete list just enter C-h C-h. These key-bindings will be your way of exploring configurations you find online.

The newer fancy way of managing package is using use-package. I've included it as a git submodule in my .emacs.d directory which you can see in the repository (be sure to clone recursively if you decide to use my version). You can get it yourself manually from: https://github.com/jwiegley/use-package

Once we have it in our directory we just need to add it to the load-path and load it in using require like last time

(setq
 load-path
 (cons
  (concat
   (file-name-directory load-file-name)
  "use-package")
  load-path))
(require 'use-package)

setq is the function that sets a variable to a value. The q indicates that we don't need to add a quote to the first arguement. There is also the more cumbersome (set 'arg1 'arg2). The rest of the code is there to append the new path to use-package correctly to the existing load-path.

Auto-update

This will make the packages update to the latest version every few days

;; (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))

Import shell variables

Especially when we launch emacs in daemon mode, the environmental variables won't be set up. So for example it won't find executables in the PATH b/c the PATH won't be set up the way you have it in your .bashrc file. So there is a special package to fix that

(use-package exec-path-from-shell
  :ensure t
  :config
  (unless (memq system-type '(ms-dos windos-nt cygwin))
    (exec-path-from-shell-initialize)))

Indentation - Change the default indentation from 2 spaces to 4

Indentation is generally govered by two variables
default-tab-width - this is the variable for any text document when you normally type in a TAB
c-basic-offset - when working with source code the indentation is done automatically and based on this offset value (a lot of modes derive from c-mode, hence the name)
More info: https://kb.iu.edu/d/abde

;  (setq c-basic-offset 4)

in ELisp it's also a bit hard to see the indentation level, so I like to add this guide (REMOVED)

;; (use-package indent-guide
;;    :ensure t
;;    :config
;;   (indent-guide-global-mode))

Trying out the very weird Parinfer mode (this code is straight copied from their github

(use-package parinfer
  :ensure t
  :bind
  (("C-," . parinfer-toggle-mode))
  :init
  (progn
    (setq parinfer-extensions
          '(defaults       ; should be included.
             pretty-parens  ; different paren styles for different modes.
             evil           ; If you use Evil.
             lispy          ; If you use Lispy. With this extension, you should install Lispy and do not enable lispy-mode directly.
             paredit        ; Introduce some paredit commands.
             smart-tab      ; C-b & C-f jump positions and smart shift with tab & S-tab.
             smart-yank))   ; Yank behavior depend on mode.
    (add-hook 'clojure-mode-hook #'parinfer-mode)
    (add-hook 'emacs-lisp-mode-hook #'parinfer-mode)
    (add-hook 'common-lisp-mode-hook #'parinfer-mode)
    (add-hook 'scheme-mode-hook #'parinfer-mode)
    (add-hook 'lisp-mode-hook #'parinfer-mode)))

Line wrap

Next we need to enable line-wrap in org mode. By default, as you keep typing the page scrolls to the right. So a whole paragraph will appear as one line making it difficult to navigate

(add-hook 'org-mode-hook (lambda () (setq truncate-lines nil)))

again, don't hesitate to look up all the variables and function. Hooks are in general places where you can add function to be called at designated times. Here it's a function that sets a variable each time org-mode is enabled.

Theme

This is the only decent light theme I could find. The advantage over the default theme is that it will color a more things in more modes. The most important to me me is that it will color code blocks in org-mode

;; (use-package moe-theme
;;   :ensure t
;;   :config
;;   (moe-light)
;;   (set-face-attribute 'default nil :background "#ffffff" :foreground "#5f5f5f"))
(use-package leuven-theme
  :init (setq leuven-scale-outline-headlines nil)
        (setq leuven-scale-org-agenda-structure nil)
  :ensure t)

The last line makes the background white (instead of yellow)

Git

For using git we want to have a couple of tools

Autosave/Backup files

By default Emacs will save copies of files with a ~ appended. This ends up cluttering directories and makes any directory touched by Emacs a bit of a mess. Instead we can have Emacs save files to a central directory.

See: https://www.emacswiki.org/emacs/BackupDirectory and https://stackoverflow.com/questions/151945/how-do-i-control-how-emacs-makes-backup-files

(setq
   backup-by-copying t      ; don't clobber symlinks
   backup-directory-alist
    '(("." . "~/.saves/"))    ; don't litter my fs tree
   delete-old-versions t
   kept-new-versions 6
   kept-old-versions 2)

Magit

This is the tool for inspecting and updating out git repository. It's a little complicated to use, so look up documentation for it. It is a must for development in emacs if you use git - so make the investment and learn to use it.

(use-package magit
  :ensure t)

Projectile

This will manage our workspaces. Each workspace will be tied to a git repository. This makes it so that our buffer list doesn't get really crowded when we are working on multiple projects

(use-package projectile
  :ensure t
  :config
  (projectile-mode))

I sometimes use this - and other times I just run separate emacs sessions for different projects.

images

When you open a GIF, make it loop forever (instead of playing through once and stopping

(setq image-animate-loop t)

Hit RET to have it start playing

system-monitor

A tiny in-bar system monitor is convenient (and doesn't need to be part of my desktop).

;; (use-package symon
;;   :ensure t
;;   :config
;;   (add-to-list 'symon-monitors 'symon-linux-battery-monitor)
;;   (symon-mode))

which-key

This is gunna give us tips for different modes so we can learn new key-combos

(use-package which-key
  :ensure t)

Standardizing (WIP)

These are some changes that bring Emacs more in line with how modern applications work. Most people don't do this.. I'm giving it a try

Overwrite selection

This will make it so that if you start typing after selecting some text it will actually overwrite what you selected instead of ignoring the selection and appending to the end. See: https://www.gnu.org/software/emacs/manual/html_node/efaq/Replacing-highlighted-text.html

(delete-selection-mode 1)

CUA Mode

This is the standard copy-cut-paste shortcuts that are different in Emacs by default. By restoring them to the standard Ctrl C/X/V it will interfere with some existing shortcuts in Emacs. So now whenever you see a Ctrl C You need to hit Ctrl C C. Off the top of my head I know this affects CIDER (Clojure code) and orgmode.

;  (cua-mode t)

Orgmode

Some adjustments to org-mode

see here for reference

(setq org-confirm-babel-evaluate nil ;; don't prompt for confirmation about executing a block
      org-src-tab-acts-natively t
      org-use-sub-superscripts '{}
      org-src-fontify-natively t
      org-clock-into-drawer nil
      org-export-backends (quote (ascii html latex md odt))
      org-cycle-emulate-tab 'white)
(use-package htmlize
  :ensure t)
  • Turns off the annoying "are you sure?" prompts on tangle export
  • Makes tabs work in the source code blocks the same as it would in a buffer with that source code
  • Makes it so underscores aren't interpreted as subscripts unless used with braces

(I often need underscores for file/variable names)

  • Make source code gets colored based on the language
  • Newer version of Orgmode stick clocks into logbooks which aren't useful for me
  • Enable exporting to Markdown (for a full set of options run customize-option then enter org-export-backends (editing this will modify your init.el)
  • Make collapsing and expanding sections with the TAB button work everywhere (except where it makes sense to insert an actual tab)
  • htmlize will colorize orgmode code-blocks code in the exported HTML

For more info on any of these variables, again, use C-h v [variable] RET

Plotting

For one of my ongoing "project" I want my ELisp code to be able to output plots. For that we need to add gnuplot and then enable execution of gnuplot blocks in orgmode. The last line lets me make plots interactively in the gnuplot buffer

(use-package gnuplot
    :ensure t)

(org-babel-do-load-languages
 'org-babel-load-languages
 '((gnuplot . t)))

(gnuplot-inline-display-mode)

C++

Here we'll setup a development environment as feature rich as an IDE
We're going to use the new language server protocol way (instead of rtags as before). I'm just following the official guide

lsp-mode

;; (use-package lsp-mode
;;   :ensure t)

emacs-cquery

;; (use-package emacs-cquery
;;   :commands lsp-cquery-enable
;;   :init (setq cquery-executable "~/Programs/cquery/bin/cquery")
;;   (add-hook 'c-mode-hook #'cquery//enable)
;;   (add-hook 'c++-mode-hook #'cquery//enable)
;;   :ensure t)

Clojure

(WIP) Getting Clojure to play friendly with Orgmode is a bit weird. But you can sorta get it to work like ELisp, where you execute blocks within the document itself useing C-c C-c. You just need to open the corresponding tangled .clj file once, launch the REPL using C-c M-J and then make sure it's all loaded with C-c C-k. After this you don't need to really touch the tangled file anymore. You just need to change to the correct namespace in your REPL with the usual (in-ns 'something.somethingelse) and then you can just stick to running code blocks in the org document. The last step is crucial b/c when you run blocks in your org document they will be effectively running in whatever state your REPL is in (though the output will go to RESULTS blocks in the org document and not the REPL output/buffer). So it's a bit goofy.. b/c the org document runs are tied to the current REPL state.

If there is no REPL running then the thing seems to just not run at all. The auto-jack-in option here doesn't seem to really work unfortunately. This might make exporting with no running REPL a bit broken. We'll see how the setup works..

(require 'ob-clojure)
(setq org-babel-clojure-backend 'cider)
(setq ob-clojure-literate-auto-jackin-p t)

Starting to play around with Clojure. The canonical Clojure development environment is CIDER

(use-package cider
  :ensure t
  :init (setq org-babel-clojure-backend 'cider))