GitHub - matthewbauer/bauer: An Emacs+Nix IDE
source link: https://github.com/matthewbauer/bauer
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
README.org
bauer: an Emacs+Nix IDE
This ORG-mode file generates an Emacs configuration. I am calling it an Emacs+Nix IDE. That is, the Emacs configuration is integrated with hardcoded Nix store paths. This provides a kind of functional Emacs configuration. The integration between Emacs & Nix comes with lots of useful side effects. The raw Org file can always be downloaded here. You can create pull requests & issues on the GitHub repo. You can access my website at https://matthewbauer.us.
Usage
Installing/upgrading
This is the script that I use to setup all of my new machines but it’s portable enough for anyone to use.
To install, just run this command from your shell:
curl https://matthewbauer.us/bauer/install | sh
Once it’s installed, you can open Emacs at any time with this command:
$HOME/.nix-profile/bin/run
If you don’t like it, it’s also very easy to uninstall. Just run:
nix-env -e bauer nix-collect-garbage -d
Developing
After you’ve installed it, it’s easy to make changes. By default, the
configuration lives in ~/.local/share/bauer
. To make changes just follow this
process,
cd ~/.local/share/bauer nix-build ./result/run README.org
The last line will spawn an Emacs frame in the Git repo. Anything in that file
can be change. Once you’ve made a change, just run M-x dev-restart
to rebuild
the configuration & restart Emacs. Make any changes you want to the README.org
file or any of the files in the site-lisp folder. Make sure you commit your
changes afterward by typing C-c p v
, then cc
. If you have already forked
this repo on GitHub, you can add it as a remote by typing Mg
followed by your
GitHub username within Magit. To push to it, just type Pr
then find your
username in the list & press enter. Pull requests are always welcome through
GitHub!
Without Nix
You can also use this configuration without Nix. This just gives you the Emacs configuration without any of the Nix integrations. All of the binaries will have to be provided externally. To get started, run the following:
mv ~/.emacs.d ~/.emacs.d.old git clone https://github.com/matthewbauer/bauer \ ~/.emacs.d
Emacs init file
This is the main part of the IDE. It is written in Emacs Lisp & will be loaded every time Emacs is started.
Increase GC
Increasing GC is a common way to speed up Emacs. gc-cons-threshold
sets at
what point Emacs should invoke its garbage collector Some people set it to a
really larger number permanently. This works well until the garbage is actually
collected (then you have to wait a long time). I’ve decided to just set it
temporarily to a large number so we only garbage collect once on startup. After
that we reset it to the standard value. Read @bling’s post for more info on
this.
;; -*- mode: emacs-lisp; coding: utf-8; -*- (defvar file-name-handler-alist-backup file-name-handler-alist) (setq gc-cons-threshold most-positive-fixnum file-name-handler-alist nil) (add-hook 'after-init-hook (lambda () (garbage-collect) (setq gc-cons-threshold (car (get 'gc-cons-threshold 'standard-value)) file-name-handler-alist (append file-name-handler-alist-backup file-name-handler-alist))))
Autoloads & Misc.
Setup some initial aliases for Emacs. These give us an easy way to use these functions without actually require’ing them. Ideally, Emacs should pick these up through the automatic autoloading method, but that sometimes conflicts with the compiling phases used later.
(eval-and-compile (autoload 'package-installed-p "package") (autoload 'use-package-autoload-keymap "use-package") (autoload 'pcomplete-arg "pcomplete") (autoload 'pcomplete--here "pcomplete") (autoload 'tramp-tramp-file-p "tramp") (autoload 'tramp-dissect-file-name "tramp") (defvar view-mode-map) (defvar iso-transl-ctl-x-8-map) (defvar dired-mode-map))
When we are within a terminal we want to be able to use the mouse, so
xterm-mouse-mode
is enabled here.
(when (not window-system) (xterm-mouse-mode 1))
Custom config
set-defaults provides an easy way to override the default custom files. This means that when you customize a variable it will appear as ‘standard’ even though it’s not what the package originally defined as the default. This is useful for an Emacs distribution to provide better defaults while still letting the user override them. Look through the lispdoc of the package for documentation on how this works. Eventually, this will be added to MELPA for use in other Emacs distributions.
(require 'set-defaults)
Better defaults
These are some better defaults for Emacs. They shouldn’t require any packages
to be installed to work (those go in use-package). In addition, they should take
almost no time to run (meaning they probably shouldn’t have custom init hooks).
The format of arguments to set-defaults
is identical to the one used by
custom-set-variables
.
(set-defaults '(TeX-auto-save t) '(TeX-auto-untabify t) '(TeX-electric-escape t) '(TeX-parse-self t) '(ad-redefinition-action 'accept) '(apropos-do-all t) '(async-shell-command-buffer 'new-buffer) '(auth-source-save-behavior t) '(auto-revert-check-vc-info t) '(auto-revert-verbose nil) '(auto-save-visited-file-name t) '(auto-window-vscroll nil) '(bug-reference-bug-regexp "\\(\\(?:[Ii]ssue \\|[Ff]ixe[ds] \\|[Rr]esolve[ds]? \\|[Cc]lose[ds]?\\|[Pp]\\(?:ull [Rr]equest\\|[Rr]\\) \\|(\\)#\\([0-9]+\\))?\\)") '(backward-delete-char-untabify-method 'hungry) '(backup-directory-alist `(("." . ,(expand-file-name "backup" user-emacs-directory)))) '(checkdoc-spellcheck-documentation-flag t) '(company-auto-complete (lambda () (and (company-tooltip-visible-p) (company-explicit-action-p)))) '(company-continue-commands '(not save-buffer save-some-buffers save-buffers-kill-terminal save-buffers-kill-emacs comint-previous-matching-input-from-input comint-next-matching-input-from-input completion-at-point)) '(company-require-match nil) '(company-selection-wrap-around t) '(company-backends '(company-elisp company-css company-cmake company-nxml (company-capf company-files company-keywords company-dabbrev-code) company-dabbrev)) '(comint-input-ring-size 100000) '(comint-input-ignoredups t) '(comint-process-echoes t) '(comint-prompt-read-only t) '(comint-scroll-to-bottom-on-input 'this) '(comint-password-prompt-regexp (concat "\\(^ *\\|" (regexp-opt '("Enter" "enter" "Enter same" "enter same" "Enter the" "enter the" "Enter Auth" "Old" "old" "New" "new" "'s" "login" "Kerberos" "CVS" "UNIX" " SMB" "LDAP" "PEM" "SUDO" "[sudo]" "Repeat" "Bad" "Retype") t) ;; Allow for user name to precede password equivalent (Bug#31075). " +.*\\)" "\\(?:" (regexp-opt password-word-equivalents) "\\|Response\\)" "\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?" ;; "[[:alpha:]]" used to be "for", which fails to match non-English. "\\(?: [[:alpha:]]+ .+\\)?[[:blank:]]*[::៖][[:blank:]]*\\'")) '(compilation-always-kill t) '(compilation-ask-about-save nil) '(compilation-environment '("TERM=xterm-256color")) '(compilation-skip-threshold 2) '(completion-styles '(basic partial-completion emacs22 substring)) '(completions-cycle-threshold t) '(completions-format 'vertical) '(cursor-in-non-selected-windows nil) '(custom-buffer-done-kill t) '(custom-file (expand-file-name "settings.el" user-emacs-directory)) '(custom-safe-themes t) '(custom-search-field nil) '(delete-by-moving-to-trash t) '(delete-old-versions t) '(dired-hide-details-hide-symlink-targets nil) '(dired-listing-switches "-alhv") '(dired-omit-files "^\\.\\|^#.*#$") '(dired-omit-verbose nil) '(dired-recursive-copies 'always) '(dired-recursive-deletes 'always) '(disabled-command-function nil) '(display-buffer-reuse-frames t) '(dtrt-indent-verbosity 0) '(echo-keystrokes 0) '(eshell-bad-command-tolerance 1.0e+INF) '(eshell-banner-message "") '(eshell-cmpl-autolist t) '(eshell-cmpl-cycle-completions nil) '(eshell-cmpl-cycle-cutoff-length 2) '(eshell-cmpl-ignore-case t) '(eshell-cp-overwrite-files nil) '(eshell-default-target-is-dot t) '(eshell-destroy-buffer-when-process-dies t) '(eshell-hist-ignoredups t) '(eshell-list-files-after-cd t) '(eshell-ls-dired-initial-args '("-h")) '(eshell-ls-initial-args "-h") '(eshell-review-quick-commands t) '(eshell-prompt-function (lambda () (concat (when (tramp-tramp-file-p default-directory) (concat (tramp-file-name-user (tramp-dissect-file-name default-directory)) "@" (tramp-file-name-host (tramp-dissect-file-name default-directory)) " ")) (let ((dir (eshell/pwd))) (if (string= dir (getenv "HOME")) "~" (let ((dirname (file-name-nondirectory dir))) (if (string= dirname "") "/" dirname)))) (if (= (user-uid) 0) " # " " $ ")))) '(eshell-save-history-on-exit t) '(eshell-stringify nil) '(eshell-scroll-show-maximum-output nil) '(eshell-visual-commands '("vi" "screen" "top" "less" "more" "lynx" "ncftp" "pine" "tin" "trn" "elm" "ssh" "mutt" "tmux" "htop" "fish" "alsamixer" "watch" "elinks" "links" "nethack" "vim" "zsh" "cmus" "nmtui" "nmtui-connect" "nmtui-edit" "ncdu" "telnet" "rlogin")) '(eshell-visual-options nil) '(eshell-visual-subcommands '(("nix" "build" "repl") ("vagrant" "ssh"))) '(eval-expression-print-level nil) '(find-ls-option '("-print0 | xargs -P4 -0 ls -ldN" . "-ldN")) '(find-ls-subdir-switches "-ldN") '(flycheck-display-errors-function 'flycheck-display-error-messages-unless-error-list) '(flycheck-global-modes '(not erc-mode message-mode git-commit-mode view-mode outline-mode text-mode org-mode)) '(flycheck-emacs-lisp-load-path (quote inherit)) '(flycheck-disabled-checkers '(haskell-stack-ghc)) '(flycheck-standard-error-navigation nil) '(flycheck-check-syntax-automatically '(save mode-enabled)) '(flyspell-highlight-properties nil) '(flyspell-issue-welcome-flag nil) '(flymake-no-changes-timeout nil) '(flymake-start-syntax-check-on-newline nil) '(frame-title-format '(:eval (if (buffer-file-name) (abbreviate-file-name (buffer-file-name)) "%b"))) '(haskell-process-check-cabal-config-on-load nil) '(haskell-process-auto-import-loaded-modules nil) '(haskell-process-suggest-restart nil) '(haskell-process-suggest-haskell-docs-imports nil) '(haskell-process-suggest-hoogle-imports nil) '(haskell-process-suggest-remove-import-lines nil) '(haskell-compile-cabal-build-command "cabal new-build") '(haskell-hoogle-url "https://hoogle.haskell.org/?hoogle=%s") '(haskell-tags-on-save t) '(help-window-select t) '(highlight-nonselected-windows nil) '(history-delete-duplicates t) '(ibuffer-default-display-maybe-show-predicates t) '(ibuffer-expert t) '(ibuffer-formats '((mark modified read-only " " (name 16 -1) " " (size 6 -1 :right) " " (mode 16 16) " " filename) (mark " " (name 16 -1) " " filename))) '(ibuffer-show-empty-filter-groups nil) '(ibuffer-shrink-to-minimum-size t) '(ibuffer-use-other-window t) '(ibuffer-never-show-predicates '("\\*magit-\\(diff\\|process\\):")) '(imenu-auto-rescan t) '(indicate-empty-lines t) '(inhibit-startup-echo-area-message t) '(inhibit-startup-screen t) '(initial-scratch-message "") '(initial-major-mode 'fundamental-mode) '(ispell-extra-args '("--sug-mode=ultra")) '(ispell-quietly t) '(ispell-silently-savep t) '(jit-lock-defer-time 0.25) '(js2-mode-show-parse-errors nil) '(js2-mode-show-strict-warnings nil) '(js2-strict-missing-semi-warning nil) '(kill-do-not-save-duplicates t) '(kill-whole-line t) '(load-prefer-newer t) '(mac-allow-anti-aliasing t) '(mac-command-key-is-meta t) '(mac-command-modifier 'meta) '(mac-option-key-is-meta nil) '(mac-option-modifier 'super) '(mac-right-option-modifier nil) '(magit-remote-add-set-remote\.pushDefault t) '(magit-clone-set-remote\.pushDefault t) '(magit-log-auto-more t) '(magit-no-confirm t) '(magit-process-find-password-functions '(magit-process-password-auth-source)) '(magit-process-popup-time 15) '(magit-save-repository-buffers 'dontask) '(magit-blame-disable-modes '(fci-mode view-mode yascroll-bar-mode)) '(mode-line-default-help-echo nil) '(mmm-global-mode 'buffers-with-submode-classes) '(mmm-submode-decoration-level 2) '(minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) '(next-error-recenter t) '(ns-function-modifier 'hyper) '(ns-pop-up-frames nil) '(nsm-save-host-names t) '(nxml-sexp-element-flag t) '(nxml-slash-auto-complete-flag t) '(org-confirm-babel-evaluate nil) '(org-export-with-toc nil) '(org-html-htmlize-output-type 'css) '(org-latex-listings-langs (quote ((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp") (c "C") (cc "C++") (fortran "fortran") (perl "Perl") (cperl "Perl") (python "Python") (ruby "Ruby") (html "HTML") (xml "XML") (tex "TeX") (latex "[LaTeX]TeX") (shell-script "bash") (gnuplot "Gnuplot") (ocaml "Caml") (caml "Caml") (sql "SQL") (sqlite "sql") (makefile "make") (R "r") (nix "{}") (nil "{}") (yaml "{}") (gitattributes "{}") (gitignore "{}") (shell "{}") (gitconfig "{}")))) '(org-latex-default-packages-alist (quote (("utf8" "inputenc" t ("pdflatex")) ("T1" "fontenc" t ("pdflatex")) ("" "graphicx" t nil) ("" "grffile" t nil) ("" "longtable" nil nil) ("" "wrapfig" nil nil) ("" "rotating" nil nil) ("normalem" "ulem" t nil) ("" "amsmath" t nil) ("" "textcomp" t nil) ("" "amssymb" t nil) ("" "capt-of" nil nil) ("" "hyperref" nil nil) ("" "parskip" nil nil) ("" "alltt" nil nil) ("" "upquote" nil nil) ("" "listings" nil nil)))) '(org-log-done 'time) '(org-special-ctrl-a/e t) '(org-support-shift-select t) '(package-archives '(("melpa" . "https://melpa.org/packages/") ("org" . "http://orgmode.org/elpa/") ("gnu" . "https://elpa.gnu.org/packages/"))) '(projectile-globally-ignored-files '(".DS_Store" "TAGS")) '(projectile-ignored-project-function 'file-remote-p) '(projectile-mode-line-prefix "") '(projectile-mode-line-function (lambda () (if (and (ignore-errors (projectile-project-p)) (not (file-remote-p default-directory))) (format " Projectile[%s]" (projectile-project-name)) ""))) '(projectile-switch-project-action 'projectile-dired) '(projectile-require-project-root t) '(projectile-verbose nil) '(proof-auto-action-when-deactivating-scripting 'retract) '(proof-autosend-enable nil) '(proof-electric-terminator-enable t) '(proof-fast-process-buffer nil) '(proof-script-fly-past-comments t) '(proof-shell-fiddle-frames nil) '(proof-splash-enable nil) '(proof-sticky-errors t) '(proof-tidy-response t) '(reb-re-syntax 'string) '(resize-mini-windows t) '(ring-bell-function 'ignore) '(ruby-insert-encoding-magic-comment nil) '(save-abbrevs 'silently) '(save-interprogram-paste-before-kill t) '(savehist-additional-variables '(search-ring regexp-search-ring kill-ring comint-input-ring kmacro-ring sr-history-registry file-name-history tablist-name-filter)) '(scroll-preserve-screen-position 'always) '(scroll-conservatively 101) '(sentence-end-double-space nil) '(set-mark-command-repeat-pop t) '(shell-completion-execonly nil) '(shell-input-autoexpand nil) '(sh-learn-basic-offset t) '(sp-autoskip-closing-pair 'always) '(sp-highlight-pair-overlay nil) '(tab-always-indent 'complete) '(tab-stop-list (number-sequence 4 200 4)) '(tags-add-tables t) '(tags-revert-without-query t) '(term-input-autoexpand t) '(term-input-ignoredups t) '(text-quoting-style 'quote) '(tramp-default-proxies-alist '(((regexp-quote (system-name)) nil nil) (nil "\\`root\\'" "/ssh:%h:") (".*" "\\`root\\'" "/ssh:%h:"))) '(tls-checktrust t) '(uniquify-buffer-name-style 'forward) '(uniquify-ignore-buffers-re "^\\*") '(uniquify-separator "/") '(use-dialog-box nil) '(use-file-dialog nil) '(use-package-always-defer t) '(version-control t) '(vc-allow-async-revert t) '(vc-command-messages t) '(vc-git-diff-switches '("-w" "-U3")) '(vc-follow-symlinks nil) '(vc-ignore-dir-regexp (concat "\\(\\(\\`" "\\(?:[\\/][\\/][^\\/]+[\\/]\\|/" "\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)" "\\'\\)\\|\\(\\`/[^/|:][^/|]*:\\)\\)\\|\\" "(\\`/[^/|:][^/|]*:\\)")) '(vc-make-backup-files t) '(view-read-only t) '(view-inhibit-help-message t) '(woman-imenu t) '(x-stretch-cursor t) '(which-key-lighter "") '(whitespace-action '(cleanup auto-cleanup)) '(whitespace-line-column 120) '(whitespace-style '(face trailing lines space-before-tab empty lines-style)) '(whitespace-global-modes '(not erc-mode ses-mode)) '(fortune-always-compile nil) )
Site paths
Now, pull in generated paths from site-paths.el
. Nix will generate this file
automatically for us & different Emacs variables will be set to their Nix
store derivation paths. Everything should work fine if you don’t have this
available, though. If you are in Emacs & already have the IDE installed you
can inspect this file by typing C-h C-l site-paths
. It will look similar to a
settings.el
file where each line corresponds to a customizable variable.
Unlike settings.el
, each entry is path in the Nix store & we verify it
exists before setting it.
(load "site-paths" t)
Set environment
set-envs
is provided by set-defaults. We can use it like
custom-set-variables
, just it calls setenv
instead of setq
. All of
these entries correspond to environment variables that we want to always be
set in the Emacs process.
(set-envs '("EDITOR" "emacsclient") '("NODE_NO_READLINE" "1") '("PAGER" "cat") '("PS1" "\\W > ") )
Fix broken Git on Windows.
(when (eq window-system 'w32) (setenv "GIT_ASKPASS" "git-gui--askpass"))
Load custom file
This file allows users to override the above defaults. This will mean you can use custom as you normally would in vanilla Emacs.
(load custom-file t)
Setup use-package
use-package is an Emacs package by John Weigley allowing users to easily configure other Emacs packages. It’s quite useful & it will be used extensively in this project.
Now to get use-package
we will require package.el
& initialize it if
site-paths is not setup (meaning we’re outside the Nix expression). Because
site-paths should be available (unless you don’t have Nix), we can skip this
step. All of this is marked ‘eval-and-compile’ to make sure the compiler picks
it up on build phase.
So, there are basically two modes for using this configuration. One when packages are installed externally (through Nix) & another where they are installed internally. This is captured in the variable ‘needs-package-init’ which will be t when we want to use the builtin package.el & will be nil when we want to just assume everything is available.
(eval-and-compile (setq needs-package-init (and (not (locate-library "site-paths")) (not (and (boundp 'use-package-list--is-running) use-package-list--is-running)))))
First handle using package.el
. We will do all of the work of bootstrapping
here including running package-initialize
, ensuring use-package
, & delight
are installed.
(when needs-package-init (require 'package) (package-initialize) (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (unless (package-installed-p 'delight) (package-refresh-contents) (package-install 'delight)))
Actually require use-package
,
(eval-and-compile (require 'delight) (require 'bind-key) (require 'use-package))
Now let’s handle the case where all of the packages are already provided. Basically, we’ll prevent use-package from running ‘ensure’ on anything.
(eval-and-compile (setq use-package-always-ensure needs-package-init) (when (not needs-package-init) (setq use-package-ensure-function 'ignore package-enable-at-startup nil package--init-file-ensured t)))
Key bindings
Using bind-key, setup some simple key bindings. None of these should overwrite
Emacs’ default keybindings. Also, they should only require vanilla Emacs to work
(non-vanilla Emacs key bindings should be put in their use-package
declaration). These are meant to all be as close to vanilla Emacs as possible. I
try to avoid extremely specific key binds here.
What is overwritten can be seen with M-x describe-personal-keybindings
. The
goal is to overwrite as little as possible. When it is necessary to overwrite
Emacs keybinds, documentation on why should be provided.
First we include a library that provides some nice helper functions that will be used as key bindings.
(require 'bauer)
Now we will call bind-keys
. We give it keys to bind & what function to run
when those keys are pressed. Note on syntax of bind-keys: if you are unfamiliar
with how Emacs key binding works, you should read through this article.
(require 'files) (when (fboundp 'ns-drag-n-drop-as-text) (global-set-key [M-s-drag-n-drop] 'ns-drag-n-drop-as-text)) (bind-keys ("C-c C-u" . rename-uniquely) ("C-x ~" . (lambda () (interactive) (find-file "~"))) ("C-x /" . (lambda () (interactive) (find-file "/"))) ("C-x 4 C-x ~" . (lambda () (interactive) (find-file-other-window "~"))) ("C-x 4 C-x /" . (lambda () (interactive) (find-file-other-window "/"))) ("C-c C-o" . browse-url-at-point) ("H-l" . browse-url-at-point) ("C-x 5 3" . iconify-frame) ("C-x 5 4" . toggle-frame-fullscreen) ("s-SPC" . cycle-spacing) ("C-c w w" . whitespace-mode) ("<C-return>" . other-window) ("<C-M-return>" . other-window) ("s-o" . other-window) ("C-z" . delete-other-windows) ("M-g l" . goto-line) ("<C-M-backspace>" . backward-kill-sexp) ("C-x t" . toggle-truncate-lines) ("C-x v H" . vc-region-history) ("C-c SPC" . just-one-space) ("C-c f" . flush-lines) ("C-c o" . customize-option) ("C-c O" . customize-group) ("C-c F" . customize-face) ("C-c q" . fill-region) ("C-c s" . replace-string) ("C-c u" . rename-uniquely) ("C-c z" . clean-buffer-list) ("C-c =" . count-matches) ("C-c ;" . comment-or-uncomment-region) ("M-+" . text-scale-increase) ("M-_" . text-scale-decrease) ("H-c" . compile) ("s-c" . compile) ("s-r" . revert-buffer) ("s-1" . other-frame) ("<s-return>" . toggle-frame-fullscreen) ("s-C-<left>" . enlarge-window-horizontally) ("s-C-<right>" . shrink-window-horizontally) ("s-C-<down>" . shrink-window) ("s-C-<up>" . enlarge-window) ("<S-s-up>" . shrink-window) ("<S-s-down>" . enlarge-window) ("<s-down>" . windmove-down) ("<s-up>" . windmove-up) ("<s-left>" . windmove-left) ("<s-right>" . windmove-right) ("C-c [" . align-regexp) ("M-s d" . find-grep-dired) ("M-s F" . find-grep) ("M-s G" . grep) ("s-/" . comment-or-uncomment-region) ("C-x M-p" . (lambda () (interactive) (save-excursion (other-window 1) (quit-window)))) ("C-M--" . (lambda () (interactive) (update-font-size -1 t))) ("C-M-=" . (lambda () (interactive) (update-font-size 1 t))) ("C-M-0" . (lambda () (interactive) (update-font-size 12 nil))) ("M-n" . next-error) ("M-p" . previous-error) ("C-c m b" . eval-buffer) ("C-c m e" . eval-last-sexp) ("C-c m i" . eval-expression) ("C-c m d" . eval-defun) ("C-c m n" . eval-print-last-sexp) ("C-c m r" . eval-region) ("C-x r q" . save-buffers-kill-terminal) ("C-c C-<return>" . delete-blank-lines) ("C-<f10>" . menu-bar-mode) ("C-x M-g" . browse-url-at-point) ("C-s" . isearch-forward-regexp) ("C-r" . isearch-backward-regexp) ("C-S-s" . isearch-forward) ("C-S-r" . isearch-backward) ("M-s l" . sort-lines) ("M-s m" . multi-occur) ("M-s M" . multi-occur-in-matching-buffers) ("M-s f" . find-name-dired) ("C-c i i" . imenu) ("C-c I" . bauer-find-config)) (bind-keys :map help-map ("C-r" . woman)) (bind-keys :package view :map view-mode-map ("n" . next-line) ("p" . previous-line) ("j" . next-line) ("k" . previous-line) ("l" . forward-char) ("f" . forward-char) ("b" . backward-char) ("e" . end-of-line) ("a" . beginning-of-line)) (bind-keys :package iso-transl :map iso-transl-ctl-x-8-map ("' /" . "′") ("\" /" . "″") ("\" (" . "“") ("\" )" . "”") ("' (" . "‘" ) ("' )" . "’" ) ("4 < -" . "←") ("4 - >" . "→") ("4 b" . "←") ("4 f" . "→") ("4 p" . "↑") ("4 n" . "↓") ("<down>" . "⇓") ("<S-down>" . "↓") ("<left>" . "⇐") ("<S-left>" . "←") ("<right>" . "⇒") ("<S-right>" . "→") ("<up>" . "⇑") ("<S-up>" . "↑") ("," . "…")) (bind-keys :prefix-map bauer-git :prefix "s-g" ("l" . magit-clone) :prefix-map bauer-help :prefix "s-h" ("k" . describe-personal-keybindings) ("p" . ffap) ("m" . man) ("w" . woman)) (unless window-system (global-set-key (kbd "<mouse-4>") 'scroll-down-line) (global-set-key (kbd "<mouse-5>") 'scroll-up-line)) (when (eq window-system 'mac) (defun mac-fullscreen () (interactive) (let ((fullscreen (frame-parameter nil 'fullscreen))) (if (memq fullscreen '(fullscreen fullboth)) (let ((fullscreen-restore (frame-parameter nil 'fullscreen-restore))) (if (memq fullscreen-restore '(maximized fullheight fullwidth)) (set-frame-parameter nil 'fullscreen fullscreen-restore) (set-frame-parameter nil 'fullscreen nil))) (modify-frame-parameters nil `((fullscreen . fullscreen) (fullscreen-restore . ,fullscreen)))))) (bind-key "C-x 5 4" 'mac-fullscreen))
Setup installer
Installer provides installation & upgrading functionality. You can upgrade the
IDE at any time by typing M-x upgrade
from within Emacs. You may have to
restart Emacs for the upgrade to take place. See installer.el for documentation.
(require 'installer nil t)
Packages
Each of these entries are use-package
calls that will both install & load
the package for us. The most important are listed first in “Essentials”.
“Built-in” Emacs packages are also configured. Next comes the “Programming
Language” modes. Finally, we list some miscellaneous modes.
This is an alphabetized listing of all Emacs packages needed by the IDE. To
resort, go to one of the package group headings & type C-c ^ a
.
Essentials
These are the best & most useful modes available to us in Emacs world.
align
(use-package align :bind ("M-[" . align) :ensure nil :config (add-to-list 'align-rules-list '(haskell-types (regexp . "\\(\\s-+\\)\\(::\\|∷\\)\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) (add-to-list 'align-rules-list '(haskell-assignment (regexp . "\\(\\s-+\\)=\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) (add-to-list 'align-rules-list '(haskell-arrows (regexp . "\\(\\s-+\\)\\(->\\|→\\)\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) (add-to-list 'align-rules-list '(haskell-left-arrows (regexp . "\\(\\s-+\\)\\(<-\\|←\\)\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) )
aggressive-indent
Automatically indent code as you type. Only enabled for Lisp currently.
(use-package aggressive-indent :hook ((emacs-lisp-mode inferior-emacs-lisp-mode ielm-mode lisp-mode inferior-lisp-mode isp-interaction-mode slime-repl-mode) . aggressive-indent-mode))
Apropospriate Theme
This is the theme I use & it works well for this configuration. It is dark with high contrast. We will only enable it when we are running with GUI Emacs.
(use-package apropospriate-theme :if window-system :init (add-to-list 'custom-theme-load-path (file-name-directory (locate-library "apropospriate-theme"))) (load-theme 'apropospriate-dark t))
While apropospriate is the default, other themes can be used as well! For instance spacemacs-theme can be enabled:
(use-package spacemacs-common :ensure spacemacs-theme :if window-system :init (add-to-list 'custom-theme-load-path (file-name-directory (locate-library "spacemacs-theme-pkg"))) (load-theme 'spacemacs-dark t))
Company
Company provides completions in Emacs. Activate them by pressing C-M-i
.
(use-package company :commands global-company-mode :delight :demand :preface (load "company-autoloads" t t) (defun company-complete-common-or-cycle-backward () "Complete common prefix or cycle backward." (interactive) (company-complete-common-or-cycle -1)) :bind (:map company-mode-map ("C-M-i" . company-complete-common-or-cycle) :map company-active-map ("RET" . company-complete-selection) ([return] . company-complete-selection) ("C-j" . company-complete-selection) ("TAB" . company-complete-common-or-cycle) ("<tab>" . company-complete-common-or-cycle) ("S-TAB" . company-complete-common-or-cycle-backward) ("<backtab>" . company-complete-common-or-cycle-backward) ("C-n" . company-select-next) ("C-p" . company-select-previous) ("C-/" . company-search-candidates) ("C-M-/" . company-filter-candidates) ("C-d" . company-show-doc-buffer) ) :hook (;; (minibuffer-setup . company-mode) ;; (minibuffer-setup . (lambda () ;; (setq-local company-frontends '(company-preview-if-just-one-frontend)) ;; (setq-local company-auto-complete nil))) (after-init . global-company-mode) (shell-mode . (lambda () (setq-local company-backends '(company-capf)))) (eshell-mode . (lambda () (setq-local company-backends '(company-files))))) :config (advice-add 'completion-at-point :around (lambda (old-function &rest args) (if company-mode (apply 'company-complete-common-or-cycle args) (apply old-function args)))) (global-company-mode))
company-irony
(use-package company-irony :commands company-irony :hook (irony-mode . (lambda () (setq-local company-backends '(company-irony company-capf)))))
company-restclient
(use-package company-restclient :commands company-restclient :hook (restclient-mode . (lambda () (setq-local company-backends '(company-restclient company-capf)))))
company-anaconda
(use-package company-anaconda :commands company-anaconda :hook (anaconda-mode . (lambda () (setq-local company-backends '((company-anaconda company-capf))))))
company-tern
(use-package company-tern :commands company-tern :hook (tern-mode . (lambda () (setq-local company-backends '(company-tern company-capf)))))
company-auctex
(use-package company-auctex :commands (company-auctex company-auctext-labels company-auctest-bibs company-auctex-macros company-auctext-symbols company-auctext-environments) :hook (tex-mode . (lambda () (setq-local company-backends '((company-auctex-labels company-auctex-bibs company-auctex-macros company-auctex-environments company-auctex-symbols company-capf))))))
company-web
(use-package company-web :preface (autoload 'company-web-html "company-web-html") (autoload 'company-web-jade "company-web-jade") (autoload 'company-web-slim "company-web-slim") :hook ((web-mode . (lambda () (setq-local company-backends '(company-web-html company-web-jade company-web-slim company-capf))))))
company-math
(use-package company-math :preface (autoload 'company-math-symbols-latex "company-math") (autoload 'company-latex-commands "company-math") :hook (TeX-mode . (lambda () (setq-local company-backends '((company-math-symbols-latex company-latex-commands company-capf))))))
Counsel
Counsel provides a better selection experience to the default Emacs.
Counsel is only enabled on non-Windows systems. This is due to an issue in counsel-find-file, see https://github.com/abo-abo/swiper/issues/773 for more info.
(use-package counsel :disabled :commands (counsel-mode counsel-descbinds counsel-grep-or-swiper) ;; counsel doesn’t work well with windows drives ;; see https://github.com/abo-abo/swiper/issues/773 ;; :if (not (string= system-type "windows-nt")) :bind* (([remap execute-extended-command] . counsel-M-x) ([remap find-library] . counsel-find-library) ([remap describe-bindings] . counsel-descbinds) ([remap describe-face] . counsel-describe-faces) ([remap list-faces-display] . counsel-faces) ([remap imenu] . counsel-imenu) ([remap load-library] . counsel-load-library) ([remap load-theme] . counsel-load-theme) ([remap yank-pop] . counsel-yank-pop) ([remap info-lookup-symbol] . counsel-info-lookup-symbol) ([remap pop-to-mark-command] . counsel-mark-ring) ([remap bookmark-jump] . counsel-bookmark) ("C-c j" . counsel-git-grep) ("C-x l" . counsel-locate) ("M-y" . counsel-yank-pop) ("C-c i 8" . counsel-unicode-char) ("C-x M-f" . counsel-find-file) :map help-map ("C-v" . counsel-find-symbol) ("C-k" . counsel-find-function-on-key) ("C-l" . counsel-find-library) ))
ivy
(use-package ivy :commands (ivy-read) :bind (([remap list-buffers] . ivy-switch-buffer) ([remap switch-to-buffer] . ivy-switch-buffer) ([remap switch-to-buffer-other-window] . ivy-switch-buffer-other-window) :package ivy :map ivy-minibuffer-map ("<escape>" . abort-recursive-edit)) :init (defvar projectile-completion-system) (defvar magit-completing-read-function) (defvar projector-completion-system) (setq projectile-completion-system 'ivy magit-completing-read-function 'ivy-completing-read) :commands (ivy-completing-read ivy-completion-in-region swiper))
diff-hl
This mode provides indicators at the right fringe of the Emacs buffer. These indications show where a file has been edited from the last Git commit.
(use-package diff-hl :disabled :bind (:package diff-hl :map diff-hl-mode-map ("<left-fringe> <mouse-1>" . diff-hl-diff-goto-hunk)) :hook ((prog-mode . diff-hl-mode) (vc-dir-mode . diff-hl-mode) (dired-mode . diff-hl-dir-mode) (magit-post-refresh . diff-hl-magit-post-refresh) (org-mode . diff-hl-mode)))
dtrt-indent
This mode will try to
(use-package dtrt-indent :delight :hook (prog-mode . dtrt-indent-mode))
Emacs shell
Emacs shell provides . Run eshell by typing C-c e
or M-x eshell
.
(use-package eshell :ensure nil :bind (("C-c M-t" . eshell) ("C-c x" . eshell) ("C-c e" . eshell)) :hook (;; (eshell-first-time-mode-hook . eshell-read-history) (eshell-first-time-mode-hook . (lambda () (add-hook 'eshell-expand-input-functions 'eshell-spawn-external-command)))) :preface (defvar eshell-isearch-map (let ((map (copy-keymap isearch-mode-map))) (define-key map [(control ?m)] 'eshell-isearch-return) (define-key map [return] 'eshell-isearch-return) (define-key map [(control ?r)] 'eshell-isearch-repeat-backward) (define-key map [(control ?s)] 'eshell-isearch-repeat-forward) (define-key map [(control ?g)] 'eshell-isearch-abort) (define-key map [backspace] 'eshell-isearch-delete-char) (define-key map [delete] 'eshell-isearch-delete-char) map) "Keymap used in isearch in Eshell.") (defalias 'eshell/q 'eshell/exit) (defalias 'eshell/\? 'help) (defun eshell-spawn-external-command (beg end) "Parse and expand any history references in current input." (save-excursion (goto-char end) (when (looking-back "&!" beg) (delete-region (match-beginning 0) (match-end 0)) (goto-char beg) (insert "spawn ")))))
em-rebind
(use-package em-rebind :ensure nil :demand :config ;; TODO: move this back to customize (setq eshell-rebind-keys-alist '(([(control 97)] . eshell-bol) ([home] . eshell-bol) ([(control 100)] . eshell-delchar-or-maybe-eof) ([backspace] . eshell-delete-backward-char) ([delete] . eshell-delete-backward-char) ([(control 119)] . backward-kill-word) ([(control 117)] . eshell-kill-input) ([tab] . completion-at-point) ([(control 101)] . (lambda () (interactive) (end-of-line))))) ;; TODO: move this back to customize (setq eshell-modules-list '(eshell-alias eshell-basic eshell-cmpl eshell-dirs eshell-glob eshell-hist eshell-ls eshell-pred eshell-prompt eshell-rebind eshell-script eshell-term eshell-tramp eshell-unix eshell-xtra )))
esh-help
(use-package esh-help :preface (autoload 'esh-help-eldoc-command "esh-help") (defun esh-help-turn-on () (interactive) (setq-local eldoc-documentation-function 'esh-help-eldoc-command) (setq eldoc-documentation-function 'esh-help-eldoc-command) (eldoc-mode 1)) :hook (eshell-mode . esh-help-turn-on))
em-dired
(use-package em-dired :preface (autoload 'em-dired-new "em-dired") :ensure nil :bind (:package dired :map dired-mode-map ("e" . em-dired)) :hook (eshell-mode . em-dired-mode) :init (advice-add 'eshell :before 'em-dired-new))
Flycheck
Flycheck will annotate code with errors from the compiler or interpreter. It supports many languages and give us a lot of features right out of the box.
(use-package flycheck :hook (prog-mode . flycheck-mode)) (use-package flycheck-haskell :hook (haskell-mode . flycheck-haskell-setup)) (use-package flycheck-cask :hook (emacs-lisp-mode . flycheck-cask-setup)) (use-package flycheck-rust :hook (rust-mode . flycheck-rust-setup))
Gnus
Gnus is an infamous email client & news reader.
(use-package gnus :ensure nil :commands gnus :hook ((dired-mode . turn-on-gnus-dired-mode)))
God Mode
God Mode makes it easier to type Emacs shortcuts involving lots of modifier keys. Activate it by pressing Escape (Notice “God” at the bottom of the screen). You no longer have to press & hold the control key!
Note that god-mode overwrites escape key. This can cause some issues for certain Emacs keybinds.
(use-package god-mode :bind (("<escape>" . god-local-mode) ;; ("ESC" . god-local-mode) ))
helpful
(use-package helpful :if (>= emacs-major-version 25) :bind (([remap describe-function] . helpful-callable) ([remap describe-variable] . helpful-variable) ([remap describe-key] . helpful-key) ("H-h" . helpful-at-point)))
Hippie Expand
Hippie provides dynamic expansions. Try it out by pressing M-/
.
(use-package hippie-exp :ensure nil :bind* (("M-/" . hippie-expand) ("s-?" . hippie-expand-line)) :hook ((emacs-lisp-mode ielm-mode) . (lambda () (setq-local hippie-expand-try-functions-list (append '(try-complete-lisp-symbol-partially try-complete-lisp-symbol) hippie-expand-try-functions-list)))))
Magit
Magit is a Git porcelain for Emacs. All of the features from the Git command line are available in an intuitive Emacs buffer.
(use-package magit :preface (autoload 'magit-toplevel "magit") (autoload 'magit-read-string-ns "magit") (autoload 'magit-get "magit") ;; (autoload 'magit-define-popup-action "magit") (autoload 'magit-remote-arguments "magit") (defun magit-dired-other-window () (interactive) (dired-other-window (magit-toplevel))) ;; (defun magit-remote-github (username &optional args) ;; (interactive (list (magit-read-string-ns "User name") ;; (magit-remote-arguments))) ;; (let* ((url (magit-get "remote.origin.url")) ;; (match (string-match ;; "^\\(?:https?://github\.com/\\|[email protected]:\\|ssh://git@github\.com/\\)[^/]*/\\(.*\\)" ;; url))) ;; (unless match ;; (error "Not a github remote")) ;; (let ((repo (match-string 1 url))) ;; (apply 'magit-remote-add username ;; (format "ssh://[email protected]/%s/%s" ;; username repo) args)))) ;; :hook (magit-mode . (lambda () ;; (magit-define-popup-action ;; 'magit-remote-popup ;; ?g ;; "Add remote from github user name" ;; 'magit-remote-github))) :commands (magit-clone magit-blame-addition) :if (locate-file "git" exec-path) :bind (("C-x g" . magit-status) ("C-x G" . magit-dispatch) :package magit :map magit-mode-map ("C-o" . magit-dired-other-window)))
Magit forge.
(use-package forge
:after magit)
git-commit
(use-package git-commit :hook ((git-commit-mode . flyspell-mode) (git-commit-mode . git-commit-save-message) (git-commit-mode . turn-on-auto-fill)))
MMM Mode
MMM mode lets you edit multiple languages within one buffer.
(use-package mmm-mode :commands mmm-mode :config (use-package mmm-auto :ensure nil))
multiple-cursors
Multiple cursors give you more cursors. It is bound to C->
& C-<
.
(use-package multiple-cursors :bind (("<C-S-down>" . mc/mark-next-like-this) ("<C-S-up>" . mc/mark-previous-like-this) ("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("M-<mouse-1>" . mc/add-cursor-on-click) ("C-c C-<" . mc/mark-all-like-this) ("C-!" . mc/mark-next-symbol-like-this) ("C-S-c C-S-c" . mc/edit-lines)))
Org
Org mode is an impressive suite of text editing solutions. It gives you an outliner but also much much more.
(use-package org :ensure org-plus-contrib :hook ((org-mode . (lambda () (add-hook 'completion-at-point-functions 'pcomplete-completions-at-point nil t))) (org-mode . auto-fill-mode) (org-mode . (lambda () (setq-local scroll-margin 3))) (message-mode . turn-on-orgtbl) (org-mode . (lambda () (autoload 'org-eldoc-documentation-function "org-eldoc") (setq-local eldoc-documentation-function 'org-eldoc-documentation-function)))) :bind* (("C-c c" . org-capture) ("C-c a" . org-agenda) ("C-c l" . org-store-link) ("C-c b" . org-iswitchb)) :config (use-package ob-dot :ensure nil :demand) (use-package ox-latex :ensure nil :demand) (use-package ox-beamer :ensure nil :demand) (use-package ox-md :ensure nil :demand)) (use-package org-download :hook (dired-mode . org-download-enable)) (use-package org-present :commands org-present)
Projectile
Setup projectile & link it with some other packages. This also adds an easymenu to make the “Projectile” modeline clickable.
(use-package projectile :commands projectile-mode :bind-keymap* (("C-c p" . projectile-command-map) ("s-p" . projectile-command-map)) :bind (("C-c C-f" . projectile-find-file)) :preface (autoload 'projectile-project-vcs "projectile") (autoload 'projectile-project-root "projectile") (autoload 'easy-menu-define "easymenu" "" nil 'macro) :demand :config (projectile-mode))
Recentf
(use-package recentf :disabled :ensure nil :config (recentf-mode 1))
smart-hungry-delete
Smart hungry delete automatically delete lots of whitespace in a row.
(use-package smart-hungry-delete :if (>= emacs-major-version 25) :bind (:map prog-mode-map ("<backspace>" . smart-hungry-delete-backward-char) ("C-d" . smart-hungry-delete-forward-char)) :hook ((prog-mode . smart-hungry-delete-default-prog-mode-hook) (c-mode-common . smart-hungry-delete-default-c-mode-common-hook) (python-mode . smart-hungry-delete-default-c-mode-common-hook) (text-mode . smart-hungry-delete-default-text-mode-hook)))
Smartparens
Smartparens is helpful in closing parenthesis when editing Lisp code.
(use-package smartparens :preface (autoload 'sp-local-pair "smartparens") (autoload 'sp-local-tag "smartparens") :hook (((emacs-lisp-mode inferior-emacs-lisp-mode ielm-mode lisp-mode inferior-lisp-mode lisp-interaction-mode slime-repl-mode eval-expression-minibuffer-setup) . smartparens-strict-mode) ((emacs-lisp-mode inferior-emacs-lisp-mode ielm-mode lisp-mode inferior-lisp-mode lisp-interaction-mode slime-repl-mode org-mode) . show-smartparens-mode) ((web-mode html-mode) . smartparens-mode)) :bind (:map smartparens-mode-map ("C-M-f" . sp-forward-sexp) ;; navigation ("C-M-b" . sp-backward-sexp) ("C-M-u" . sp-backward-up-sexp) ("C-M-d" . sp-down-sexp) ("C-M-p" . sp-backward-down-sexp) ("C-M-n" . sp-up-sexp) ("M-s" . sp-splice-sexp) ;; depth-changing commands ("M-<up>" . sp-splice-sexp-killing-backward) ("M-<down>" . sp-splice-sexp-killing-forward) ("M-r" . sp-splice-sexp-killing-around) ("M-(" . sp-wrap-round) ("C-)" . sp-forward-slurp-sexp) ;; barf/slurp ("C-<right>" . sp-forward-slurp-sexp) ("C-}" . sp-forward-barf-sexp) ("C-<left>" . sp-forward-barf-sexp) ("C-(" . sp-backward-slurp-sexp) ("C-M-<left>" . sp-backward-slurp-sexp) ("C-{" . sp-backward-barf-sexp) ("C-M-<right>" . sp-backward-barf-sexp) ("M-S" . sp-split-sexp) ;; misc ("M-j" . sp-join-sexp)) :config (autoload 'sp-with-modes "smartparens" "" nil 'macro) (use-package smartparens-config :ensure nil :demand) (sp-with-modes 'org-mode (sp-local-pair "*" "*" :actions '(insert wrap) :unless '(sp-point-after-word-p sp-point-at-bol-p) :wrap "C-*" :skip-match 'sp--org-skip-asterisk) (sp-local-pair "_" "_" :unless '(sp-point-after-word-p) :wrap "C-_") (sp-local-pair "/" "/" :unless '(sp-point-after-word-p) :post-handlers '(("[d1]" "SPC"))) (sp-local-pair "~" "~" :unless '(sp-point-after-word-p) :post-handlers '(("[d1]" "SPC"))) (sp-local-pair "=" "=" :unless '(sp-point-after-word-p) :post-handlers '(("[d1]" "SPC"))) (sp-local-pair "«" "»")) (sp-with-modes '(java-mode c++-mode) (sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET"))) (sp-local-pair "/*" "*/" :post-handlers '((" | " "SPC") ("* ||\n[i]" "RET")))) (sp-with-modes '(markdown-mode gfm-mode rst-mode) (sp-local-pair "*" "*" :bind "C-*") (sp-local-tag "2" "**" "**") (sp-local-tag "s" "```scheme" "```") (sp-local-tag "<" "<_>" "</_>" :transform 'sp-match-sgml-tags)) (sp-local-pair 'emacs-lisp-mode "`" nil :when '(sp-in-string-p)) (sp-local-pair 'clojure-mode "`" "`" :when '(sp-in-string-p)) (sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil) (sp-with-modes 'nix-mode (sp-local-pair "'" "'" :unless '(sp-in-comment-p sp-in-string-quotes-p)) (sp-local-pair "\"" "\"") (sp-local-pair "''" "''" :unless '(sp-in-comment-p sp-in-string-quotes-p))))
sudo-edit
Sudo-edit lets you open a file using sudo (it actually goes through TRAMP to achieve this).
(use-package sudo-edit :bind (("C-c C-r" . sudo-edit)))
try
(use-package try
:commands try)
which-key
Which-key will tell you what key bindings are available give a prefix. Test it
out by pressing C-x
& waiting a few seconds. Each key listed is bound to a
function.
(use-package which-key :demand :commands which-key-mode :config (which-key-mode 1))
Built-ins
These are available automatically, so these use-package
blocks just
configure them.
ansi-color
Get color/ansi codes in compilation mode.
(use-package ansi-color :ensure nil :hook (compilation-filter . colorize-compilation-buffer) :preface (autoload 'ansi-color-apply-on-region "ansi-color") (defun colorize-compilation-buffer () (let ((inhibit-read-only t)) (ansi-color-apply-on-region (point-min) (point-max)))))
autorevert
Autorevert mode makes files update when they have changed on disk. Unfortunately this can have some issues in cases where Emacs uses the wrong file. Need to investigate how to fix this.
(use-package autorevert :ensure nil :commands global-auto-revert-mode :demand :config (global-auto-revert-mode t))
bug-reference
Provides links to bugs listed in sourvce code.
(use-package bug-reference :ensure nil :hook ((prog-mode . bug-reference-prog-mode) (text-mode . bug-reference-mode)))
comint
Base mode used for shell and terminal modes.
(defvar comint-input-ring-prefix ": [[:digit:]]+:[[:digit:]]+;" "Possible prefix that may come before history elements. In Zshell with extended_history, this is useful.") (use-package comint :ensure nil :preface (autoload 'comint-write-input-ring "comint") (autoload 'comint-read-input-ring "comint") (autoload 'comint-send-invisible "comint") (defun turn-on-comint-history (history-file) (setq comint-input-ring-file-name history-file) (comint-read-input-ring 'silent)) (defun save-history () (dolist (buffer (buffer-list)) (with-current-buffer buffer (comint-write-input-ring)))) :config (advice-add 'comint-read-input-ring :override (lambda (&optional silent) (cond ((or (null comint-input-ring-file-name) (equal comint-input-ring-file-name "")) nil) ((not (file-readable-p comint-input-ring-file-name)) (or silent (message "Cannot read history file %s" comint-input-ring-file-name))) (t (let* ((file comint-input-ring-file-name) (count 0) ;; Some users set HISTSIZE or `comint-input-ring-size' ;; to huge numbers. Don't allocate a huge ring right ;; away; there might not be that much history. (ring-size (min 1500 comint-input-ring-size)) (ring (make-ring ring-size))) (with-temp-buffer (insert-file-contents file) ;; Save restriction in case file is already visited... ;; Watch for those date stamps in history files! (goto-char (point-max)) (let (start end history) (while (and (< count comint-input-ring-size) (re-search-backward comint-input-ring-separator nil t) (setq end (match-beginning 0))) (setq start (if (re-search-backward comint-input-ring-separator nil t) (progn (when (looking-at (concat comint-input-ring-separator comint-input-ring-prefix)) ;; Skip zsh extended_history stamps (re-search-forward comint-input-ring-prefix nil t)) (match-end 0)) (progn (goto-char (point-min)) (if (looking-at comint-input-ring-prefix) (progn (re-search-forward comint-input-ring-prefix nil t) (match-end 0)) (point-min))))) (setq history (buffer-substring start end)) (goto-char start) (when (and (not (string-match comint-input-history-ignore history)) (or (null comint-input-ignoredups) (ring-empty-p ring) (not (string-equal (ring-ref ring 0) history)))) (when (= count ring-size) (ring-extend ring (min (- comint-input-ring-size ring-size) ring-size)) (setq ring-size (ring-size ring))) (ring-insert-at-beginning ring history) (setq count (1+ count)))))) (setq comint-input-ring ring comint-input-ring-index nil)))))))
compile
(use-package compile :ensure nil :bind (("C-c C-c" . compile) :map compilation-mode-map ("o" . compile-goto-error)) :preface (autoload 'ansi-color-process-output "ansi-color") (defun show-compilation () (interactive) (let ((compile-buf (catch 'found (dolist (buf (buffer-list)) (if (string-match "\\*compilation\\*" (buffer-name buf)) (throw 'found buf)))))) (if compile-buf (switch-to-buffer-other-window compile-buf) (call-interactively 'compile)))) (defun compilation-ansi-color-process-output () (ansi-color-process-output nil) (set (make-local-variable 'comint-last-output-start) (point-marker))) :hook (compilation-filter . compilation-ansi-color-process-output))
delsel
(use-package delsel :ensure nil :demand :commands delete-selection-mode :config (delete-selection-mode t))
dired
(use-package dired :ensure nil :preface (autoload 'dired-get-filename "dired") (autoload 'term-set-escape-char "term") (defun dired-run-command (&optional filename) "Run file at point in a new buffer." (interactive) (unless filename (setq filename (expand-file-name (dired-get-filename t t) default-directory))) (let ((buffer (make-term (file-name-nondirectory filename) filename)) (buffer-read-only nil)) (with-current-buffer buffer ;; (term-mode) (term-char-mode) (term-set-escape-char ?\C-x)) (set-process-sentinel (get-buffer-process buffer) (lambda (proc event) (when (not (process-live-p proc)) (kill-buffer (process-buffer proc))))) (switch-to-buffer buffer))) :bind (("C-c J" . dired-double-jump) :package dired :map dired-mode-map ("C-c C-c" . compile) ("r" . term) ("M-@" . shell) ("M-*" . eshell) ("W" . browse-url-of-dired-file) ("@" . dired-run-command))) (use-package dired-du :commands dired-du-mode)
dired-column
(use-package dired-column :ensure nil :bind (:package dired :map dired-mode-map ("o" . dired-column-find-file)))
dired-subtree
(use-package dired-subtree :bind (:package dired :map dired-mode-map ("<tab>" . dired-subtree-toggle) ("TAB" . dired-subtree-toggle) ("<backtab>" . dired-subtree-cycle)))
dired-x
(use-package dired-x :ensure nil :hook ((dired-mode . dired-omit-mode) (dired-mode . dired-hide-details-mode)) :bind (("s-\\" . dired-jump-other-window) :package dired :map dired-mode-map (")" . dired-omit-mode)))
eldoc
Provides some info for the thing at the point.
(use-package eldoc :ensure nil :hook ((emacs-lisp-mode . eldoc-mode) (eval-expression-minibuffer-setup . eldoc-mode) (lisp-mode-interactive-mode . eldoc-mode) (typescript-mode . eldoc-mode) (haskell-mode . eldoc-mode) (python-mode . eldoc-mode) (eshell-mode . eldoc-mode) (org-mode . eldoc-mode)))
electric
Setup these modes:
- electric-quote
- electric-indent
- electric-layout
(use-package electric :ensure nil :if (>= emacs-major-version 25) :hook ((prog-mode . electric-quote-local-mode) (text-mode . electric-quote-local-mode) (org-mode . electric-quote-local-mode) (message-mode . electric-quote-local-mode) (prog-mode . electric-indent-local-mode) (prog-mode . electric-layout-mode) (haskell-mode . (lambda () (electric-indent-local-mode -1))) (nix-mode . (lambda () (electric-indent-local-mode -1)))))
elec-pair
Setup electric-pair-mode for prog-modes. Also disable it when smartparens is setup.
(use-package elec-pair :ensure nil :if (>= emacs-major-version 25) :hook ((prog-mode . electric-pair-local-mode) (smartparens-mode . (lambda () (electric-pair-local-mode -1)))))
eww
eww is enabled so we can open files in non-graphical environments.
(use-package eww :ensure nil :if (and (not window-system) (not (string-equal (getenv "TERM_PROGRAM") "Apple_Terminal"))) :commands (eww-browse-url eww-reload) :config (add-hook 'eww-mode-hook (lambda () (add-hook 'text-scale-mode-hook (lambda (&rest _) (eww-reload t)) nil t) (add-hook 'window-size-change-functions (lambda (&rest _) (eww-reload t)) nil t))) :init (setq browse-url-browser-function 'eww-browse-url))
executable
Make scripts executable automatically.
(use-package executable :ensure nil :hook ((after-save . executable-make-buffer-file-executable-if-script-p)))
ffap
(use-package ffap :bind (("C-x C-f" . find-file-at-point) ("C-x 4 C-f" . ffap-other-window) ("C-x C-r" . ffap-read-only) ("C-x C-v" . ffap-alternate-file) ("C-x 4 f" . ffap-other-window) ("C-x 5 f" . ffap-other-frame) ("C-x 4 r" . ffap-read-only-other-window) ("C-x 5 r" . ffap-read-only-other-frame) ("C-x d" . dired-at-point) ("C-x 4 d" . ffap-dired-other-window) ("C-x 5 d" . ffap-dired-other-frame) ("C-x C-d" . ffap-list-directory)) :hook ((gnus-summary-mode . ffap-gnus-hook) (gnus-article-mode . ffap-gnus-hook) (vm-mode . ffap-ro-mode-hook) (rmail-mode . ffap-ro-mode-hook)) :ensure nil)
files
(use-package files :ensure nil :demand :preface (defun find-file--line-number (orig-fun filename &optional wildcards) (save-match-data (let* ((matched (string-match "^\\(.*\\):\\([0-9]+\\):?$" filename)) (line-number (and matched (match-string 2 filename) (string-to-number (match-string 2 filename)))) (filename (if matched (match-string 1 filename) filename))) (apply orig-fun (list filename wildcards)) (when line-number ;; goto-line is for interactive use (goto-char (point-min)) (forward-line (1- line-number)))))) :config (advice-add 'find-file :around #'find-file--line-number))
flyspell
(use-package flyspell :ensure nil :if (locate-file (if (boundp 'ispell-program-name) ispell-program-name "ispell") exec-path) :hook ((text-mode . flyspell-mode) (prog-mode . flyspell-prog-mode)) :bind (:map flyspell-mode-map ("C-M-i" . nil)))
goto-addr
(use-package goto-addr :ensure nil :hook (((prog-mode conf-mode) . goto-address-prog-mode) ((help-mode org-mode text-mode) . goto-address-mode) (git-commit-mode . goto-address-mode) (shell-mode . goto-address-mode)))
hl-line
(use-package hl-line :ensure nil :hook ((prog-mode . hl-line-mode) (org-mode . hl-line-mode) (dired-mode . hl-line-mode)))
paren
(use-package paren :ensure nil :hook ((prog-mode . show-paren-mode) (smartparens-mode . (lambda () (show-paren-mode -1)))))
pp
(use-package pp :ensure nil :commands pp-eval-last-sexp :bind (([remap eval-expression] . pp-eval-expression)) ;; :init ;;(global-unset-key (kbd "C-x C-e")) :hook ((lisp-mode emacs-lisp-mode) . always-eval-sexp) :preface (defun always-eval-sexp () (define-key (current-local-map) (kbd "C-x C-e") 'pp-eval-last-sexp)))
prog-mode
(use-package prog-mode :ensure nil :hook ((prog-mode . prettify-symbols-mode) (lisp-mode . prettify-symbols-lisp) (c-mode . prettify-symbols-c) (c++-mode . prettify-symbols-c++) ((js-mode js2-mode) . prettify-symbols-js) (prog-mode . (lambda () (setq-local scroll-margin 3)))) :preface (defun prettify-symbols-prog () (push '("<=" . ?≤) prettify-symbols-alist) (push '(">=" . ?≥) prettify-symbols-alist)) (defun prettify-symbols-lisp () (push '("/=" . ?≠) prettify-symbols-alist) (push '("sqrt" . ?√) prettify-symbols-alist) (push '("not" . ?¬) prettify-symbols-alist) (push '("and" . ?∧) prettify-symbols-alist) (push '("or" . ?∨) prettify-symbols-alist)) (defun prettify-symbols-c () (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)) (defun prettify-symbols-c++ () (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 '("->" . ?→) prettify-symbols-alist)) (defun prettify-symbols-js () (push '("function" . ?λ) prettify-symbols-alist) (push '("=>" . ?⇒) prettify-symbols-alist)))
savehist-mode
(use-package savehist :ensure nil :hook (after-init . savehist-mode))
saveplace-mode
(use-package saveplace :ensure nil :if (>= emacs-major-version 25) :hook (after-init . save-place-mode))
Shell
(use-package shell :ensure nil :bind (("C-c C-s" . shell) ("H-s" . shell) ("M-@" . shell)) :hook ((shell-mode . ansi-color-for-comint-mode-on) (shell-mode . dirtrack-mode) (shell-mode . pcomplete-shell-setup) ;; (shell-mode . (lambda () ;; (turn-on-comint-history (expand-file-name "sh-history" ;; user-emacs-directory)))) ))
simple
(use-package simple :ensure nil :demand :commands (column-number-mode auto-fill-mode) :bind (("C-`" . list-processes) :map minibuffer-local-map ("<escape>" . abort-recursive-edit) ("M-TAB" . previous-complete-history-element) ("<M-S-tab>" . next-complete-history-element)) :hook ((text-mode . visual-line-mode) (text-mode . auto-fill-mode)) :config (column-number-mode))
subword
(use-package subword :ensure nil :hook ((java-mode . subword-mode)))
term
(use-package term :ensure nil :commands (term-mode term-char-mode) :hook ((term-mode . (lambda () (setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *") (setq-local transient-mark-mode nil) (auto-fill-mode -1)))) :preface (autoload 'tramp-tramp-file-p "tramp") (autoload 'tramp-dissect-file-name "tramp")) (use-package tramp-term :commands tramp-term :functions term-send-raw-string :hook (tramp-term-after-initialized . (lambda (host) (term-send-raw-string (concat "cd " default-directory (kbd "RET"))))))
text-mode
(use-package text-mode :no-require :ensure nil :hook ((text-mode . turn-on-auto-fill)))
time
(use-package time :demand :ensure nil :config (display-time-mode))
url-handlers
(use-package url-handlers :ensure nil :demand :commands url-handler-mode :config (url-handler-mode))
which-func
(use-package which-func :ensure nil :commands which-function-mode :demand :config (which-function-mode))
whitespace
(use-package whitespace :ensure nil :hook (prog-mode . whitespace-mode))
Programming languages
Each use-package
declaration corresponds to major modes
in Emacs lingo.
Each language will at least one of these major modes as well as associated
packages (for completion, syntax checking, etc.)
C/C++
(use-package cc-mode :ensure nil :mode (("\\.h\\(h?\\|xx\\|pp\\)\\'" . c++-mode) ("\\.m\\'" . c-mode) ("\\.c\\'" . c-mode) ("\\.cpp\\'" . c++-mode) ("\\.c++\\'" . c++-mode) ("\\.mm\\'" . c++-mode)))
Irony
(use-package irony :preface (autoload 'file-remote-p "files") (defun irony-mode-disable-remote () "Disabled irony in remote buffers." (when (and buffer-file-name (file-remote-p buffer-file-name)) (irony-mode -1))) :hook (((c++-mode c-mode objc-mode) . irony-mode-disable-remote) ((c++-mode c-mode objc-mode) . irony-mode)))
(use-package irony-cdb :ensure nil :hook (irony-mode . irony-cdb-autosetup-compile-options))
(use-package flycheck-irony :hook (flycheck-mode . flycheck-irony-setup))
(use-package irony-eldoc :hook (irony-mode . irony-eldoc))
CoffeeScript
(use-package coffee-mode :mode (("\\.coffee\\'" . coffee-mode)))
CSS
(use-package css-mode :ensure nil :mode "\\.css\\'")
CSV
(use-package csv-mode :mode "\\.csv\\'")
ELF
(use-package elf-mode :magic ("�ELF" . elf-mode))
Emacs speaks statistics
(use-package ess-site :ensure ess :no-require :interpreter (("Rscript" . r-mode) ("r" . r-mode)) :mode (("\\.sp\\'" . S-mode) ("/R/.*\\.q\\'" . R-mode) ("\\.[qsS]\\'" . S-mode) ("\\.ssc\\'" . S-mode) ("\\.SSC\\'" . S-mode) ("\\.[rR]\\'" . R-mode) ("\\.[rR]nw\\'" . Rnw-mode) ("\\.[sS]nw\\'" . Snw-mode) ("\\.[rR]profile\\'" . R-mode) ("NAMESPACE\\'" . R-mode) ("CITATION\\'" . R-mode) ("\\.omg\\'" . omegahat-mode) ("\\.hat\\'" . omegahat-mode) ("\\.lsp\\'" . XLS-mode) ("\\.do\\'" . STA-mode) ("\\.ado\\'" . STA-mode) ("\\.[Ss][Aa][Ss]\\'" . SAS-mode) ("\\.[Ss]t\\'" . S-transcript-mode) ("\\.Sout" . S-transcript-mode) ("\\.[Rr]out" . R-transcript-mode) ("\\.Rd\\'" . Rd-mode) ("\\.[Bb][Uu][Gg]\\'" . ess-bugs-mode) ("\\.[Bb][Oo][Gg]\\'" . ess-bugs-mode) ("\\.[Bb][Mm][Dd]\\'" . ess-bugs-mode) ("\\.[Jj][Aa][Gg]\\'" . ess-jags-mode) ("\\.[Jj][Oo][Gg]\\'" . ess-jags-mode) ("\\.[Jj][Mm][Dd]\\'" . ess-jags-mode) ))
Go
(use-package go-mode :mode "\\.go\\'")
HAML
(use-package haml-mode :mode "\\.haml\\'")
Haskell
haskell-mode
(use-package haskell :preface (load "haskell-mode-autoloads" t t) :ensure haskell-mode :mode (("\\.hs\\(c\\|-boot\\)?\\'" . haskell-mode) ("\\.lhs\\'" . literate-haskell-mode) ("\\.cabal\\'" . haskell-cabal-mode)) :hook ((haskell-mode . subword-mode) (haskell-mode . flyspell-prog-mode) ;; (haskell-mode . haskell-indentation-mode) (haskell-mode . haskell-auto-insert-module-template) ;; (haskell-mode . haskell-decl-scan-mode) (haskell-mode . haskell-indent-mode) ;; (haskell-mode . imenu-add-menubar-index) ;; (haskell-mode . ;; (lambda () ;; (autoload 'haskell-doc-current-info ;; "haskell-doc") ;; (setq-local eldoc-documentation-function ;; 'haskell-doc-current-info))) ) :functions xref-push-marker-stack :commands (haskell-session-maybe haskell-mode-find-def haskell-ident-at-point haskell-mode-handle-generic-loc) :bind (:map haskell-mode-map ("C-c h" . haskell-hoogle) ("C-c C-." . haskell-navigate-imports) ("C-`" . haskell-interactive-bring) ("C-c `" . haskell-interactive-bring) ("C-c C-t" . haskell-process-do-type) ("C-c C-i" . haskell-process-do-info) ("C-c C-c" . haskell-process-cabal-build) ("C-c C-k" . haskell-interactive-mode-clear) ("C-c c" . haskell-process-cabal) ;; ("M-." . haskell-mode-jump-to-def) :map haskell-cabal-mode-map ("C-`" . haskell-interactive-bring) ("C-c C-k" . haskell-interactive-mode-clear) ("C-c C-c" . haskell-process-cabal-build) ("C-c c" . haskell-process-cabal) :map interactive-haskell-mode-map ("M-." . (lambda (&optional _next-p) (interactive "P") (if (haskell-session-maybe) (let ((initial-loc (point-marker)) (loc (haskell-mode-find-def (haskell-ident-at-point)))) (if loc (progn (haskell-mode-handle-generic-loc loc) (unless (equal initial-loc (point-marker)) (xref-push-marker-stack initial-loc))) (call-interactively 'haskell-mode-tag-find))) (call-interactively 'haskell-mode-tag-find)))) ("C-c C-t" . haskell-mode-show-type-at)) :init (add-to-list 'completion-ignored-extensions ".hi"))
haskell-interactive-mode
(use-package haskell-interactive-mode :ensure nil :commands interactive-haskell-mode ;; :hook (haskell-mode . interactive-haskell-mode) )
nix-haskell
(use-package nix-haskell-mode :ensure nil :hook (haskell-mode . nix-haskell-mode))
Java
jdee
(use-package jdee :disabled :mode ("\\.java\\'" . jdee-mode) :bind (:package jdee :map jdee-mode-map ("<s-mouse-1>" . jdee-open-class-at-event)))
JavaScript
indium
(use-package indium :if (>= emacs-major-version 25) :mode ("\\.js\\'" . indium-mode))
js2-mode
(use-package js2-mode :mode (("\\.js\\'" . js2-mode) ("\\.es6\\'" . js2-mode) ("\\.ejs\\'" . js2-mode)) :interpreter "node")
(use-package js2-imenu-extras :ensure nil :hook (js2-mode . js2-imenu-extras-mode))
tern
(use-package tern :if (locate-file "tern" exec-path) :hook (js2-mode . tern-mode))
JSON
(use-package json-mode :mode (("\\.bowerrc$" . json-mode) ("\\.jshintrc$" . json-mode) ("\\.json_schema$" . json-mode) ("\\.json\\'" . json-mode)) :bind (:package json-mode-map :map json-mode-map ("C-c <tab>" . json-mode-beautify)) :config (make-local-variable 'js-indent-level))
LaTeX
auctex
Auctex provides some helpful tools for working with LaTeX.
tex-site(use-package tex-site :ensure auctex :no-require :mode ("\\.tex\\'" . TeX-latex-mode))
(use-package tex-mode :ensure nil :hook (TeX-mode . latex-electric-env-pair-mode))
Lisp
(use-package elisp-mode :ensure nil :interpreter (("emacs" . emacs-lisp-mode)))
ielm
(use-package ielm :ensure nil :bind ("C-c :" . ielm))
Mach-O
View macho binaries read-only. To view in Hexl-mode raw binaries, run M-x macho-mode to toggle then M-x hexl-mode.
(use-package macho-mode :ensure nil :magic (("\xFE\xED\xFA\xCE" . macho-mode) ("\xFE\xED\xFA\xCF" . macho-mode) ("\xCE\xFA\xED\xFE" . macho-mode) ("\xCF\xFA\xED\xFE" . macho-mode)))
Markdown
markdown-mode
(use-package markdown-mode :mode (("README\\.md\\'" . gfm-mode) ("\\.md\\'" . markdown-mode) ("\\.markdown\\'" . gfm-mode)))
git-modes
gitattributes
(use-package gitattributes-mode :mode (("/\\.gitattributes\\'" . gitattributes-mode) ("/info/attributes\\'" . gitattributes-mode) ("/git/attributes\\'" . gitattributes-mode)))
gitconfig
(use-package gitconfig-mode :mode (("/\\.gitconfig\\'" . gitconfig-mode) ("/\\.git/config\\'" . gitconfig-mode) ("/modules/.*/config\\'" . gitconfig-mode) ("/git/config\\'" . gitconfig-mode) ("/\\.gitmodules\\'" . gitconfig-mode) ("/etc/gitconfig\\'" . gitconfig-mode)))
gitignore
(use-package gitignore-mode :mode (("/\\.gitignore\\'" . gitignore-mode) ("/info/exclude\\'" . gitignore-mode) ("/git/ignore\\'" . gitignore-mode)))
restclient
(use-package restclient :mode (("\\.rest\\'" . restclient-mode) ("\\.restclient\\'" . restclient-mode)))
Nix
nix-mode
(use-package nix-mode :mode "\\.nix\\'")
nix-shell
(use-package nix-shell :ensure nil :commands (nix-shell nix-unpack))
nix-drv-mode
(use-package nix-drv-mode :ensure nil :mode "\\.drv\\'")
nix-buffer
(use-package nix-buffer :commands nix-buffer ;; :preface ;; (defun turn-on-nix-buffer () ;; (when (and (not noninteractive) ;; (not (eq (aref (buffer-name) 0) ?\s)) ;; (not (file-remote-p default-directory))) ;; (nix-buffer))) ;; :hook (after-change-major-mode . turn-on-nix-buffer) )
nix-update
(use-package nix-update :commands nix-update-fetch :ensure nil :bind (("C-. u" . nix-update-fetch)))
PHP
(use-package php-mode :mode "\\.php\\'")
Proof General
(use-package proof-site :disabled :ensure proofgeneral :demand :if (not needs-package-init))
Python
Anaconda
(use-package anaconda-mode :hook ((python-mode . anaconda-mode) (python-mode . anaconda-eldoc-mode)))
python-mode
(use-package python :ensure nil :mode ("\\.py\\'" . python-mode) :interpreter ("python" . python-mode))
Ruby
(use-package ruby-mode :ensure nil :mode ("\\.rb\\'" . ruby-mode) :interpreter ("ruby" . ruby-mode))
Rust
(use-package rust-mode :mode "\\.rs\\'")
SASS
(use-package sass-mode :mode "\\.sass\\'")
Scala
(use-package scala-mode :interpreter ("scala" . scala-mode))
SCSS
(use-package scss-mode :mode "\\.scss\\'")
Shell
(use-package sh-script :ensure nil :commands shell-command :mode (("\\.*shellrc$" . sh-mode) ("\\.*shell_profile" . sh-mode) ("\\.zsh\\'" . sh-mode)))
texinfo
(use-package texinfo :ensure nil :mode ("\\.texi\\'" . texinfo-mode))
TypeScript
(use-package typescript-mode :mode "\\.ts\\'")
Web
(use-package web-mode :mode (("\\.erb\\'" . web-mode) ("\\.mustache\\'" . web-mode) ("\\.html?\\'" . web-mode) ("\\.php\\'" . web-mode) ("\\.jsp\\'" . web-mode) ;; ("\\.jsx?$" . web-mode) ("\\.es6\\'" . web-mode) ("\\.ejs\\'" . web-mode) ("\\.phtml\\'" . web-mode) ("\\.tpl\\.php\\'" . web-mode) ("\\.[agj]sp\\'" . web-mode) ("\\.as[cp]x\\'" . web-mode) ("\\.djhtml\\'" . web-mode)))
YAML
(use-package yaml-mode :mode "\\.ya?ml\\'")
Custom
These are all available in ./site-lisp. Eventually they should go into separate repositories.
dired-column
em-dired
installer
macho-mode
nethack
(use-package nethack :commands nethack :ensure nil)
nix-fontify
set-defaults
use-package-list
Other
These should correspond to minor modes or helper functions. Some of them are more helpful than others but none are essential.
Most of these are available in MELPA.
browse-at-remote
(use-package browse-at-remote :bind ("C-c g g" . browse-at-remote))
buffer-move
(use-package buffer-move :bind (("<M-S-up>" . buf-move-up) ("<M-S-down>" . buf-move-down) ("<M-S-left>" . buf-move-left) ("<M-S-right>" . buf-move-right)))
copy-as-format
(use-package copy-as-format :bind (("C-c w s" . copy-as-format-slack) ("C-c w g" . copy-as-format-github)))
crux
(use-package crux :bind (("C-c D" . crux-delete-file-and-buffer) ("C-c C-e" . crux-eval-and-replace) ("C-c d" . crux-duplicate-current-line-or-region) ([shift return] . crux-smart-open-line)))
delight
(use-package delight)
emacs-gif-screencast
(use-package gif-screencast
:commands gif-screencast)
htmlize
(use-package htmlize :no-require)
idle-highlight-mode
(use-package idle-highlight-mode :hook (prog-mode . idle-highlight-mode))
iedit
(use-package iedit
:commands iedit-mode)
page-break-lines
(use-package page-break-lines :delight :hook ((doc-mode emacs-lisp-mode compilation-mode outline-mode prog-mode haskell-mode help-mode magit-mode) . page-break-lines-mode))
pandoc-mode
(use-package pandoc-mode :hook ((markdown-mode . pandoc-mode) (pandoc-mode . pandoc-load-default-settings)))
rainbow-delimiters
(use-package rainbow-delimiters :hook ((emacs-lisp-mode inferior-emacs-lisp-mode ielm-mode lisp-mode inferior-lisp-mode lisp-interaction-mode slime-repl-mode) . rainbow-delimiters-mode))
rainbow-mode
(use-package rainbow-mode :hook ((emacs-lisp-mode inferior-emacs-lisp-mode ielm-mode lisp-mode inferior-lisp-mode lisp-interaction-mode slime-repl-mode web-mode less-css-mode html-mode css-mode) . rainbow-mode))
shrink-whitespace
(use-package shrink-whitespace :bind ("H-SPC" . shrink-whitespace))
string-inflection
(use-package string-inflection :bind (("C-c r r" . string-inflection-all-cycle) ("C-c r c" . string-inflection-camelcase) ("C-c r l" . string-inflection-lower-camelcase) ("C-c r u" . string-inflection-underscore) ("C-c r k" . string-inflection-kebab-case) ("C-c r J" . string-inflection-java-style-cycle)))
url-util
(use-package url-util :ensure nil :functions (url-hexify-string url-unhex-string region-active-p) :preface (defun func-region (start end func) "Run a function over the region between START and END in current buffer." (unless (region-active-p) (throw "No active region.")) (save-excursion (let ((text (delete-and-extract-region start end))) (insert (funcall func text))))) (defun url-encode (start end) "URL encode the region between START and END in current buffer." (interactive "r") (func-region start end 'url-hexify-string)) (defun url-decode (start end) "URL decode the region between START and END in current buffer." (interactive "r") (func-region start end 'url-unhex-string)))
undo-tree
(use-package undo-tree :commands global-undo-tree-mode :config (global-undo-tree-mode 1) ;; (global-set-key (kbd "C-z") 'undo) ;; (defalias 'redo 'undo-tree-redo) ;; (global-set-key (kbd "C-S-z") 'redo) )
git-timemachine
(use-package git-timemachine
:commands git-timemachine)
with-editor
(use-package with-editor :disabled :hook ((shell-mode eshell-mode) . with-editor-export-editor))
dired-rsync
(use-package dired-rsync :bind (:map dired-mode-map ("C-c C-r" . dired-rsync)))
comment-tags
(use-package comment-tags :hook (prog-mode . comment-tags-mode))
unfill
(use-package unfill :bind ([remap fill-paragraph] . unfill-toggle))
deadgrep
;; (use-package ripgrep :commands ripgrep-regexp) ;; (use-package rg :commands rg-dwim) (use-package deadgrep :commands deadgrep :bind (:map projectile-command-map ("s g" . deadgrep)))
org-static-blog
(use-package org-static-blog :commands org-static-blog-publish)
pcomplette
(use-package pcomplete :ensure nil :demand :commands pcomplete-here :preface (autoload 'pcomplete-comint-setup "pcomplete") :hook ((shell-mode . (lambda () (pcomplete-comint-setup 'shell-dynamic-complete-functions))) ;; (term-mode . (lambda () (pcomplete-comint-setup 'term-dynamic-complete-functions))) (comint-mode . (lambda () (pcomplete-comint-setup 'comint-dynamic-complete-functions))) ;; (eshell-mode . (lambda () (add-hook 'completion-at-point-functions ;; 'pcomplete-completions-at-point ;; nil t))) )) (use-package pcmpl-args) ;; (use-package pcmpl-git)
mwim
(use-package mwim :bind (([remap move-beginning-of-line] . mwim-beginning-of-code-or-line) ([remap move-end-of-line] . mwim-end-of-code-or-line)))
Profiles
All of these files live outside of Emacs but are necessary for a usable developer environment. They are basic shell profile and some git configuration scripts as well.
.profile
To use this, you must create a short ~/.profile file. Here is an example,
bootstrap=$HOME/.nix-profile/etc/profile [ -f $bootstrap ] && source $bootstrap
Set some Nix variables that never seem to get set correctly. There are a few bug
that break how this works. Also need to set some common exports that are needed.
Lots of common variables need to know about the .nix-profile
directory. We
leave the first MANPATH separator empty so it uses the default PATH lookup as
well. CVS_RSH is needed if your ever need to do cvs. HISTFILE sets where to
store the bash or zsh history. We set the history size to 10000 for good
measure. EDITOR should point to this editor.
export NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs:$HOME/.nix-defexpr/channels" export NIX_PROFILES="/nix/var/nix/profiles/default/profile $HOME/.nix-profile"
Here we setup .profile
. First, setup exports. We leave the first part of
MANPATH empty so it resolves using the PATH-based method. Fallbacks are provided
just in case.
export NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs:$HOME/.nix-defexpr/channels" \ NIX_PROFILES="/nix/var/nix/profiles/default/profile $HOME/.nix-profile" \ PATH=$HOME/.nix-profile/bin:$PREFIX/bin:@PATH@ INFOPATH=$HOME/.nix-profile/share/info:@INFOPATH@ \ MANPATH=:$HOME/.nix-profile/share/man:@MANPATH@ \ XDG_DATA_DIRS=$HOME/.nix-profile/share:@XDG_DATA_DIRS@ \ CVS_RSH=ssh \ HISTFILE=$HOME/.history \ SAVEHIST=50000 \ HISTSIZE=50000 \ EDITOR=emacs
Then setup aliases.
alias ls="TERM=ansi ls --color=always" \ l="ls -lF" \ ..="cd .." \ ...="cd ../.." \ ....="cd ../../.." \ .....="cd ../../../.." \ tree='tree -Csuh' \ grep="grep --color=auto"
Configure INSIDE_EMACS.
if [ "$TERM" = dumb ] && ! [ -z "$INSIDE_EMACS" ]; then export TERM=dumb-emacs-ansi \ COLORTERM=1 fi
Last, we source the HOME profile to make sure it is used by zsh.
if [ -f $HOME/.profile ] && [ -z "$SHELL_SOURCED_PROFILE" ]; then SHELL_SOURCED_PROFILE=1 source $HOME/.profile fi
.zshrc
This is a profile for use with Zsh. It is closely based off of oh-my-zsh.
Setup ZSH profile. First, we just source the global profile.
source @out@/etc/profile
Handle dumb options.
case "$TERM" in dumb) unsetopt zle \ prompt_cr \ prompt_subst PS1='$ ' PROMPT='$ ' return ;; eterm*) setopt nopromptsp \ single_line_zle ;; esac
Load up site-functions in ZSH.
fpath+=@completions@/share/zsh/site-functions
Turn on ZSH-specific options.
setopt always_to_end \ auto_cd \ auto_menu \ auto_name_dirs \ auto_pushd \ cdable_vars \ extended_history \ extended_glob \ hist_expire_dups_first \ hist_find_no_dups \ hist_ignore_dups \ hist_ignore_space \ hist_reduce_blanks \ hist_save_no_dups \ hist_verify \ interactive_comments \ inc_append_history_time \ long_list_jobs \ multios \ no_beep \ prompt_subst \ pushd_ignore_dups \ pushdminus \ transient_rprompt \ menu_complete
Setup completions & colors.
autoload -U colors && colors autoload -U compinit && compinit
Bind to emacs…
bindkey -e
Zstyle completions.
zstyle ':completion:*::::' completer \ _expand _complete _ignored _approximate zstyle ':completion:*' menu select=1 \ _complete _ignored _approximate zstyle ':completion:*' matcher-list \ 'm:{a-zA-Z-_}={A-Za-z_-}' \ 'r:|=*' 'l:|=* r:|=*' zstyle ':completion:*' list-colors '' zstyle ':completion:*' select-prompt \ '%SScrolling active: current selection at %p%s' zstyle ':completion:*' \ ignored-patterns '*~' '_*' '*\\\#*\\\#' zstyle ':completion:*:scp:*' group-order files \ all-files users hosts-domain \ hosts-host hosts-ipaddr zstyle ':completion:*:ssh:*' group-order hosts-domain \ hosts-host users hosts-ipaddr zstyle ':vcs_info:*' enable git zstyle '*' single-ignored show
Turn on prompt with colors.
PROMPT='%F{blue}%n@%m:%F{cyan}%c%F{yellow} $ %F{reset}'
Setup Apple Terminal so that CWD is shown.
update_terminal_cwd () { printf '\e]7;%s\a' "file://$HOSTNAME${PWD// /%20}" } if [ "$TERM_PROGRAM" = Apple_Terminal ] \ && [ -z "$INSIDE_EMACS" ] \ && [ -n "$TERM_SESSION_ID" ]; then chpwd_functions+=(update_terminal_cwd) update_terminal_cwd fi
etc-profile.sh
This just sources everything in the /etc/profile.d
dir. PREFIX
can be
used to reference the Nix output dir.
export PREFIX=@out@
This will source everything in /etc/profile.d
. We skip nix-daemon.sh
because
it is put in the global profile, and sets values incorrectly when we are in
single user mode. We need @out@ to come after $HOME so that it gets the last
word in these settings.
for i in $HOME/.nix-profile/etc/profile.d/*.sh @out@/etc/profile.d/*.sh; do if [ -r $i ] && [ "$(basename $i)" != nix-daemon.sh ]; then source $i fi done
Bootstrapping
site-paths.el.in
This file provides site-specific paths. However, it must be substituted in Nix
before we can actually run it in Emacs. To prevent Emacs from trying to run
this, I’ve set the syntax to text
.
(require 'set-defaults) (require 'subr-x)
output-directory
points to the nix-profile directory created by Nix.
Ideally, this could point to a Nix store path, but the order of building
means that we don’t know this until too late.
(defvar output-directory (expand-file-name ".nix-profile" (getenv "HOME"))) (defvar zsh-command (expand-file-name "bin/zsh" output-directory))
Setup exec-path
.
(setq exec-path (append `("@bins@/bin" ,(expand-file-name "bin" output-directory) "@PATH@") exec-path))
Setup man-path
.
(defvar man-path `("" "@manpages@/share/man" ,(expand-file-name "share/man" output-directory) "@MANPATH@"))
This will setup cacert-file var,
(defcustom cacert-file "/etc/ssl/certs/ca-bundle.crt" "Path for SSL certificates." :type 'string :group 'environment)
Setup history and stuff. This gets messy, but we need to make sure these are set otherwise zsh will default to 500 and not save at all!
(defun bauer-set-history-file (sym val) "Setter for history-file." (setenv "HISTFILE" (eval val)) t) (defcustom history-file (expand-file-name ".history" (getenv "HOME")) "The history file to use." :type 'string :group 'bauer :set 'bauer-set-history-file :initialize 'bauer-set-history-file) (defvar eshell-history-size) (defun bauer-set-history-size (sym val) "Setter for history-size." (setenv "HISTSIZE" (format "%i" val)) (setenv "SAVEHIST" (format "%i" val)) (setq eshell-history-size val) t) (defcustom history-size 50000 "The history size to use." :type 'integer :group 'bauer :set 'bauer-set-history-size :initialize 'bauer-set-history-size)
Set some more misc. vars.
(append-envs ":" `("PATH" ,exec-path) `("MANPATH" ,man-path)) (set-envs `("XDG_DATA_DIRS" ,(string-join `("@XDG_DATA_DIRS@" ,(expand-file-name "share" output-directory)) ":")) `("INFOPATH" ,(string-join `("@INFOPATH@" ,(expand-file-name "share/info" output-directory)) ":")))
Set env vars provided by Nix. We have to override this because the defaults Nix has are bad.
(setenv "NIX_PATH" (format "nixpkgs=%s/.nix-defexpr/channels/nixpkgs:%s/.nix-defexpr/channels" (getenv "HOME") (getenv "HOME"))) (setenv "NIX_PROFILES" (string-join (list "/nix/var/nix/profiles/default/profile" (format "%s/.nix-profile" (getenv "HOME"))) " "))
Set paths provided by Nix,
(defvar gnutls-program "gnutls") (defvar pdf2dsc-command "pdf2dsc") (defvar dvips-command "dvips") (defvar dvipng-command "dvipng") (defvar xetex-command "xetex") (defvar xelatex-command "xelatex") (defvar luatex-command "luatex") (defvar makeinfo-command "makeinfo") (defvar LaTeX-command "LaTeX") (defvar pdftex-command "pdftex") (defvar context-command "context") (defvar bibtex-command "bibtex") (defvar makeindex-command "makeindex") (defvar dvipdfmx-command "dvipdfmx") (defvar ag-executable "ag") (defvar ripgrep-executable "ripgrep") (defvar lacheck-command "lacheck") (defvar chktex-command "chktex") (defvar ps2pdf-command "ps2pdf") (set-paths '(company-cmake-executable "@cmake@/bin/cmake") '(doc-view-dvipdf-program "@ghostscript@/bin/dvipdf") '(cacert-file "@cacert@/etc/ssl/certs/ca-bundle.crt") '(calc-gnuplot-name "@gnuplot@/bin/gnuplot") '(gnuplot-program "@gnuplot@/bin/gnuplot") '(doc-view-ps2pdf-program "@ghostscript@/bin/ps2pdf") '(dired-touch-program "@coreutils@/bin/touch") '(dired-chmod-program "@coreutils@/bin/chmod") '(dired-chown-program "@coreutils@/bin/chown") '(dired-free-space-program "@coreutils@/bin/df") '(diff-command "@diffutils@/bin/diff") '(find-program "@findutils@/bin/find") '(epg-gpg-program "@gpg@/bin/gpg") '(epg-gpgconf-program "@gpg@/bin/gpgconf") '(epg-gpgsm-program "@gpg@/bin/gpgsm") '(flycheck-sh-bash-executable "@bash@/bin/bash") '(flycheck-sh-zsh-executable "@zsh@/bin/zsh") '(flycheck-perl-executable "@perl@/bin/perl") ;; '(flycheck-go-golint-executable "@golint@/bin/golint") '(flycheck-haskell-hlint-executable "@hlint@/bin/hlint") '(flycheck-python-flake8-executable "@flake8@/bin/flake8") '(flycheck-asciidoc-executable "@asciidoc@/bin/asciidoc") '(flycheck-less-executable "@lessc@/bin/lessc") '(flycheck-c/c++-gcc-executable "@gcc@/bin/gcc") '(flycheck-javascript-eslint-executable "@eslint@/bin/eslint") '(flycheck-javascript-jshint-executable "@jshint@/bin/jshint") ;; '(flycheck-go-build-executable "@go@/bin/go") ;; '(flycheck-go-test-executable "@go@/bin/go") '(flycheck-lua-executable "@lua@/bin/luac") '(flycheck-xml-xmllint-executable "@libxml2@/bin/xmllint") '(flycheck-html-tidy-executable "@tidy@/bin/tidy") '(fortune-dir "@fortune@/share/games/fortunes") '(fortune-program "@fortune@/bin/fortune") '(fortune-file "@fortune@/share/games/fortunes/debian") '(grep-program "@gnugrep@/bin/grep") '(haskell-check-command "@hlint@/bin/hlint") '(haskell-hoogle-command "@hoogle@/bin/hoogle") '(haskell-hasktags-path "@hasktags@/bin/hasktags") '(ispell-program-name "@aspell@/bin/aspell") '(ispell-grep-command "@gnugrep@/bin/grep") '(irony-cmake-executable "@cmake@/bin/cmake") '(jka-compr-info-compress-program "@ncompress@/bin/compress") '(jka-compr-info-uncompress-program "@ncompress@/bin/uncompress") ;; '(irony-server-install-prefix "@irony@") '(jka-compr-dd-program "@coreutils@/bin/dd") '(magit-git-executable "@git@/bin/git") '(markdown-command "@markdown2@/bin/markdown2") '(manual-program "@man@/bin/man") '(man-awk-command "@gawk@/bin/awk") '(man-sed-command "@gnused@/bin/sed") '(man-untabify-command "@coreutils@/bin/pr") '(nethack-executable "@nethack@/bin/nethack") '(org-pandoc-command "@pandoc@/bin/pandoc") '(pandoc-binary "@pandoc@/bin/pandoc") '(remote-shell-program "@openssh@/bin/ssh") '(ripgrep-executable "@ripgrep@/bin/rg") '(rtags-path "@rtags@/bin") '(sql-ingres-program "@parallel@/bin/sql") '(sql-interbase-program "@unixODBC@/bin/isql") ;; '(sql-mysql-program "@mariadb@/bin/mysql") '(sql-ms-program "@freetds@/bin/osql") '(sql-postgres-program "@freetds@/bin/osql") '(sql-sqlite-program "@sqliteInteractive@/bin/sqlite3") '(tramp-encoding-shell "@bash@/bin/sh") '(tex-shell "@bash@/bin/sh") '(xargs-program "@findutils@/bin/xargs") '(vc-git-program "@git@/bin/git") '(gnutls-program "@gnutls@/bin/gnutls-cli") '(pdf2dsc-command "@ghostscript@/bin/pdf2dsc") '(preview-gs-command "@texlive@/bin/rungs") '(TeX-command "@texlive@/bin/tex") '(LaTeX-command "@texlive@/bin/latex") '(latex-run-command "@texlive@/bin/latex") '(tex-run-command "@texlive@/bin/tex") '(luatex-command "@texlive@/bin/luatex") '(xetex-command "@texlive@/bin/xetex") '(xelatex-command "@texlive@/bin/xelatex") '(makeinfo-command "@texinfoInteractive@/bin/makeinfo") '(pdftex-command "@texlive@/bin/pdftex") '(context-command "@texlive@/bin/context") '(bibtex-command "@texlive@/bin/bibtex") '(dvipdfmx-command "@texlive@/bin/dvipdfmx") '(makeindex-command "@texlive@/bin/makeindex") '(chktex-command "@texlive@/bin/chktex") '(lacheck-command "@texlive@/bin/lacheck") '(dvipdfmx-command "@texlive@/bin/dvipdfmx") '(dvips-command "@texlive@/bin/dvips") '(dvipng-command "@texlive@/bin/dvipng") '(ps2pdf-command "@ghostscript@/bin/ps2pdf") '(locate-executable "@findutils@/bin/locate") '(ag-executable "@ag@/bin/ag") '(notmuch-command "@notmuch@/bin/notmuch") '(dumb-jump-rg-cmd "@ripgrep@/bin/rg") '(dumb-jump-ag-cmd "@ag@/bin/ag") '(gud-gdb-command-name "@gdb@/bin/gdb") '(coq-prog-name "@coq@/bin/coqtop") '(coq-dependency-analyzer "@coq@/bin/coqdep") '(coq-compiler "@coq@/bin/coqc") )
Set some defaults that depend on the path variables below,
(set-defaults '(imap-ssl-program `(,(concat gnutls-program " --tofu -p %p %s"))) '(tls-program (concat gnutls-program " --tofu -p %p %h")) '(preview-pdf2dsc-command (concat pdf2dsc-command " %s.pdf %m/preview.dsc")) '(preview-dvips-command (concat dvips-command " -Pwww %d -o %m/preview.ps")) '(preview-fast-dvips-command (concat dvips-command " -Pwww %d -o %m/preview.ps")) '(preview-dvipng-command (concat dvipng-command " -picky -noghostscript %d -o \"%m/prev%%03d.png\"")) '(TeX-engine-alist `((xetex "XeTeX" xetex-command xelatex-command xetex-command) (luatex "LuaTeX" luatex-command ,(concat luatex-command " --jobname=%s") luatex-command))) '(TeX-command-list `(("TeX" ,(concat "%(PDF)%(tex) %(file-line-error) " "%(extraopts) %`%S%(PDFout)%(mode)%' %t") TeX-run-TeX nil (plain-tex-mode ams-tex-mode texinfo-mode) :help "Run plain TeX") ("LaTeX" "%`%l%(mode)%' %t" TeX-run-TeX nil (latex-mode doctex-mode) :help "Run LaTeX") ("Makeinfo" ,(concat makeinfo-command " %(extraopts) %t") TeX-run-compile nil (texinfo-mode) :help "Run Makeinfo with Info output") ("Makeinfo HTML" ,(concat makeinfo-command " %(extraopts) --html %t") TeX-run-compile nil (texinfo-mode) :help "Run Makeinfo with HTML output") ("AmSTeX" ,(concat pdftex-command " %(PDFout) %(extraopts) %`%S%(mode)%' %t") TeX-run-TeX nil (ams-tex-mode) :help "Run AMSTeX") ("ConTeXt" ,(concat context-command " --once --texutil %(extraopts) %(execopts)%t") TeX-run-TeX nil (context-mode) :help "Run ConTeXt once") ("ConTeXt Full" ,(concat context-command " %(extraopts) %(execopts)%t") TeX-run-TeX nil (context-mode) :help "Run ConTeXt until completion") ("BibTeX" ,(concat bibtex-command " %s") TeX-run-BibTeX nil t :help "Run BibTeX") ("Biber" "biber %s" TeX-run-Biber nil t :help "Run Biber") ("View" "%V" TeX-run-discard-or-function t t :help "Run Viewer") ("Print" "%p" TeX-run-command t t :help "Print the file") ("Queue" "%q" TeX-run-background nil t :help "View the printer queue" :visible TeX-queue-command) ("File" ,(concat dvips-command " %d -o %f ") TeX-run-dvips t t :help "Generate PostScript file") ("Dvips" ,(concat dvips-command " %d -o %f ") TeX-run-dvips nil t :help "Convert DVI file to PostScript") ("Dvipdfmx" ,(concat dvipdfmx-command " %d") TeX-run-dvipdfmx nil t :help "Convert DVI file to PDF with dvipdfmx") ("Ps2pdf" ,(concat ps2pdf-command " %f") TeX-run-ps2pdf nil t :help "Convert PostScript file to PDF") ("Index" ,(concat makeindex-command " %s") TeX-run-index nil t :help "Run makeindex to create index file") ("upMendex" "upmendex %s" TeX-run-index t t :help "Run mendex to create index file") ("Xindy" "xindy %s" TeX-run-command nil t :help "Run xindy to create index file") ("Check" ,(concat lacheck-command " %s") TeX-run-compile nil (latex-mode) :help "Check LaTeX file for correctness") ("ChkTeX" ,(concat chktex-command " -v6 %s") TeX-run-compile nil (latex-mode) :help "Check LaTeX file for common mistakes") ("Spell" "(TeX-ispell-document \"\")" TeX-run-function nil t :help "Spell-check the document") ("Clean" "TeX-clean" TeX-run-function nil t :help "Delete generated intermediate files") ("Clean All" "(TeX-clean t)" TeX-run-function nil t :help "Delete generated intermediate and output files") ("Other" "" TeX-run-command t t :help "Run an arbitrary command"))) '(counsel-grep-base-command (concat ripgrep-executable " -i -M 120 --no-heading --line-number --color never '%s' %s")) '(counsel-rg-base-command (concat ripgrep-executable " -i --no-heading --line-number %s .")) '(counsel-ag-base-command (concat ag-executable " --nocolor --nogroup %s")) '(org-preview-latex-process-alist `((dvipng :programs ("latex" "dvipng") :description "dvi > png" :message "" :image-input-type "dvi" :image-output-type "png" :image-size-adjust (1.0 . 1.0) :latex-compiler (,(concat LaTeX-command " -interaction nonstopmode -output-directory %o %f")) :image-converter (,(concat dvipng-command " -fg %F -bg %B -D %D -T tight -o %O %f"))))) '(Info-directory-list '("@infopages@/share/info")) '(tramp-remote-path `(tramp-own-remote-path "/run/current-system/sw/bin" tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin" "/opt/bin" "/opt/sbin" ,(expand-file-name "bin" output-directory))) '(woman-manpath man-path) '(Man-header-file-path `("@sysheaders@/include" "/usr/include" "/usr/local/include")) '(ffap-c-path '("@sysheaders@/include" "/usr/include" "/usr/local/include")) '(rng-schema-locating-files `("schemas.xml" "@schemas@" ,(expand-file-name "schema/schemas.xml" data-directory))) '(irony-additional-clang-options '("-I@sysheaders@/include" "-I@sysheaders@/include/c++/v1" "-F@sysframeworks@/Library/Frameworks")) )
bootstrap.sh
This is the bootstrap script that is mentioned above. We use it to install the IDE. It ensures Nix is installed as well as that the Git repo is available & up-to-date. Note, this script will automatically install Nix and Git for you if they are not already installed! Use it at your own risk.
Install Nix if it isn’t already.
echo This script will install Nix and Git echo if they are not already installed. if ! command -v nix-env >/dev/null 2>&1; then nix_installer=$(mktemp) curl -s https://nixos.org/nix/install \ > $nix_installer sh $nix_installer source $HOME/.profile fi
Check for Git. Install if it’s not there.
if ! command -v git >/dev/null 2>&1; then nix-env -iA nixpkgs.git fi
If we are in a Git repo already, we’ll pull to get latest updates.
if [ -d .git ]; then git pull origin master || true fi
If we can’t find default.nix then we’ll clone from GitHub. This will be stored in
~/.local/share/bauer
.
if ! [ -f default.nix ]; then repo_dir=$HOME/.local/share/bauer mkdir -p $(dirname $repo_dir) git clone https://github.com/matthewbauer/bauer \ $repo_dir cd $repo_dir fi
The last action is to install our new derivation.
nix-env -if .
Install the profile.
echo 'source $HOME/.nix-profile/etc/profile' >> $HOME/.profile echo "To use bauer correctly, you must first source the profile." echo echo "To do this, just run:" echo " source $HOME/.nix-profile/etc/profile" echo "From you command line" echo "You can also run either emacs or zsh to launch the environment"
runemacs.sh
Cross-platform script to execute app.
case $(uname) in Darwin) open @emacs@/Applications/Emacs.app ;; *) @emacs@/bin/emacs ;; esac
Building
default.nix
: the tangler
Here we being the building process. There are a couple of stages to this not normally seen in configurations. The first part is the ‘default.nix’ which will tangle the README.org file. This should be the only file that has to live outside of this ORG document. This is meant to be very minimal so that once we tangle README.org, we can get a working .nix file to import from using Nix’s import from derivation.
The function header defines some arguments you can pass. It will use the latest nixpkgs-unstable from nixos.org. If you want to change this, you can pass in your own pkgs variable.
The small argument is a bit of a hack. Nix will only recognize args that have been explicitly listed so we cannot rely on the ‘…’ syntax to pick up random args.
# -*- mode: nix; coding: utf-8; -*- { version ? "19.03" , channel ? { "x86_64-darwin" = "nixpkgs-${version}-darwin"; }.${builtins.currentSystem} or "nixos-${version}" , nixpkgs-url ? "nixos.org/channels/${channel}/nixexprs.tar.xz" , system ? builtins.currentSystem , crossSystem ? null , config ? {} , overlays ? [] , pkgs ? import (builtins.fetchTarball nixpkgs-url) { inherit crossSystem system config overlays; } , small ? false , ... } @ args:
Now let’s tangle README.org… This uses ORG’s babel functionality to generate a .nix file. The .nix file is renamed to default.nix to replace this script.
let ensure = f: n: if builtins.pathExists f then f else builtins.fetchurl "https://matthewbauer.us/bauer/${n}"; in import (pkgs.runCommand "README" { buildInputs = with pkgs; [ emacs git ]; } ('' install -D ${ensure ./README.org "README.org"} \ $out/README.org cd $out '' + pkgs.lib.optionalString (builtins.pathExists ./site-lisp) '' cp -r ${./site-lisp} site-lisp '' + '' emacs --batch --quick \ -l ob-tangle \ --eval "(org-babel-tangle-file \"README.org\")" cp bauer.nix default.nix '')) { inherit ensure pkgs; }
bauer.nix
: the build script
Here we have the actual Nix file that will build our Emacs configuration. Again we have some options that can be provided…
# -*- mode: nix; coding: utf-8; -*- { system ? builtins.currentSystem , crossSystem ? null , config ? {} , overlays ? [] , pkgs ? import <nixpkgs> { inherit crossSystem system config overlays; } , ensure ? (f: n: f) , small ? pkgs.config.bauer.small or true , ... }: let inherit (pkgs) stdenv lib runCommand buildEnv config writeText; inherit (stdenv) hostPlatform; big = !small; allowUnfree = config.allowUnfree or false;
By default, you will be building the “small” version which is about 500MB. The normal version has a huge closure totalling in at over 5GB. This is extremely useful for integrations with developer tools and manuals, but also inconvenient when wanting to start running for the first time. If you want to enable the big version, you can just do ‘config.bauer.small = false’ in your ~/.config/nixpkgs/config.nix file. Alternatively, if you want the small version, just do ‘nixpkgs.config.bauer.small = true’.
Next we start defining some packages. R is one of the simpler ones right now, so let’s start with that.
rEnv = pkgs.rWrapper.override { packages = with pkgs.rPackages; [ RCurl ]; };
Here we define our package set. This will just give us access to all of the Emacs packages defined in Nixpkgs.
We also define our Emacs version to use. Mitsuharo’s Emacs package is much better for MacOS so we use that when we’re on Darwin systems. Otherwise, just default to ‘emacs’ which should be the latest (Nixpkgs-unstable has version 26.1 currently).
customEmacsPackages = pkgs.emacsPackagesNgGen (if hostPlatform.isDarwin then pkgs.emacsMacport else pkgs.emacs);
Tex live provides some LaTeX commads for us.
myTex = pkgs.texlive.combine { inherit (pkgs.texlive) xetex setspace fontspec chktex enumitem xifthen ifmtarg filehook wrapfig inconsolata upquote minted lastpage collection-basic collection-binextra collection-context collection-fontsrecommended collection-fontutils collection-langenglish collection-latex collection-latexrecommended collection-luatex collection-metapost collection-texworks collection-xetex capt-of ulem hyperref titlesec; };
Emacs configuration
Here, we start building up the site-paths.el file. This does a simple substitution of all the attributes set.
site-paths = runCommand "site-paths.el" (with pkgs; ({ inherit (customEmacsPackages) emacs; inherit ripgrep ag # fortune # nethack coreutils findutils openssh bash zsh diffutils man gawk gnugrep gnused cacert git # Nix paths manpages sysheaders sysframeworks schemas bins infopages aspell; inherit MANPATH PATH XDG_DATA_DIRS INFOPATH; } // (lib.optionalAttrs big { # random packages needed in site-paths gpg = gnupg1compat; inherit ant perl perlcritic asciidoc lessc lua gcc pandoc clang cmake ghostscript sqliteInteractive freetds parallel unixODBC ncompress texinfoInteractive notmuch gnuplot gdb coq rtags # mariadb go golint gnutls ; inherit (pythonPackages) flake8; inherit (nodePackages) jshint eslint; inherit (haskellPackages) hoogle hlint; # hasktags texlive = myTex; markdown2 = pythonPackages.markdown2; tidy = html-tidy; libxml2 = libxml2.bin; # stylish = haskellPackages.stylish-haskell; # intero = haskellPackages.intero-nix-shim; # irony = irony-server; # jdeeserver = jdee-server; }))) '' substituteAll ${./site-paths.el.in} $out substituteInPlace $out \ --subst-var-by PATH ${PATH} \ --subst-var-by INFOPATH ${INFOPATH} \ --subst-var-by MANPATH ${MANPATH} \ --subst-var-by XDG_DATA_DIRS ${XDG_DATA_DIRS} '';
Emacs building can be divided into phases. Each phase will run through the Elisp once.
Phase 1: picking up dependencies
myEmacsPackages gets a listing of all of the packages that are needed by the Emacs configuration. use-package-list generates this list automatically.
package-list = runCommand "package-list" { buildInputs = [ customEmacsPackages.emacs ]; } ''
emacs --batch --quick \ -L ${customEmacsPackages.use-package }/share/emacs/site-lisp/elpa/use-package-* \ -L ${customEmacsPackages.delight }/share/emacs/site-lisp/elpa/delight-* \ -L ${customEmacsPackages.bind-key }/share/emacs/site-lisp/elpa/bind-key-* \ -l ${ensure ./site-lisp/set-defaults.el "site-lisp/set-defaults.el"} \ -l ${ensure ./site-lisp/bauer.el "site-lisp/bauer.el"} \ -l ${ensure ./site-lisp/use-package-list.el "site-lisp/use-package-list.el"} \ --eval "(use-package-list \"${./README.el}\")" \ > $out
'';
myEmacsPackages' = builtins.fromJSON (builtins.readFile package-list);
Phase 2: byte compiling
default = runCommand "bauer-emacs" { buildInputs = [ pkgs.emacs ]; } ''
Install our lisp files. Many of these should be released into MELPA but don’t have the time to do it currently.
install -D ${site-paths} \ $out/share/emacs/site-lisp/site-paths.el install -D ${./README.el} \ $out/share/emacs/site-lisp/default.el install -D ${ensure ./site-lisp/em-dired.el "site-lisp/em-dired.el"} \ $out/share/emacs/site-lisp/em-dired.el install -D ${ensure ./site-lisp/dired-column.el "site-lisp/dired-column.el"} \ $out/share/emacs/site-lisp/dired-column.el install -D ${ensure ./site-lisp/macho-mode.el "site-lisp/macho-mode.el"} \ $out/share/emacs/site-lisp/macho-mode.el install -D ${ensure ./site-lisp/nethack.el "site-lisp/nethack.el"} \ $out/share/emacs/site-lisp/nethack.el install -D ${ensure ./site-lisp/set-defaults.el "site-lisp/set-defaults.el"} \ $out/share/emacs/site-lisp/set-defaults.el install -D ${ensure ./site-lisp/installer.el "site-lisp/installer.el"} \ $out/share/emacs/site-lisp/installer.el install -D ${ensure ./site-lisp/restart-emacs.el "site-lisp/restart-emacs.el"} \ $out/share/emacs/site-lisp/restart-emacs.el install -D ${ensure ./site-lisp/use-package-list.el "site-lisp/use-package-list.el"} \ $out/share/emacs/site-lisp/use-package-list.el install -D ${builtins.fetchurl "https://raw.githubusercontent.com/matthewbauer/nix-haskell-mode/master/nix-haskell-mode.el"} \ $out/share/emacs/site-lisp/nix-haskell-mode.el install -D ${ensure ./site-lisp/bauer.el "site-lisp/bauer.el"} \ $out/share/emacs/site-lisp/bauer.el
This is fairly complicated. What happens is we batch compile all of the .el files. The problem is the .el files all are going to depend on dependencies that we have just found in package-list. The solution is that complex eval below where we add all of the paths (plus their requisites) to the load path. This works but is hacky & I am interested in fixing it.
cd $out/share/emacs/site-lisp export HOME=$PWD emacs --batch --quick \ --eval \ "(let ((default-directory \"${emacsWrapper ((requiredPackages customEmacsPackages myEmacsPackages') ++ (with customEmacsPackages; [use-package delight])) }/share/emacs/site-lisp\")) (normal-top-level-add-subdirs-to-load-path))" \ -L . -f batch-byte-compile *.el
'';
Phase 3: wrapping into Emacs
emacsWrapper = explicitRequires: runCommand "emacs-packages-deps" { nativeBuildInputs = [ pkgs.xorg.lndir pkgs.emacs ]; inherit explicitRequires; } '' findInputsOld() { local pkg="$1"; shift local var="$1"; shift local propagatedBuildInputsFiles=("$@") local varSlice="$var[*]" case "''${!varSlice-}" in *" $pkg "*) return 0 ;; esac unset -v varSlice eval "$var"'+=("$pkg")' if ! [ -e "$pkg" ]; then echo "build input $pkg does not exist" >&2 exit 1 fi local file for file in "''${propagatedBuildInputsFiles[@]}"; do file="$pkg/nix-support/$file" [[ -f "$file" ]] || continue local pkgNext for pkgNext in $(< "$file"); do findInputsOld "$pkgNext" "$var" \ "''${propagatedBuildInputsFiles[@]}" done done } mkdir -p $out/bin mkdir -p $out/share/emacs/site-lisp local requires for pkg in $explicitRequires; do findInputsOld $pkg requires propagated-user-env-packages done linkPath() { local pkg=$1 local origin_path=$2 local dest_path=$3 if [[ -d "$pkg/$origin_path" ]]; then lndir -silent "$pkg/$origin_path" \ "$out/$dest_path" fi } linkEmacsPackage() { linkPath "$1" "bin" "bin" linkPath "$1" "share/emacs/site-lisp" \ "share/emacs/site-lisp" } for pkg in "''${requires[@]}"; do linkEmacsPackage $pkg done emacs --batch -f batch-byte-compile \ "$siteStart" '';
requiredPackages is a function that takes two arguments.
requiredPackages = epkgs: map (x: if builtins.hasAttr x epkgs then builtins.getAttr x epkgs else if builtins.hasAttr x pkgs.emacsPackages then builtins.getAttr x pkgs.emacsPackages else abort "no attribute found for use-package ${x}");
Now we build our Emacs distribution.
TODO use dump-emacs here to speed up config.
myEmacsPackages = buildEnv { name = "emacs-packages-env"; paths = (requiredPackages customEmacsPackages myEmacsPackages') ++ [ customEmacsPackages.use-package customEmacsPackages.delight ]; }; myEmacs = customEmacsPackages.emacsWithPackages (epkgs: (requiredPackages epkgs myEmacsPackages') ++ [default epkgs.use-package epkgs.delight] );
The environment
Finally, we can actually build the environment.
First build the info pages…
infopages = buildEnv { name = "info-pages"; buildInputs = [ pkgs.texinfoInteractive ]; paths = userPackages ++ [customEmacsPackages.emacs]; extraOutputsToInstall = [ "info" "doc" "devdoc" ]; pathsToLink = [ "/share/info" ]; postBuild = '' shopt -s nullglob find -L ${myEmacsPackages}/share/emacs/ -name '*.info*' -exec ln -s {} $out/share/info \; for i in $out/share/info/*; do install-info $i $out/share/info/dir done ''; };
Setup man pages…
manpages = buildEnv { name = "man-pages"; ignoreCollisions = (!(config.bauer.small or false)); paths = userPackages ++ [pkgs.posix_man_pages pkgs.stdman # pkgs.llvmPackages.clang-manpages # pkgs.llvmPackages.llvm-manpages ] ++ lib.optional (hostPlatform.isDarwin && big && allowUnfree) "${apple_sdk}/usr" ++ lib.optionals (hostPlatform.isLinux && big) [ pkgs.man-pages pkgs.glibcInfo pkgs.stdmanpages ]; extraOutputsToInstall = [ "man" "doc" "devdoc" "devman" ]; pathsToLink = [ "/share/man" ]; };
Setup XDG data directory..
xdg-data = buildEnv { name = "xdg-data-dirs"; buildInputs = [ pkgs.desktop-file-utils pkgs.shared-mime-info ]; paths = userPackages ++ [ customEmacsPackages.emacs pkgs.zsh ]; pathsToLink = [ "/share/applications" "/share/mime" "/share/menus" "/share/icons" ]; postBuild = '' export XDG_DATA_DIRS=$out/share if [ -w $out/share/applications ]; then update-desktop-database $out/share/applications fi if [ -w $out/share/mime ] \ && [ -w $out/share/mime/packages ]; then update-mime-database -V $out/share/mime fi ''; };
ZSH completions…
zsh-completions = buildEnv { name = "zsh-completions"; paths = userPackages; pathsToLink = [ "/share/zsh/site-functions" ]; };
Setup binaries
bins = buildEnv { name = "bins"; paths = userPackages; extraOutputsToInstall = [ "bin" ]; pathsToLink = [ "/bin" ]; postBuild = '' find $out/bin -maxdepth 1 -name ".*" -type l -delete ''; };
Setup system headers…
sysheaders = buildEnv { name = "headers"; paths = [ pkgs.libcxx ] ++ lib.optional (hostPlatform.isDarwin && big && allowUnfree) "${apple_sdk}/usr"; };
Setup some Apple frameworks.
apple_sdk = "${pkgs.darwin.xcode}/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"; sysframeworks = buildEnv { name = "frameworks"; paths = lib.optionals (hostPlatform.isDarwin && big && allowUnfree) [ "${apple_sdk}/System/Library/Frameworks" "${apple_sdk}/System/Library/PrivateFrameworks" ]; };
Setup schemas…
schemas = writeText "schemas.xml" '' <locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0" > <documentElement localName="section" typeId="DocBook"/> <documentElement localName="chapter" typeId="DocBook"/> <documentElement localName="article" typeId="DocBook"/> <documentElement localName="book" typeId="DocBook"/> <typeId id="DocBook" uri="${pkgs.docbook5}/xml/rng/docbook/docbookxi.rnc" /> </locatingRules> '';
Full list of packages that will be made available.
userPackages = (with pkgs; [ # From common-path.nix coreutils findutils diffutils gnused gnugrep gawk gnutar gzip bzip2 gnumake bash patch xz # Helpful core tools curl zsh cacert file lsof pstree which rsync unzip man openssh less calc ag ripgrep # sqlite tree # cvs # gnuplot # subversion # gnupg # watchman # (pkgs.git.override { withManual = true; }) # Nix tools nix-zsh-completions # nix # nix-index ] ++ lib.optionals big ([ # Useful tools isync notmuch graphviz indent graphviz imagemagick bazaar mercurial # Programming interpreters/compilers myTex rEnv perl python lua coq ocaml openjdk nodejs gcc gdb travis v8 # Disabled # gcal ocrad mailutils dirmngr jwhois moe ] ++ (with netbsd; [ getent getconf ]) # games ++ (with nodePackages; [ tern heroku node2nix ]) ++ (with gitAndTools; [ hub ]) ++ (with haskellPackages; [ ghc jq nix-diff cabal2nix cabal-install ]) ++ (with unixtools; [ utillinux nettools procps ]) ));
Setup global environment variables & directories. Most of the global directories will not exist, but the way search paths work, means that is okay. We aim to support all directories in a common system, prioritizing ones that the user has the most direct access to.
global-dirs = [ # "~/.nix-profile" # "~/.local" "/nix/var/nix/profiles/default" "/run/wrappers" "/run/current-system/sw" "/usr/local" "/usr" "" ]; PATH = lib.concatStringsSep ":" [ (lib.makeBinPath ([ bins customEmacsPackages.emacs pkgs.zsh ] ++ global-dirs)) (lib.makeSearchPath "sbin" [ "/usr" "" ]) ]; MANPATH = ":" + lib.makeSearchPathOutput "man" "share/man" ([ manpages customEmacsPackages.emacs pkgs.zsh ] ++ global-dirs); INFOPATH = "${infopages}/share/info"; XDG_DATA_DIRS = lib.makeSearchPathOutput "xdg" "share" ([ xdg-data ] ++ global-dirs);
The actual environment.
in buildEnv { name = "bauer"; buildInputs = [ pkgs.makeWrapper pkgs.bash ]; postBuild = '' mkdir -p $out/etc substituteAll ${./zshrc.sh} $out/etc/.zshrc substituteInPlace $out/etc/.zshrc \ --subst-var-by completions ${zsh-completions} ln -s $out/etc/.zshrc $out/etc/zshrc makeWrapper ${pkgs.zsh}/bin/zsh $out/bin/zsh --set ZDOTDIR $out/etc substituteAll ${./etc-profile.sh} $out/etc/profile substitute ${./runemacs.sh} $out/bin/run \ --subst-var-by emacs ${myEmacs} chmod +x $out/bin/run patchShebangs $out/bin/run ln -s $out/bin/run $out/bin/bauer ''; pathsToLink = [ "/bin" "/etc/profile.d" "/share/applications" ] ++ lib.optional hostPlatform.isDarwin "/Applications"; meta = with lib; { description = "Bauer's automated unified Emacs realm"; maintainers = with maintainers; [ matthewbauer ]; platforms = platforms.all; }; passthru = with lib; { shellPath = "/bin/zsh"; run = "/bin/run"; sourceFile = "/etc/profile.d/profile"; PATH = makeSearchPath "bin" [bins]; MANPATH = makeSearchPath "share/man" [manpages]; INFOPATH = makeSearchPath "share/info" [infopages]; XDG_DATA_DIRS = makeSearchPath "share" [xdg-data]; }; paths = [ myEmacs (runCommand "my-profile" { emacs = myEmacs; inherit (pkgs) cacert; # fortune inherit PATH MANPATH XDG_DATA_DIRS INFOPATH; } '' mkdir -p $out/etc/profile.d substituteAll ${./profile.sh} $out/etc/profile.d/my-profile.sh substituteInPlace $out/etc/profile.d/my-profile.sh \ --subst-var-by PATH ${PATH} \ --subst-var-by INFOPATH ${INFOPATH} \ --subst-var-by MANPATH ${MANPATH} \ --subst-var-by XDG_DATA_DIRS ${XDG_DATA_DIRS} '') ]; }
Invoking it
We can build it with nix-build
.
nix-build ./result/bin/run
Continuous integration
We’ll set up Travis support here. We start by configuring .travis.yml
.
.travis.yml
language: nix
Next we’ll set up nix-build & pass the URL of Nixpkgs with the NIXPKGS
.
script: - nix-build -Q --argstr channel $CHANNEL
Setup the OSs. Sadly no Windows support yet.
git: depth: 1
Setup some values for NIXPKGS
variables.
matrix: include: - os: linux dist: trusty env: CHANNEL=nixos-19.03 - os: linux dist: trusty env: CHANNEL=nixos-unstable - os: osx env: CHANNEL=nixpkgs-19.03-darwin - os: osx env: CHANNEL=nixpkgs-unstable
Setup the cache.
cache: directories: - /nix/store
Turn off those annoying Travis notifications.
notifications: email: false
Extra
update.sh
This is a simple script that I use to make sure I’ve updated the generated files.
emacs --batch \
-l ob-tangle \
--eval "(org-babel-tangle-file \"README.org\")"
emacs README.org --batch -f org-html-export-to-html
.gitignore
If you end up with generated files, they’re easy to remove with Git. Just run
git clean -xdf
& it will remove all of the files that match the .gitignore
rules (which should never be added to the git tree).
These set up some paths for .gitignore
that we don’t want getting put in
the repo. Start with Emacs/org-mode/LaTeX stuff.
flycheck_*.el *.elc *.pdf *.html *.tex *.log *.aux *.out *.toc
Nix-related stuff.
# nix stuff result result-*
These are all tangled by README.org.
README.el bauer.nix zshrc.sh etc-profile.sh runemacs.sh gitconfig gitignore default.el profile.sh site-paths.el.in org-init.el org-src-* configuration.nix install auto/ *~
.gitattributes
config.nix linguist-generated=true default.nix linguist-generated=true bootstrap.sh linguist-generated=true install linguist-generated=true update.sh linguist-generated=true .travis.yml linguist-generated=true .gitattributes linguist-generated=true .gitignore linguist-generated=true module.nix linguist-generated=true
init.el
You can use this as your Emacs init file:
(load (expand-file-name "settings.el" user-emacs-directory) t) (package-initialize) (defvar bauer-dir (expand-file-name ".emacs.d" (getenv "HOME"))) (defvar bauer-org (expand-file-name "README.org" bauer-dir)) (add-to-list 'load-path (expand-file-name "site-lisp" bauer-dir)) (unless (file-exists-p (expand-file-name "README.el" bauer-dir)) (let ((default-directory bauer-dir)) (autoload 'org-babel-tangle-file "ob-tangle") (org-babel-tangle-file bauer-org "README.el" "emacs-lisp"))) (load (expand-file-name "README.el" bauer-dir) t)
NixOS module
I’ve provided a module suitable for use with a NixOS configuration. To use it, just add something like the following to your configuration.nix file.
# -*- mode: nix; coding: utf-8; -*- { ... }: { imports = [ (builtins.fetchurl "https://matthewbauer.us/bauer/module.nix") ]; programs.bauer.enable = true; }
The actual module implementation follow here. It will pull in some files needed for all of this to work. It should provide ‘bauer’ as a runnable command.
# -*- mode: nix; coding: utf-8; -*- { config, lib, pkgs, ... }: with lib; let ensure = f: n: if builtins.pathExists f then f else builtins.fetchurl "https://matthewbauer.us/bauer/${n}"; bauer = import (ensure ./default.nix "default.nix") { inherit pkgs; }; in { options = { programs.bauer = { enable = mkOption { default = false; type = types.bool; }; }; }; config = mkIf config.programs.bauer.enable { environment = { systemPackages = [ bauer ]; variables = with lib; { PATH = [bauer.PATH]; XDG_DATA_DIRS = [bauer.XDG_DATA_DIRS]; MANPATH = [bauer.MANPATH]; INFOPATH = [bauer.INFOPATH]; }; }; }; }
NixOS virtualbox & installer
# -*- mode: nix; coding: utf-8; -*- { system ? builtins.currentSystem }: let ensure = f: n: if builtins.pathExists f then f else builtins.fetchurl "https://matthewbauer.us/bauer/${n}"; in { ova = (import <nixpkgs/nixos/lib/eval-config.nix> { inherit system; modules = [ <nixpkgs/nixos/modules/installer/virtualbox-demo.nix> (ensure ./module.nix "module.nix") ]; }).config.system.build.virtualBoxOVA; iso = (import <nixpkgs/nixos/lib/eval-config.nix> { inherit system; modules = [ <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix> (ensure ./module.nix "module.nix") ]; }).config.system.build.isoImage; }
Deploy script
setup() { git stash push git checkout gh-pages } cleanup() { git checkout master git stash pop } setup trap cleanup EXIT git fetch origin git reset --hard origin/gh-pages git merge --no-edit master ./update.sh git add . git commit -m "Regen" git push origin gh-pages
LICENSE
Copyright © 2018-2019 Matthew Bauer
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK