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
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))
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
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/")))
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
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
.
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))
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 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)))
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.
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)
(custom-theme-set-faces
'user
'(variable-pitch ((t (:family "unifont"))))
'(fixed-pitch ((t ( :family "unifont"))))
'(org-block ((t (:inherit fixed-pitch :background "#FFFFEA")))))
;; (set-fontset-font t 'han "Zpix")
;; (add-hook 'org-mode-hook 'variable-pitch-mode)
;; (add-hook 'org-mode-hook 'visual-line-mode)
The last line makes the background white (instead of yellow)
For using git we want to have a couple of tools
(use-package ivy
:ensure t)
(ivy-mode 1)
(setq ivy-use-virtual-buffers t)
(setq ivy-count-format "(%d/%d) ")
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
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)
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)
;;(use-package ergoemacs-mode
;; :ensure t
;; :config
;; (setq ergoemacs-theme nil)
;; (setq ergoemacs-keyboard-layout "us")
;; (ergoemacs-mode 1))
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
org-export-with-timestamps nil)
(use-package htmlize
:ensure t)
(setq org-babel-default-header-args:octave '((:results . "org")
(:session . "*Inferior Octave*")
(:eval . "never-export")
(:exports . "both")))
(setq org-babel-default-header-args:org '((:eval . "never")))
- 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 enterorg-export-backends
(editing this will modify yourinit.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 HTMLorg-babel-default-header-args
are default ways I like to display run results in orgmode (subject to change)
For more info on any of these variables, again, use C-h v [variable] RET
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)
(octave . t)
(clojure . t)))
(gnuplot-inline-display-mode)
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
;; (use-package lsp-mode
;; :ensure t)
;; (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)
(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))
Add a default CIDER alias
(setq cider-clojure-cli-global-options "-A:server:client:dev")
Next we turn on company
. The package that will do autocompletion for us (it standards for COMPlete ANYthing)
(use-package company
:config
(add-hook 'cider-repl-mode-hook #'cider-company-enable-fuzzy-completion)
(add-hook 'cider-mode-hook #'cider-company-enable-fuzzy-completion)
(global-set-key (kbd "TAB") #'company-indent-or-complete-common))
;(push 'company-rtags company-backends) TODO: FIX this RTags related stuff!
;;(global-company-mode)
looking at the documentation we see that push
will take the 1st argument and add it to the beginning of the list provided in the 2nd argument. company-backends
is “a list of active backends (completion engines)”. company-rtags
is a backend provided by the rtags
guys. See the documentation for more info :)
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)
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
:init)
;; (setq magit-display-buffer-function #'magit-display-buffer-fullcolumn-most-v1))
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 +1))
(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(setq projectile-completion-system 'ivy)
(setq projectile-use-git-grep t)
(setq projectile-use-native-indexing t)
;;(setq projectile-enable-caching t)
(setq projectile-git-command "/usr/bin/git ls-files -zc")
I sometimes use this - and other times I just run separate emacs sessions for different projects.
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
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))
This is gunna give us tips for different modes so we can learn new key-combos
(use-package which-key
:ensure t)
make scrolling in Emacs more sane
;(setq mouse-wheel-scroll-amount '(0.07))
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1)))
(setq mouse-wheel-progressive-speed nil)
(setq scroll-step 1)
Set links to open in the Emacs browser (then press & if you need to open them in Firefox)
;(setq browse-url-browser-function 'eww-browse-url)
Example of how to set a font from within Emacs
;; (set-face-attribute 'default nil :font "tewi:pixelsize=11:foundry=lucy:weight=normal:slant=normal:width=normal:spacing=110:scalable=false")
;; (set-frame-font "tewi:pixelsize=11:foundry=lucy:weight=normal:slant=normal:width=normal:spacing=110:scalable=false" nil t)
- magit status
- git gutter
- export to html
- tangle file
- refresh/revert file
- launch REPL
- F12
- Go to Definition (VS)
- F11
- Step Into
- F12
- Step Out
- F10
- Step Over
- F9
- Toggle Breakpoint (VS)
- F8
- Build Selection
- F7
- F5
- Debug Start
- F3
- Split Window (Dolphin)
- F4
- Shell (Dolphin)
(global-set-key (kbd "<f2>") 'magit-status)
(global-set-key (kbd "<f3>") 'cider-browse-ns)
(global-set-key (kbd "<f4>") 'eshell)
(setq display-buffer-alist '(("\\`\\*e?shell" display-buffer-use-some-window)))
(global-set-key (kbd "<f5>") 'calendar)
(global-set-key (kbd "<f6>") 'org-babel-tangle)
(global-set-key (kbd "<f7>") 'org-html-export-to-html)
(global-set-key (kbd "<f8>") 'eshell)
(global-set-key (kbd "<f9>") 'cider-jack-in)
(global-set-key (kbd "<f10>") 'cider-xref-fn-refs)
(global-set-key (kbd "<f11>") 'cider-browse-ns-all)
(global-set-key (kbd "<f12>") ''cider-enlighten-mode)
Live in ~/.emacs.d/bookmarks
Set bookmarks with =
C-x r m RET
C-x r m /bookmark/ RET
Jump to bookmark
C-x r b /bookmark/ RET
List bookmarks
C-x r l
C-l
recenter around pointshow-trailing-whitespace
- to display.. whitespacedelete-trailing-whitespace
display-time
display-battery-mode
“Save As”
C-x C-w
Autoreload files (like logs.. ones that change “under you”)
C-h C-h
general help menuC-h a /topic/ RET
approposC-h i d m emacs RET i /topic/ RET
indexC-h i d m emacs RET s /topic/ RET
manual textC-h C-f
FAQ[prefix] C-h
completion optionsC-h b
all active bindings (minor/major modes)C-h m
major/minor modesC-h d /topic/ RET
aproposC-h e
Messages bufferC-h h
HELLO file + character setC-h i
Info + ManualC-h k /key/
describe keyC-h o /symbol/
info on symbol
C-x C-d
directory listingC-u C-x C-d
vebose directory listingmake-directory
delete-directory
q
bury Dired bufferSPC/n
navigate dired up/downj
go to filee/f RET
extract file into buffer tar moded
deletem
mark as file (with a *)**
mark all executable filesu
unmarkx
execute pending operationsC /new/ RET
like cp with new being the argD
like rm removed marked filesR /new RET
renameH /new RET
hard linkS /new RET
soft linkM /new RET
change modeG /new RET
new groupO /new RET
new ownerT /new RET
touchZ
compress (each into it’s own archive)c
compress into one archive:d
decompress:v
verify signature:s
sign:e
encrypt!
run shell command&
same but asyncI
insert file (empty))
Hide details (we turn on by default)~
go “up” a directory (like..
)/host:filename
/user@host:filename
/user@host#port:filename
method:user@host#port:filename
M-x gdb
runs the GDB graphical interfaceM-x gud-gdb
run GUD and GDB as a subprocessC-x C-a C-b
set breakpoint at current source lineC-c C-l
display the last source line in another windowC-c C-s
run next line ENTER functionC-c C-n
STEPOVERC-c C-i
execute a simple machine instructionC-c C-p
evaluate expression at point - can mark a regionC-c C-r
CONTINUEC-c C-d
delete breakpointC-c C-t
temp breakpointC-c >/<
up/down stackC-c C-u
CONTINUE to current lineC-c C-f
run till stack frame is doneC-x C-a C-j
jump to pointC-x k
kill the GUD session and all associated buffers
compile
runs the compile command (defaultmake -k
) in the current buffer’s directoryrecompile
reruns compile in the previous directoryC-x `
go to next error messageM-;
go to next error