2018-08-31 10:23:54 -04:00
* overview
This is my personal emacs config which currently runs on emacs 26.1 (currently the latest package from the Arch Linux official repos).
I use this for a variety of purposes:
- maintaining my todo list/[[https:/ /en.wikipedia.org/wiki/Getting_Things_Done][GTD]] workflow (org mode)
- unified interface for system administration (dired, shell, git, ediff)
- email (mu4e, work in progress)
- editing some of my favorite languages (R, Lisp, Haskell, Lua, Python)
2018-03-21 21:44:31 -04:00
* ui
2018-07-15 20:51:57 -04:00
** theme
#+BEGIN_SRC emacs-lisp
(use-package spacemacs-theme
:defer t
2018-07-20 00:50:51 -04:00
:config
(setq spacemacs-theme-custom-colors '((lnum . "#64707c"))))
2018-07-15 20:51:57 -04:00
(defvar nd/theme 'spacemacs-dark)
(defvar nd/theme-window-loaded nil)
(defvar nd/theme-terminal-loaded nil)
;; required for emacsclient/daemon setup
(if (daemonp)
(add-hook 'after-make-frame-functions
2018-11-22 00:49:47 -05:00
(lambda (frame)
2018-07-15 20:51:57 -04:00
(select-frame frame)
(if (window-system frame)
(unless nd/theme-window-loaded
(if nd/theme-terminal-loaded
(enable-theme nd/theme)
(load-theme nd/theme t))
(setq nd/theme-window-loaded t))
(unless nd/theme-terminal-loaded
(if nd/theme-window-loaded
(enable-theme nd/theme)
(load-theme nd/theme t))
(setq nd/theme-terminal-loaded t)))))
(progn
(load-theme nd/theme t)
(if (display-graphic-p)
(setq nd/theme-window-loaded t)
(setq nd/theme-terminal-loaded t))))
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-07-20 02:23:08 -04:00
** modeline
#+BEGIN_SRC emacs-lisp
(use-package spaceline
:ensure t
:config
(require 'spaceline-config)
(setq powerline-default-separator 'arrow
2018-11-22 00:49:47 -05:00
spaceline-buffer-size-p nil)
2018-07-20 02:23:08 -04:00
(spaceline-spacemacs-theme))
(line-number-mode 1)
(column-number-mode 1)
#+END_SRC
*** delight
Used to hide minor modes on the modeline
2018-03-21 21:44:31 -04:00
#+BEGIN_SRC emacs-lisp
2018-07-15 00:04:47 -04:00
(use-package delight
:ensure t)
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-07-20 02:23:08 -04:00
** clean the interface
No need for startup screen, tool/menu/scrollbars, or backups
#+BEGIN_SRC emacs-lisp
(setq inhibit-startup-screen t)
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(setq make-backup-files nil)
(setq auto-save-default nil)
#+END_SRC
** other enhancements
*** popup windows
#+BEGIN_SRC emacs-lisp
(setq pop-up-windows nil) ; no popups (eg ediff)
#+END_SRC
*** line wrap
#+BEGIN_SRC emacs-lisp
(set-default 'truncate-lines t)
#+END_SRC
*** smooth scrolling
#+BEGIN_SRC emacs-lisp
(setq scroll-conservatively 100)
#+END_SRC
*** imagemagick
#+BEGIN_SRC emacs-lisp
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))
#+END_SRC
*** yes-no prompt
#+BEGIN_SRC emacs-lisp
(defalias 'yes-or-no-p 'y-or-n-p) ; eliminate yes or no prompt on killing procs
#+END_SRC
* packages
2018-03-21 21:44:31 -04:00
** beacon
#+BEGIN_SRC emacs-lisp
2018-07-15 00:04:47 -04:00
(use-package beacon
:ensure t
:delight
:init
(beacon-mode 1))
2018-03-21 21:44:31 -04:00
#+END_SRC
** whichkey
#+BEGIN_SRC emacs-lisp
2018-07-15 00:04:47 -04:00
(use-package which-key
:ensure t
:delight
:init
(which-key-mode))
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-07-13 20:05:50 -04:00
** helm
#+BEGIN_SRC emacs-lisp
(use-package helm
:ensure t
2018-07-14 20:42:20 -04:00
:delight
2018-07-13 20:05:50 -04:00
:init
(helm-mode 1)
:config
2018-07-20 00:50:51 -04:00
(setq helm-autoresize-max-height 0
2018-11-22 00:49:47 -05:00
helm-autoresize-max-height 40
helm-M-x-fuzzy-match t
helm-buffers-fuzzy-matching t
helm-recentf-fuzzy-match t
helm-semantic-fuzzy-match t
helm-imenu-fuzzy-match t
helm-scroll-amount 8)
2018-07-14 23:36:42 -04:00
(add-to-list 'display-buffer-alist
`(,(rx bos "*helm" (* not-newline) "*" eos)
(display-buffer-in-side-window)
(inhibit-same-window . t)
2018-07-15 00:04:47 -04:00
(window-height . 0.4)))
(helm-autoresize-mode 1)
(require 'helm-config))
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-09-21 01:03:17 -04:00
** helm-swoop
#+BEGIN_SRC emacs-lisp
(use-package helm-swoop
:ensure t)
#+END_SRC
2018-03-21 21:44:31 -04:00
** rainbow-delimiters
#+BEGIN_SRC emacs-lisp
2018-07-15 00:04:47 -04:00
(use-package rainbow-delimiters
:ensure t
:delight
:hook
((prog-mode . rainbow-delimiters-mode)
(inferior-ess-mode . rainbow-delimiters-mode)
2018-09-15 00:18:19 -04:00
(ess-mode . rainbow-delimiters-mode)
(LaTeX-mode . rainbow-delimiters-mode)
(Tex-latex-mode . rainbow-delimiters-mode)))
2018-03-21 21:44:31 -04:00
#+END_SRC
** ace-window
#+BEGIN_SRC emacs-lisp
2018-07-03 22:27:12 -04:00
(use-package ace-window
:ensure t
2018-07-20 00:50:51 -04:00
:config
(setq aw-background t)
2018-07-25 09:43:51 -04:00
(custom-set-faces '(aw-leading-char-face
2018-11-22 00:49:47 -05:00
((t (:foreground "#292b2e"
:background "#bc6ec5"
:height 1.0
:box nil))))))
2018-03-21 21:44:31 -04:00
#+END_SRC
** avy
#+BEGIN_SRC emacs-lisp
(use-package avy
:ensure t
2018-07-20 00:50:51 -04:00
:config
(setq avy-background t))
2018-03-21 21:44:31 -04:00
#+END_SRC
** sudo edit
#+BEGIN_SRC emacs-lisp
(use-package sudo-edit
2018-07-14 23:36:42 -04:00
:ensure t)
2018-03-21 21:44:31 -04:00
#+END_SRC
** undo tree
#+BEGIN_SRC emacs-lisp
2018-07-15 00:04:47 -04:00
(use-package undo-tree
:ensure t
:delight
:config
2018-07-20 00:50:51 -04:00
(setq undo-tree-visualizer-diff t)
2018-07-15 00:04:47 -04:00
(global-undo-tree-mode))
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-06-09 18:31:40 -04:00
** fill-column-indicator
#+BEGIN_SRC emacs-lisp
(use-package fill-column-indicator
:ensure t
2018-07-20 00:50:51 -04:00
:config
(setq fci-rule-use-dashes t)
2018-07-15 00:04:47 -04:00
:hook
(prog-mode . fci-mode))
2018-06-09 18:31:40 -04:00
#+END_SRC
2018-07-03 19:48:50 -04:00
** rainbow
#+BEGIN_SRC emacs-lisp
(use-package rainbow-mode
:ensure t)
#+END_SRC
2018-07-21 14:01:53 -04:00
** async
#+BEGIN_SRC emacs-lisp
(use-package async
:ensure t
2018-07-24 17:18:17 -04:00
:delight dired-async-mode
2018-07-21 14:01:53 -04:00
:init
(dired-async-mode 1))
#+END_SRC
2018-08-06 12:27:26 -04:00
** csv-mode
#+BEGIN_SRC emacs-lisp
(use-package csv-mode
2018-09-18 16:07:40 -04:00
:ensure t
:hook (csv-mode . (lambda () (csv-align-fields nil (point-min) (point-max)))))
2018-08-06 12:27:26 -04:00
#+END_SRC
2018-08-10 10:15:09 -04:00
** markdown-mode
#+BEGIN_SRC emacs-lisp
(use-package markdown-mode
:ensure t)
#+END_SRC
** polymode
#+BEGIN_SRC emacs-lisp
(use-package polymode
:ensure t
:after markdown-mode
:mode
(("\\.Rmd\\'" . poly-markdown+r-mode)
("\\.rmd\\'" . poly-markdown+r-mode))
:config
(require 'poly-R)
(require 'poly-markdown))
#+END_SRC
2018-05-19 14:45:43 -04:00
* library
2018-12-11 20:12:16 -05:00
These is general code that is used throughout the config file. Stored in another file for brevity.
2018-05-19 14:45:43 -04:00
#+BEGIN_SRC emacs-lisp
2018-12-11 20:12:16 -05:00
(org-babel-load-file (expand-file-name "lib/lib.org" nd/conf-dir))
2018-07-14 20:11:10 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
* editing
2018-10-14 16:42:13 -04:00
** tabs and alignment
First things first, don't use spaces and force tabs to 4 chars by default (because...let's compromise on things that don't matter since I am using spaces anyways)
#+BEGIN_SRC emacs-lisp
(setq-default indent-tabs-mode nil
2018-11-22 00:49:47 -05:00
tab-width 4)
2018-10-14 16:42:13 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
** completion
*** company
2018-07-17 23:27:53 -04:00
#+BEGIN_SRC emacs-lisp
(use-package company
:ensure t
2018-07-22 07:37:44 -04:00
:delight " ©"
2018-07-17 23:27:53 -04:00
:config
(setq company-idle-delay 0
2018-11-22 00:49:47 -05:00
company-minimum-prefix-length 3))
2018-07-17 23:27:53 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
*** flycheck
2018-07-17 23:27:53 -04:00
#+BEGIN_SRC emacs-lisp
(use-package flycheck
:ensure t
:hook
2018-07-18 13:45:26 -04:00
(prog-mode . flycheck-mode)
:config
(setq flycheck-check-syntax-automatically '(save
2018-11-22 00:49:47 -05:00
idle-change
mode-enabled)
flycheck-idle-change-delay 2
flycheck-error-list-minimum-level 'warning
flycheck-navigation-minimum-level 'warning))
2018-07-17 23:27:53 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
*** yasnippet
2018-07-17 23:27:53 -04:00
#+BEGIN_SRC emacs-lisp
(use-package yasnippet
:ensure t)
(use-package yasnippet-snippets
:ensure t
:after yasnippet
:hook
((prog-mode . yas-minor-mode))
:config
(yas-reload-all))
#+END_SRC
2018-10-13 11:43:10 -04:00
*** electric pairs
Complete pairs globally. Maybe will add more mode-specific options in addition to defaults (eg =html-mode= )
#+BEGIN_SRC emacs-lisp
2018-11-06 00:38:09 -05:00
;; (electric-pair-mode t)
2018-10-13 11:43:10 -04:00
#+END_SRC
2018-08-19 10:27:55 -04:00
** flyspell
2018-10-11 17:08:13 -04:00
Obviously I am going to use =helm= when I spellcheck something.
2018-08-19 10:27:55 -04:00
#+BEGIN_SRC emacs-lisp
(use-package flyspell-correct-helm
:ensure t
:after (helm flyspell))
#+END_SRC
2018-10-11 17:08:13 -04:00
Additionally, I want to automatically highlight errors whenever =flyspell-mode= is enabled.
#+BEGIN_SRC emacs-lisp
2018-11-22 00:49:47 -05:00
;; (add-hook 'flyspell-mode-hook 'flyspell-buffer)
2018-10-11 17:08:13 -04:00
#+END_SRC
2018-07-18 11:32:57 -04:00
** progmode
#+BEGIN_SRC emacs-lisp
(add-hook 'prog-mode-hook #'prettify-symbols-mode)
2018-08-18 18:07:39 -04:00
(add-hook 'prog-mode-hook #'flyspell-prog-mode)
(setq flyspell-issue-message-flag nil)
2018-07-18 11:32:57 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
** languages
*** elisp
2018-07-18 11:32:57 -04:00
#+BEGIN_SRC emacs-lisp
(add-hook 'emacs-lisp-mode-hook 'company-mode)
#+END_SRC
2018-09-12 16:54:55 -04:00
*** ess
2018-07-18 13:45:26 -04:00
NOTES:
- ess is not considered part of prog-mode for some reason
2018-07-18 15:39:30 -04:00
- ess-mode requires a running R process for company to work
2018-07-18 13:45:26 -04:00
- flycheck requries r-lintr
2018-03-21 21:44:31 -04:00
#+begin_src emacs-lisp
2018-07-18 11:32:57 -04:00
(defun nd/init-ess-company ()
2018-10-10 19:23:21 -04:00
"Set the company backends for ess modes."
2018-07-18 11:32:57 -04:00
(setq-local company-backends '((company-R-objects company-R-args))))
(use-package ess
:ensure t
:init
(load "ess-site")
:hook
2018-07-18 12:06:51 -04:00
((ess-mode . flycheck-mode)
(ess-mode . company-mode)
2018-07-18 11:32:57 -04:00
(ess-mode . nd/init-ess-company)
(ess-mode . prettify-symbols-mode)
2018-07-18 15:39:30 -04:00
(ess-mode . fci-mode)
2018-07-18 11:32:57 -04:00
(inferior-ess-mode . company-mode)
(inferior-ess-mode . nd/init-ess-company)
(inferior-ess-mode . prettify-symbols-mode))
:config
(setq inferior-R-args "--quiet --no-save"
2018-11-22 00:49:47 -05:00
ess-history-file "session.Rhistory"
ess-history-directory (substitute-in-file-name "${XDG_CONFIG_HOME}/r/ ")))
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
*** python
2018-08-31 10:23:54 -04:00
#+BEGIN_SRC emacs-lisp
2018-03-21 21:44:31 -04:00
(elpy-enable)
;; make python tabs 4 chars
(add-hook 'python-mode-hook
(lambda ()
(setq indent-tabs-mode t)
(setq tab-width 4)
2018-12-11 19:59:10 -05:00
(setq python-offset 4)))
2018-10-21 01:18:11 -04:00
(setq python-shell-interpreter "ipython"
python-shell-interpreter-args "--colors=Linux --profile=default")
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-09-12 16:54:55 -04:00
*** haskell
2018-11-18 23:30:26 -05:00
**** major mode and intero
2018-11-08 19:32:54 -05:00
Haskell is covered just with the basic major mode and intero (provides =company= and =flycheck= ) which integrates well with stack.
2018-07-03 19:48:50 -04:00
#+BEGIN_SRC emacs-lisp
(use-package haskell-mode
:ensure t
2018-07-20 00:50:51 -04:00
:config
2018-11-08 19:32:54 -05:00
(setq haskell-interactive-popup-errors nil))
(use-package intero
2018-07-22 07:37:44 -04:00
:ensure t
2018-11-08 19:32:54 -05:00
:after haskell-mode
2018-07-22 07:37:44 -04:00
:hook
2018-11-08 19:32:54 -05:00
(haskell-mode . intero-mode))
2018-07-03 19:48:50 -04:00
#+END_SRC
2018-11-18 23:30:26 -05:00
**** camelCase
The defacto style for haskell mandates camelcase, so use subword mode.
#+BEGIN_SRC emacs-lisp
(add-hook 'haskell-mode-hook #'subword-mode)
#+END_SRC
2018-10-10 19:23:21 -04:00
*** latex
2018-10-11 14:19:49 -04:00
**** flycheck
Flycheck should work out of the box.
2018-10-10 19:23:21 -04:00
#+BEGIN_SRC emacs-lisp
(add-hook 'LaTeX-mode-hook #'flycheck-mode)
(add-hook 'Tex-latex-mode-hook #'flycheck-mode)
2018-10-11 14:19:49 -04:00
#+END_SRC
**** company
There are two backends which (kinda) complement each other. The =company-math= package should privide completion for math symbols and the =company-auctex= package should cover pretty much everything else.
#+BEGIN_SRC emacs-lisp
2018-10-10 19:23:21 -04:00
(defun nd/init-company-auctex ()
"Set the company backends for auctex modes."
(setq-local company-backends '((company-auctex-labels
2018-11-22 00:49:47 -05:00
company-auctex-bibs
company-auctex-macros
company-auctex-symbols
company-auctex-environments
;; company-latex-commands
company-math-symbols-latex
company-math-symbols-unicode))))
2018-10-10 19:23:21 -04:00
(use-package company-math
:ensure t
:after company
:config
(setq company-math-allow-unicode-symbols-in-faces '(font-latex-math-face)
2018-11-22 00:49:47 -05:00
company-math-disallow-latex-symbols-in-faces nil))
2018-10-10 19:23:21 -04:00
(use-package company-auctex
:ensure t
:after (company company-math)
:hook
((LaTeX-mode . company-mode)
(LaTeX-mode . nd/init-company-auctex)
(Tex-latex-mode . company-mode)
(Tex-latex-mode . nd/init-company-auctex)))
#+END_SRC
2018-10-11 14:19:49 -04:00
**** auto-fill-mode
I like having my lines short and readable (also easier to git). Turn on autofill here and also make a nice vertical line at 80 chars (=visual-line-mode= ).
#+BEGIN_SRC emacs-lisp
(defun nd/turn-on-auto-fill-maybe ()
"Prompts user to turn on `auto-fill-mode'."
(when (y-or-n-p "Activate Auto Fill Mode? ")
2018-11-22 00:49:47 -05:00
(turn-on-auto-fill)))
2018-10-11 14:19:49 -04:00
(add-hook 'LaTeX-mode-hook #'nd/turn-on-auto-fill-maybe)
(add-hook 'LaTeX-mode-hook #'fci-mode)
#+END_SRC
2018-10-11 17:08:13 -04:00
**** flyspell
Spell checking is important for prose
#+BEGIN_SRC emacs-lisp
(add-hook 'LaTeX-mode-hook (lambda () (flyspell-mode 1)))
#+END_SRC
2018-03-21 21:44:31 -04:00
* org-mode
2018-12-11 20:16:02 -05:00
My org config is massive and therefore stored in another file.
2018-03-21 21:44:31 -04:00
#+BEGIN_SRC emacs-lisp
2018-12-11 20:16:02 -05:00
(org-babel-load-file (expand-file-name "org/org.org" nd/conf-dir))
2018-10-30 21:25:01 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
* tools
2018-10-09 23:22:42 -04:00
** printing
For some reason there is no default way to get a "print prompt." Instead one needs to either install some third-party helper or make a function like this.
#+BEGIN_SRC emacs-lisp
(defun nd/helm-set-printer-name ()
2018-10-09 23:23:18 -04:00
"Set the printer name using helm-completion to select printer."
2018-10-09 23:22:42 -04:00
(interactive)
(let ((pl (or helm-ff-printer-list (helm-ff-find-printers))))
2018-11-22 00:49:47 -05:00
(if pl (setq printer-name (helm-comp-read "Printer: " pl)))))
2018-10-09 23:22:42 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
** magit
#+BEGIN_SRC emacs-lisp
(use-package magit
:ensure t
:config
:delight auto-revert-mode
(setq magit-push-always-verify nil
2018-11-22 00:49:47 -05:00
git-commit-summary-max-length 50))
2018-09-12 16:50:31 -04:00
#+END_SRC
** dired
*** no confirm
Keeping confirmation enabled does weird stuff with helm. Not ideal at the moment but we shall see if I find something better.
#+BEGIN_SRC emacs-lisp
(setq dired-no-confirm '(move copy))
#+END_SRC
*** compression
Only supports tar.gz, tar.bz2, tar.xz, and .zip by default. Add support for more fun algos such as lzo and zpaq
#+BEGIN_SRC emacs-lisp
(if (file-exists-p "/usr/bin/7z")
2018-11-22 00:49:47 -05:00
(add-to-list 'dired-compress-files-alist
'("\\.7z\\'" . "7z a %o %i")))
2018-09-12 16:50:31 -04:00
(if (file-exists-p "/usr/bin/lrzip")
2018-11-22 00:49:47 -05:00
(progn
(add-to-list 'dired-compress-files-alist
'("\\.lrz\\'" . "lrzip -L 9 -o %o %i &"))
(add-to-list 'dired-compress-files-alist
'("\\.lzo\\'" . "lrzip -l -L 9 -o %o %i &"))
(add-to-list 'dired-compress-files-alist
'("\\.zpaq\\'" . "lrzip -z -L 9 -o %o %i &"))))
2018-09-12 16:50:31 -04:00
;; NOTE: this must be after the shorter lrz algos otherwise it will
;; always default to .lrz and not .tar.lrz
(if (file-exists-p "/usr/bin/lrztar")
2018-11-22 00:49:47 -05:00
(progn
(add-to-list 'dired-compress-files-alist
'("\\.tar\\.lrz\\'" . "lrztar -L 9 -o %o %i &"))
(add-to-list 'dired-compress-files-alist
'("\\.tar\\.lzo\\'" . "lrztar -l -L 9 -o %o %i &"))
(add-to-list 'dired-compress-files-alist
'("\\.tar\\.zpaq\\'" . "lrztar -z -L 9 -o %o %i &"))))
2018-09-12 16:50:31 -04:00
#+END_SRC
*** formatting for humans
make sizes human readable
#+BEGIN_SRC emacs-lisp
(setq dired-listing-switches "-Alh")
#+END_SRC
2018-09-16 14:45:49 -04:00
*** mu4e attachments
By default the included gnus-dired package does not understan mu4e, so override the existing =gnus-dired-mail-buffers= function to fix. This allows going to a dired buffer, marking files, and attaching them interactively to mu4e draft buffers.
#+BEGIN_SRC emacs-lisp
;; from here:
;; https://www.djcbsoftware.nl/code/mu/mu4e/Dired.html#Dired
(require 'gnus-dired)
(eval-after-load 'gnus-dired
'(defun gnus-dired-mail-buffers ()
2018-11-22 00:49:47 -05:00
"Return a list of active mu4e message buffers."
(let (buffers)
2018-09-16 14:45:49 -04:00
(save-current-buffer
2018-11-22 00:49:47 -05:00
(dolist (buffer (buffer-list t))
2018-09-16 14:45:49 -04:00
(set-buffer buffer)
(when (and (derived-mode-p 'message-mode)
2018-11-22 00:49:47 -05:00
(null message-sent-message-via))
(push (buffer-name buffer) buffers))))
2018-09-16 14:45:49 -04:00
(nreverse buffers))))
(setq gnus-dired-mail-mode 'mu4e-user-agent)
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
#+END_SRC
2018-10-03 00:11:05 -04:00
*** directory sized
By default dired uses =ls -whatever= to get its output. This does not have recursive directory contents by default. This nitfy package solves this. This is not on default because navigation is much slower and the du output adds very little in many situations (toggle when needed).
#+BEGIN_SRC emacs-lisp
(use-package dired-du
:ensure t
:config
(setq dired-du-size-format t))
#+END_SRC
2018-10-31 23:23:54 -04:00
*** mounted devices
2018-11-02 00:07:18 -04:00
If dired is to replace all other file managers it must handle devices. This function assumes all my devices are mounted on =/media/$USER= and that udevil is installed. It provides mount and mount/follow ops for all usb removable media and follow/unmount for all mounted devices (note the latter includes things that are not mounted here such as samba drives, which I normally hotkey to my window manager). This /almost/ replicates the functionality of gvfs that I actually use without the bloat; the only missing piece is MPT for android (which will come later).
2018-10-31 23:23:54 -04:00
#+BEGIN_SRC emacs-lisp
2018-11-02 00:07:18 -04:00
(defun nd/helm-devices ()
"Mount, unmount, and navigate to removable media using helm."
2018-10-31 23:23:54 -04:00
(interactive)
2018-11-02 00:07:18 -04:00
(let* ((mounted (mapcar
(lambda (d)
`(,(file-name-base d) . ,d))
(nd/get-mounted-directories)))
(mountable (seq-filter
(lambda (d) (not (member (car d) (mapcar #'car mounted))))
(nd/get-mountable-devices))))
(helm
:sources
(list
(helm-build-sync-source "Mounted Devices"
2018-11-22 00:49:47 -05:00
:candidates mounted
:action
'(("Open" . (lambda (s) (find-file s)))
2018-11-02 00:07:18 -04:00
("Unmount" . (lambda (s) (start-process "unmount" nil "udevil" "unmount" s)))))
(helm-build-sync-source "Mountable Devices"
2018-11-22 00:49:47 -05:00
:candidates mountable
:action
'(("Mount and Follow" . (lambda (s)
2018-11-02 00:07:18 -04:00
(nd/mount-device s)
(find-file (nd/get-mountpoint s))))
("Mount" . (lambda (s) (nd/mount-device s))))))
:buffer "*helm device buffer* "
:prompt "Device: ")))
2018-10-31 23:23:54 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
** mu4e
*** basic
2018-07-10 18:59:31 -04:00
#+BEGIN_SRC emacs-lisp
(require 'mu4e)
2018-09-01 21:02:22 -04:00
2018-07-10 18:59:31 -04:00
(setq mail-user-agent 'mu4e-user-agent
2018-11-22 00:49:47 -05:00
mu4e-maildir "/mnt/data/Mail"
2018-07-15 11:23:55 -04:00
2018-11-22 00:49:47 -05:00
mu4e-attachment-dir "~/Downloads"
2018-07-17 22:49:04 -04:00
2018-11-22 00:49:47 -05:00
mu4e-view-show-images t
mu4e-headers-show-target nil
2018-12-03 21:03:32 -05:00
mu4e-view-show-addresses t
2018-11-22 00:49:47 -05:00
2018-07-17 22:49:04 -04:00
message-kill-buffer-on-exit t
2018-11-22 00:49:47 -05:00
mu4e-change-filenames-when-moving t
2018-07-15 11:23:55 -04:00
2018-11-22 00:49:47 -05:00
mu4e-confirm-quit nil
2018-09-08 20:30:45 -04:00
2018-11-22 00:49:47 -05:00
mu4e-view-prefer-html t
2018-09-14 16:56:09 -04:00
2018-11-22 00:49:47 -05:00
mu4e-compose-dont-reply-to-self t
2018-09-01 21:02:22 -04:00
2018-11-22 00:49:47 -05:00
mu4e-get-mail-command "systemctl --user start mbsync"
2018-09-15 00:18:47 -04:00
2018-11-22 00:49:47 -05:00
user-full-name "Dwarshuis, Nathan J")
2018-09-01 21:02:22 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
*** headers view
2018-09-12 09:15:03 -04:00
#+BEGIN_SRC emacs-lisp
(setq mu4e-headers-fields '((:human-date . 11)
2018-11-22 00:49:47 -05:00
(:flags . 5)
(:from . 22)
(:thread-subject))
mu4e-headers-date-format "%F"
mu4e-headers-time-format "%R"
mu4e-use-fancy-chars nil)
2018-09-12 09:15:03 -04:00
#+END_SRC
2018-09-21 01:59:59 -04:00
*** citing
2018-11-22 00:49:47 -05:00
The citation line should enable history folding in outlook. This is enabled by using 32 underscores followed by the addressing info of the previous message(s).
2018-09-21 01:03:39 -04:00
#+BEGIN_SRC emacs-lisp
;; necessary for the header macros below
(require 'nnheader)
(defun nd/message-insert-citation-header ()
"Insert the header of the reply message."
(let* ((h message-reply-headers)
2018-11-22 00:49:47 -05:00
(sep "________________________________")
(from (concat "From: " (mail-header-from h)))
(date (concat "Sent: " (mail-header-date h)))
(to (concat "To: " user-full-name))
(subj (concat "Subject: " (message-strip-subject-re (mail-header-subject h)))))
(insert (string-join `("" ,sep ,from ,date ,to ,subj "") "\n"))))
2018-09-21 01:03:39 -04:00
(setq message-citation-line-function 'nd/message-insert-citation-header)
#+END_SRC
2018-09-21 01:59:59 -04:00
The default "> " things are annoying when citing old messages.
#+BEGIN_SRC emacs-lisp
(setq message-yank-prefix "")
(setq message-yank-cited-prefix "")
(setq message-yank-empty-prefix "")
#+END_SRC
By default the citation is destroyed (as in totally textified) if it is HTML. I want the links to be preserved, so use html2text and set arguments accordingly. Note that =--body-width=0= is necessary to prevent line breaks from being inserted in the middle of links.
2018-09-16 01:39:21 -04:00
#+BEGIN_SRC emacs-lisp
(setq
mu4e-compose-pre-hook
(lambda ()
(let* ((msg mu4e-compose-parent-message)
2018-11-22 00:49:47 -05:00
(html (and msg (plist-get msg :body-html)))
;; oops, mu4e screwed up
(mu4e-html2text-command
(if (file-exists-p "/usr/bin/html2text")
"html2text --ignore-emphasis --images-to-alt --body-width=0"
'mu4e-shr2text)))
(when (and html mu4e-view-prefer-html (member compose-type '(reply forward)))
;; hackity hack, since the normal mu4e-message-body-text function
;; does not render the desired html, do it here and force the
;; aforementioned function to only look at text by removing
;; the html
(plist-put msg :body-txt (mu4e~html2text-shell msg mu4e-html2text-command))
(plist-put msg :body-html nil)))))
2018-09-16 01:39:21 -04:00
#+END_SRC
2018-09-15 20:33:25 -04:00
*** smtp
#+BEGIN_SRC emacs-lisp
(require 'smtpmail)
2018-09-25 09:01:55 -04:00
;; (require 'smtpmail-async)
2018-09-15 20:33:25 -04:00
;; (require 'secrets)
;; (setq secrets-enabled t)
2018-09-25 09:01:55 -04:00
(setq send-mail-function 'smtpmail-send-it
2018-11-22 00:49:47 -05:00
message-send-mail-function 'smtpmail-send-it)
2018-09-15 20:33:25 -04:00
(add-to-list 'auth-sources (expand-file-name "~/.emacs.d/ .authinfo_mu4e.gpg"))
;; (add-to-list 'auth-sources "secrets:default")
#+END_SRC
2018-09-12 16:50:31 -04:00
*** contexts
2018-09-01 21:02:22 -04:00
I have current have three contexts, personal and two work accounts. The first is a gmail account and the second/third are office365 accounts.
#+BEGIN_SRC emacs-lisp
2018-09-06 22:01:30 -04:00
(setq mu4e-context-policy 'pick-first
2018-11-22 00:49:47 -05:00
mu4e-compose-context-policy 'ask-if-none
mu4e-user-mail-address-list '("natedwarshuis@gmail.com" "ndwarshuis3@gatech.edu" "ndwarsh@emory.edu")
2018-09-06 22:01:30 -04:00
mu4e-contexts
2018-11-22 00:49:47 -05:00
`( ,(make-mu4e-context
:name "personal"
:match-func
(lambda (msg)
(when msg
(let ((pfx (mu4e-message-field msg :maildir)))
(string-prefix-p "/gmail" pfx))))
:vars '((mu4e-trash-folder . "/gmail/trash")
(mu4e-drafts-folder . "/gmail/drafts")
(mu4e-sent-folder . "/gmail/sent")
(mu4e-refile-folder . "/gmail/archive")
(mu4e-sent-messages-behavior . delete)
(smtpmail-stream-type . starttls)
(smtpmail-smtp-server . "smtp.gmail.com")
(smtpmail-smtp-service . 587)
(smtpmail-smtp-user . "natedwarshuis@gmail.com")
(user-mail-address . "natedwarshuis@gmail.com")
(mu4e-maildir-shortcuts .
(("/gmail/inbox" . ?i)
("/gmail/sent" . ?s)
("/gmail/trash" . ?t)
("/gmail/drafts" . ?d)
("/gmail/archive" . ?a)))))
,(make-mu4e-context
:name "gatech"
:match-func
(lambda (msg)
(when msg
(let ((pfx (mu4e-message-field msg :maildir)))
(string-prefix-p "/gatech" pfx))))
:vars '((mu4e-trash-folder . "/gatech/trash")
(mu4e-drafts-folder . "/gatech/drafts")
(mu4e-sent-folder . "/gatech/sent")
(mu4e-refile-folder . "/gatech/archive")
(mu4e-sent-messages-behavior . sent)
(smtpmail-stream-type . starttls)
(smtpmail-smtp-server . "smtp.office365.com")
(smtpmail-smtp-service . 587)
(smtpmail-smtp-user . "ndwarshuis3@gatech.edu")
(user-mail-address . "ndwarshuis3@gatech.edu")
(mu4e-maildir-shortcuts .
(("/gatech/inbox" . ?i)
("/gatech/sent" . ?s)
("/gatech/trash" . ?t)
("/gatech/drafts" . ?d)
("/gatech/archive" . ?a)))))
,(make-mu4e-context
:name "emory"
:match-func
(lambda (msg)
(when msg
(let ((pfx (mu4e-message-field msg :maildir)))
(string-prefix-p "/emory" pfx))))
:vars '((mu4e-trash-folder . "/emory/trash")
(mu4e-drafts-folder . "/emory/drafts")
(mu4e-sent-folder . "/emory/sent")
(mu4e-refile-folder . "/emory/archive")
(mu4e-sent-messages-behavior . sent)
(smtpmail-stream-type . starttls)
(smtpmail-smtp-server . "smtp.office365.com")
(smtpmail-smtp-service . 587)
(smtpmail-smtp-user . "ndwarsh@emory.edu")
(user-mail-address . "ndwarsh@emory.edu")
(mu4e-maildir-shortcuts .
(("/emory/inbox" . ?i)
("/emory/sent" . ?s)
("/emory/trash" . ?t)
2018-09-07 12:12:11 -04:00
("/emory/drafts" . ?d)
2018-11-22 00:49:47 -05:00
("/emory/archive" . ?a)))))))
2018-07-10 18:59:31 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
*** org-mu4e
2018-09-08 20:30:45 -04:00
#+BEGIN_SRC emacs-lisp
(use-package org-mu4e
:after (org mu4e)
:config
(setq
;; for using mu4e in org-capture templates
org-mu4e-link-query-in-headers-mode nil
;; for composing rich-text emails using org mode
org-mu4e-convert-to-html t))
#+END_SRC
2018-09-16 15:17:00 -04:00
*** signature
Signatures take lots of space and make short messages look needlessly clunky, so keep off by default.
#+BEGIN_SRC emacs-lisp
(setq mu4e-compose-signature-auto-include nil
2018-11-22 00:49:47 -05:00
mu4e-compose-signature
(string-join
'("Nathan Dwarshuis"
""
"PhD Student - Biomedical Engineering - Krish Roy Lab"
"Georgia Institute of Technology and Emory University"
"ndwarshuis3@gatech.edu")
"\n"))
2018-09-16 15:17:00 -04:00
#+END_SRC
2018-09-26 21:29:00 -04:00
*** visual-line-mode
By default mu4e adds breaks after 80-ish chars using auto-fill-mode which makes messages look weird when opened. =Visual-line-mode= avoids this problem.
2018-09-21 01:20:07 -04:00
#+BEGIN_SRC emacs-lisp
(add-hook 'mu4e-compose-mode-hook 'turn-off-auto-fill)
(add-hook 'mu4e-compose-mode-hook 'visual-line-mode)
2018-09-26 21:29:00 -04:00
(add-hook 'mu4e-view-mode-hook 'turn-off-auto-fill)
(add-hook 'mu4e-view-mode-hook 'visual-line-mode)
2018-09-21 01:20:07 -04:00
#+END_SRC
2018-11-08 19:41:52 -05:00
*** flyspell
Spell checking is generally a good idea when writing to pointy-haired bosses.
#+BEGIN_SRC emacs-lisp
(add-hook 'mu4e-compose-mode-hook (lambda () (flyspell-mode 1)))
#+END_SRC
2018-09-14 16:39:01 -04:00
** auctex
#+BEGIN_SRC emacs-lisp
(load "auctex.el" nil t t)
(require 'tex-mik)
(setq TeX-view-program-selection '(((output-dvi has-no-display-manager)
2018-11-22 00:49:47 -05:00
"dvi2tty")
((output-dvi style-pstricks)
"dvips and gv")
(output-dvi "xdvi")
(output-pdf "Okular")
(output-html "xdg-open")))
2018-09-14 16:39:01 -04:00
;; remove ugly section size
(setq font-latex-fontify-sectioning 'color)
(add-hook 'LaTeX-mode-hook (lambda () (outline-minor-mode 1)))
(add-hook 'Tex-latex-mode-hook (lambda () (outline-minor-mode 1)))
(use-package outline-magic
:ensure t
:after outline)
#+END_SRC
2018-09-12 16:50:31 -04:00
** bibtex
2018-09-12 16:46:59 -04:00
#+BEGIN_SRC emacs-lisp
2018-09-13 16:44:57 -04:00
(use-package org-ref
:ensure t
:after org
:config
2018-10-02 23:29:01 -04:00
(setq reftex-default-bibliography (expand-file-name "~/BibTeX/master.bib")
2018-11-22 00:49:47 -05:00
org-ref-bibliography-notes (expand-file-name "~/BibTeX/notes.org")
org-ref-default-bibliography (expand-file-name "~/BibTeX/master.bib")))
2018-09-13 16:44:57 -04:00
2018-09-12 16:46:59 -04:00
(use-package helm-bibtex
:ensure t
:after helm
:config
2018-10-02 23:29:01 -04:00
(setq bibtex-completion-bibliography (expand-file-name "~/BibTeX/master.bib")
2018-11-22 00:49:47 -05:00
bibtex-completion-library-path (expand-file-name "~/BibTeX/pdf")
bibtex-completion-pdf-field "File"))
#+END_SRC
** ebib
#+BEGIN_SRC emacs-lisp
(use-package ebib
:ensure t)
2018-09-12 16:46:59 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
** shell
2018-03-21 21:44:31 -04:00
#+begin_src emacs-lisp
(defadvice ansi-term (before force-bash)
2018-07-21 18:41:42 -04:00
(interactive (list "/bin/zsh")))
2018-03-21 21:44:31 -04:00
(ad-activate 'ansi-term)
2018-09-16 23:46:33 -04:00
(defun nd/term-send-raw-escape ()
"Send a raw escape character to the running terminal."
(interactive)
(term-send-raw-string "\e"))
2018-03-21 21:44:31 -04:00
#+END_SRC
2018-09-12 16:50:31 -04:00
** ediff
2018-03-21 21:44:31 -04:00
#+BEGIN_SRC emacs-lisp
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
#+END_SRC
2018-07-14 20:42:20 -04:00
* keybindings
2018-07-21 17:30:35 -04:00
For the sake of my sanity, all bindings go here. Note this means I don't use =:bind= in use-package forms.
2018-12-03 20:52:20 -05:00
** setup
Most of my modifiers are reloacted using xkb and xcape. Below is a summary where each item is in the form <original key > -> <new key action > (<key release action if used >)
- tab -> l_super (tab)
- backslash -> r_super (backslash)
- caps -> l_ctrl (escape)
- return -> r_ctrl (return)
- l_ctrl -> l_hyper
- l_super -> iso_l3_shift (xf86search)
- space -> r_alt (space)
- r_alt -> r_hyper
- r_ctrl -> caps
2018-07-14 20:42:20 -04:00
** evil
I like being evil. All package and custom bindings go here.
2018-07-21 17:30:35 -04:00
*** base
2018-07-14 20:42:20 -04:00
#+BEGIN_SRC emacs-lisp
(use-package evil
:ensure t
:init
;; this is required to make evil collection work
(setq evil-want-integration nil)
:config
2018-07-21 17:30:35 -04:00
(evil-mode 1))
#+END_SRC
2018-09-11 08:26:05 -04:00
*** motion
By default, emacs counts a sentence as having at least 2 spaces after punctuation. Make this behave more like vim.
#+BEGIN_SRC emacs-lisp
(setq sentence-end-double-space nil)
#+END_SRC
2018-11-08 19:32:54 -05:00
*** evil state defaults
Some modes use primitive emacs bindings by default. Educate them.
#+BEGIN_SRC emacs-lisp
(add-to-list 'evil-motion-state-modes 'ess-help-mode)
(add-to-list 'evil-insert-state-modes 'inferior-ess-mode)
#+END_SRC
2018-08-19 10:27:55 -04:00
*** enhancements
delightfully ripped off from vim plugins
**** surround
2018-08-18 18:06:18 -04:00
#+BEGIN_SRC emacs-lisp
(use-package evil-surround
:ensure t
:after evil
:config
(global-evil-surround-mode 1))
#+END_SRC
2018-09-06 20:37:44 -04:00
**** commentary
#+BEGIN_SRC emacs-lisp
(use-package evil-commentary
:ensure t
:after evil
:delight
:config
(evil-commentary-mode))
#+END_SRC
**** replace with register
#+BEGIN_SRC emacs-lisp
(use-package evil-replace-with-register
:ensure t
:after evil
:config
(evil-replace-with-register-install))
#+END_SRC
2018-07-21 17:30:35 -04:00
*** unbind emacs keys
Some of these commands just get in the way of being evil (which really means that I keep pressing them on accident). Rather than nullifying them completely, tuck them away in the emacs state map in case I actually want them.
#+BEGIN_SRC emacs-lisp
(mapc (lambda (k) (nd/move-key global-map evil-emacs-state-map (eval k)))
2018-11-22 00:49:47 -05:00
'((kbd "C-s")
(kbd "C-p")
(kbd "C-n")
(kbd "C-f")
(kbd "C-b")
(kbd "C-a")
(kbd "C-e")
(kbd "C-<SPC >")
(kbd "C-x C-;")
(kbd "C-x C-l")
(kbd "C-x C-u")
(kbd "C-x C-z")
(kbd "C-x C-c")
(kbd "M-c")
(kbd "M-d")
(kbd "M-e")
(kbd "M-r")
(kbd "M-f")
(kbd "M-h")
(kbd "M-j")
(kbd "C-M-j")
(kbd "M-k")
(kbd "M-l")
(kbd "M-m")
(kbd "M-q")
(kbd "M-w")
(kbd "M-t")
(kbd "M-u")
(kbd "M-i")
(kbd "M-z")
(kbd "M-v")
(kbd "M-/")
(kbd "M-;")
(kbd "M-DEL")))
2018-07-14 20:42:20 -04:00
#+END_SRC
*** evil-org
#+BEGIN_SRC emacs-lisp
(use-package evil-org
:ensure t
2018-07-14 22:16:32 -04:00
:after (evil org)
2018-07-14 20:42:20 -04:00
:delight
:config
2018-07-15 00:08:00 -04:00
(add-hook 'org-mode-hook 'evil-org-mode)
2018-07-14 22:32:34 -04:00
(add-hook 'evil-org-mode-hook 'evil-org-set-key-theme)
2018-07-14 20:42:20 -04:00
(require 'evil-org-agenda)
(evil-org-agenda-set-keys)
;; some of the defaults bug me...
(evil-define-key 'motion org-agenda-mode-map
2018-11-22 00:49:47 -05:00
"t" 'nd/toggle-project-toplevel-display
"D" 'org-agenda-day-view
"W" 'org-agenda-week-view
"M" 'org-agenda-month-view
"Y" 'org-agenda-year-view
"ct" nil
"sC" 'nd/org-agenda-filter-non-context
"sE" 'nd/org-agenda-filter-non-effort
"sD" 'nd/org-agenda-filter-delegate
"sP" 'nd/org-agenda-filter-non-peripheral
"e" 'org-agenda-set-effort
"ce" nil))
2018-07-14 20:42:20 -04:00
#+END_SRC
2018-07-20 02:47:34 -04:00
*** evil-magit
#+BEGIN_SRC emacs-lisp
(use-package evil-magit
:ensure t
:after (evil magit))
#+END_SRC
2018-07-21 14:01:53 -04:00
*** visual line mode
This is somewhat strange because all I really care about is moving between lines and to the beginning and end as normal. However, I like the idea of thinking of paragraphs as one line (eg df. deletes a sentence even if on multiple lines). Opinion subject to change.
#+BEGIN_SRC emacs-lisp
2018-07-21 17:30:35 -04:00
(evil-define-key '(normal visual) 'visual-line-mode
2018-07-21 14:01:53 -04:00
"j" 'evil-next-visual-line
"k" 'evil-previous-visual-line
"0" 'beginning-of-visual-line
"$" 'end-of-visual-line)
#+END_SRC
2018-11-08 19:32:54 -05:00
*** comint
Comint-based inferior modes often are not evil (eg =intero= and =ESS= ). Configure this similarly to term (see below) where C-j/k navigate cmd history and insert mode goes to cmd input line.
**** interactive functions
Some common interactive functions for comint-based modes
2018-07-21 21:53:56 -04:00
#+BEGIN_SRC emacs-lisp
2018-11-08 19:32:54 -05:00
(defun nd/comint-char-mode-evil-insert ()
2018-07-21 21:53:56 -04:00
"If not at the last line, go to the end of the buffer and enter insert mode. Else just enter insert mode."
(interactive)
(if (/= (line-number-at-pos (point)) (line-number-at-pos (point-max)))
2018-11-22 00:49:47 -05:00
(goto-char (point-max))))
2018-11-08 19:32:54 -05:00
(defun nd/comint-send-input-evil-insert (&optional send-input-cmd)
"Go into insert mode after calling SEND-INPUT-CMD which is usually
the function that send the command to the interactive process in the
REPL. If no SEND-INPUT-CMD then `comint-send-input' is used."
2018-07-21 21:53:56 -04:00
(interactive)
2018-11-08 19:32:54 -05:00
(if send-input-cmd (funcall send-input-cmd) (comint-send-input))
2018-07-21 21:53:56 -04:00
(evil-insert 1))
2018-11-08 19:32:54 -05:00
(evil-define-key '(normal insert) comint-mode-map
2018-08-01 11:39:47 -04:00
(kbd "C-k") 'comint-previous-input
(kbd "C-j") 'comint-next-input)
2018-11-08 19:32:54 -05:00
#+END_SRC
**** ess
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal inferior-ess-mode-map
(kbd "RET") (lambda () nd/comint-send-input-evil-insert
'inferior-ess-send-input))
2018-07-21 21:53:56 -04:00
(add-hook 'inferior-ess-mode-hook
2018-11-22 00:49:47 -05:00
(lambda ()
(add-hook 'evil-insert-state-entry-hook
'nd/comint-char-mode-evil-insert nil t)))
2018-11-08 19:32:54 -05:00
#+END_SRC
**** intero
#+BEGIN_SRC emacs-lisp
(evil-define-key 'normal intero-repl-mode-map
(kbd "RET") 'nd/comint-send-input-evil-insert)
(add-hook 'intero-repl-mode-hook
2018-11-22 00:49:47 -05:00
(lambda ()
(add-hook 'evil-insert-state-entry-hook
'nd/comint-char-mode-evil-insert nil t)))
2018-07-21 21:53:56 -04:00
#+END_SRC
2018-07-14 20:42:20 -04:00
*** collection
2018-07-21 17:30:35 -04:00
Most packages that don't have an evil version are in this one. I don't like surprises so I set =evil-collection-modes-list= with the modes I actually want. Some of these are further configured below.
2018-07-14 20:42:20 -04:00
#+BEGIN_SRC emacs-lisp
(use-package evil-collection
:ensure t
:after evil
:init
2018-09-14 16:39:01 -04:00
(setq evil-collection-mode-list
2018-11-22 00:49:47 -05:00
'(company dired ediff flycheck helm minibuffer mu4e term which-key))
2018-07-20 00:50:51 -04:00
(setq evil-collection-setup-minibuffer t)
2018-07-14 22:05:02 -04:00
:config
(evil-collection-init))
2018-07-14 20:42:20 -04:00
#+END_SRC
2018-07-20 00:33:40 -04:00
**** dired
2018-07-21 17:30:35 -04:00
Dired makes new buffers by default. Use =find-alternate-file= to avoid this.
2018-07-20 00:33:40 -04:00
#+BEGIN_SRC emacs-lisp
2018-09-16 23:45:43 -04:00
(defun nd/dired-move-to-parent-directory ()
"Move buffer to parent directory (like 'cd ..')."
(interactive)
(find-alternate-file ".."))
(defun nd/dired-xdg-open ()
"Open all non-text files in external app using xdg-open.
Only regular files are considered."
(interactive)
(let* ((file-list (seq-filter #'file-regular-p (dired-get-marked-files)))
2018-11-22 00:49:47 -05:00
(do-it (if (<= (length file-list) 5)
t
(y-or-n-p "Open more then 5 files? "))))
(when do-it
(mapc
(lambda (f) (let ((process-connection-type nil))
(start-process "" nil "xdg-open" f)))
file-list))))
2018-09-16 23:45:43 -04:00
(defun nd/dired-open-with ()
"Open marked non-text files in external app via open-with dialog
according to mime types as listed in all available desktop files."
(interactive)
(let* ((mf (seq-filter #'file-regular-p (dired-get-marked-files)))
2018-11-22 00:49:47 -05:00
(qmf (mapcar #'shell-quote-argument mf))
(file-mime-list (mapcar (lambda (f) (list f (nd/get-mime-type f))) qmf)))
(if (= (length file-mime-list) 0)
(message "No files selected")
(let* ((first-pair (car file-mime-list))
(last-pairs (cdr file-mime-list))
mime-alist file-list)
(setq file-list (nth 0 first-pair)
mime-alist (nd/get-apps-from-mime (nth 1 first-pair)))
;; if multiple files selected, add to the selection list
(if last-pairs
(progn
(setq file-list (string-join (mapcar #'car file-mime-list) " "))
(dolist (mime (mapcar (lambda (f) (nth 1 f)) last-pairs))
(setq mime-alist (intersection mime-alist
(nd/get-apps-from-mime mime)
:test #'equal)))))
(if (= (length mime-alist) 0)
(let* ((ml (delete-dups (mapcan #'cdr file-mime-list)))
(mls (string-join ml ", ")))
(if (= (length ml) 1)
(message (concat "No apps found for mime type: " mls))
(message (concat "No common apps found for mime types: " mls))))
(helm
:sources (helm-build-sync-source "Apps"
:candidates mime-alist
:action '(("Open" . (lambda (f) (nd/execute-desktop-command f file-list)))))
:buffer "*helm open with* "))))))
2018-09-16 23:45:43 -04:00
(defun nd/dired-sort-by ()
"Sort current dired buffer by a list of choices presented in helm menu.
Note this assumes there are no sorting switches on `dired-ls'"
(interactive)
(let ((sort-alist '(("Name" . "")
2018-11-22 00:49:47 -05:00
("Date" . "-t")
("Size" . "-S")
("Extension" . "-X")
("Dirs First" . "--group-directories-first"))))
(helm
:sources
(helm-build-sync-source "Switches"
:candidates sort-alist
:action
'(("Sort" . (lambda (s) (dired-sort-other (concat dired-listing-switches " " s))))))
:buffer "*helm sort buffer* ")))
2018-09-16 23:45:43 -04:00
2018-07-20 00:54:53 -04:00
(put 'dired-find-alternate-file 'disabled nil)
2018-07-20 00:33:40 -04:00
(evil-define-key 'normal dired-mode-map
"a" 'dired-find-file
2018-12-03 20:56:26 -05:00
"za" 'gnus-dired-attach
2018-09-01 15:49:24 -04:00
"gs" 'nd/dired-sort-by
2018-09-16 23:37:47 -04:00
"^" 'nd/dired-move-to-parent-directory
"q" 'nd/kill-current-buffer
2018-07-20 00:33:40 -04:00
(kbd "<return >") 'dired-find-alternate-file
2018-08-21 22:45:02 -04:00
(kbd "C-<return >") 'nd/dired-xdg-open
2018-09-16 23:37:47 -04:00
(kbd "M-<return >") 'nd/dired-open-with)
2018-07-21 17:30:35 -04:00
#+END_SRC
**** helm
I like tab completion...regardless of what the helm zealots say. This is actually easier and faster because I can just scroll through the source list with j/k and mash TAB when I find the right directory.
#+BEGIN_SRC emacs-lisp
(evil-define-key '(normal insert) helm-map
(kbd "<tab >") 'helm-execute-persistent-action
(kbd "C-<tab >") 'helm-select-action)
2018-07-20 00:33:40 -04:00
#+END_SRC
2018-07-21 18:41:42 -04:00
**** term
Since I use vi mode in my terminal emulator, need to preserve the escape key's raw behavior
#+BEGIN_SRC emacs-lisp
(evil-define-key 'insert term-raw-map
2018-09-16 23:46:33 -04:00
(kbd "<escape >") 'nd/term-send-raw-escape
2018-07-21 18:41:42 -04:00
(kbd "C-<escape >") 'evil-normal-state)
#+END_SRC
2018-07-14 20:42:20 -04:00
** local
2018-12-03 20:52:20 -05:00
These are for mode-specific bindings that can/should be outside of the evil maps above (there are not many, and these may be merged with their evil bretheren in the future).
2018-07-14 20:42:20 -04:00
*** org-mode
#+BEGIN_SRC emacs-lisp
(add-hook 'org-mode-hook
(lambda ()
2018-11-29 17:56:31 -05:00
;; override default TODO timestamp creation to insert the creation date
2018-11-27 23:56:48 -05:00
(local-set-key (kbd "M-S-<return >") 'nd/org-insert-todo-heading-inactive-timestamp)
2018-11-29 17:56:31 -05:00
2018-12-03 20:52:20 -05:00
;; use the hyper keys/vim arrows with the shifters instead of shift/arrows
2018-12-02 01:17:54 -05:00
(local-set-key (kbd "H-k") 'org-shiftup)
(local-set-key (kbd "H-l") 'org-shiftright)
(local-set-key (kbd "H-j") 'org-shiftdown)
(local-set-key (kbd "H-h") 'org-shiftleft)
2018-11-29 17:56:31 -05:00
;; this is just a useful function I made (actually I think I stole)
2018-07-14 20:42:20 -04:00
(local-set-key (kbd "C-c C-x x") 'nd/mark-subtree-done)
2018-11-29 17:56:31 -05:00
;; override default org subtree cloning with something that clones and resets
2018-07-14 20:42:20 -04:00
(local-set-key (kbd "C-c C-x c") 'nd/org-clone-subtree-with-time-shift)))
(add-hook 'org-agenda-mode-hook
(lambda ()
2018-11-24 20:34:23 -05:00
(local-set-key (kbd "C-c C-c") 'org-agenda-set-tags)
2018-12-04 23:28:33 -05:00
(local-set-key (kbd "C-c C-x c") 'nd/org-agenda-clone-subtree-with-time-shift)
2018-11-24 20:34:23 -05:00
(local-set-key (kbd "C-c C-x C-b") 'nd/org-agenda-toggle-checkbox)))
2018-07-14 20:42:20 -04:00
#+END_SRC
2018-12-03 20:52:41 -05:00
*** mu4e
#+BEGIN_SRC emacs-lisp
(define-key mu4e-headers-mode-map (kbd "C-c C-l") 'org-store-link)
(define-key mu4e-view-mode-map (kbd "C-c C-l") 'org-store-link)
#+END_SRC
2018-08-06 12:27:26 -04:00
*** dired
#+BEGIN_SRC emacs-lisp
(define-key dired-mode-map (kbd "C-x g") 'magit)
#+END_SRC
2018-09-13 16:44:57 -04:00
*** helm-prefix
2018-10-11 17:08:13 -04:00
Some of these are useful enough that I make give them a direct binding without requiring a prefix. For now this is fine.
2018-09-13 16:44:57 -04:00
#+BEGIN_SRC emacs-lisp
(define-key helm-command-prefix (kbd "b") 'helm-bibtex)
2018-09-21 01:04:04 -04:00
(define-key helm-command-prefix (kbd "S") 'helm-swoop)
2018-09-13 16:44:57 -04:00
(define-key helm-command-prefix (kbd "<f8 >") 'helm-resume)
#+END_SRC
2018-10-11 17:08:13 -04:00
Give =f= to =nd/helm-flyspell-correct= instead of =helm-multi-files= and give the latter =F= (used much less).
#+BEGIN_SRC emacs-lisp
(define-key helm-command-prefix (kbd "f") 'helm-flyspell-correct)
(define-key helm-command-prefix (kbd "F") 'helm-multi-files)
#+END_SRC
2018-09-14 16:39:01 -04:00
*** outline-magic
#+BEGIN_SRC emacs-lisp
(define-key outline-minor-mode-map (kbd "<tab >") 'outline-cycle)
#+END_SRC
2018-07-14 20:42:20 -04:00
** global
2018-10-10 19:28:58 -04:00
*** function
The function keys are nice because they are almost (not always) free in every mode. Therefore I use these for functions that I need to access anywhere, but not necessary extremely often (because they are out of the way and harder to reach).
2018-07-14 20:42:20 -04:00
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "<f1 >") 'org-agenda)
(global-set-key (kbd "<f2 >") 'org-capture)
2018-07-21 02:44:10 -04:00
(global-set-key (kbd "<f3 >") 'cfw:open-org-calendar)
2018-08-21 22:45:02 -04:00
(global-set-key (kbd "<f4 >") 'org-clock-goto)
(global-set-key (kbd "<f5 >") 'ansi-term)
2018-09-13 16:44:57 -04:00
(global-set-key (kbd "<f8 >") 'helm-command-prefix)
2018-08-22 00:20:31 -04:00
(global-set-key (kbd "C-<f5 >") 'nd/open-urxvt)
2018-07-18 10:35:37 -04:00
(global-set-key (kbd "<f12 >") 'mu4e)
(global-set-key (kbd "C-<f12 >") 'global-hl-line-mode)
2018-07-14 20:42:20 -04:00
(global-set-key (kbd "S-<f12 >") 'display-line-numbers-mode)
2018-10-10 19:28:58 -04:00
#+END_SRC
*** control/meta
#+BEGIN_SRC emacs-lisp
2018-10-10 19:24:03 -04:00
(global-set-key (kbd "C-<SPC >") 'company-complete)
2018-07-14 20:42:20 -04:00
(global-set-key (kbd "C-c e") 'nd/config-visit)
2018-07-14 23:36:42 -04:00
(global-set-key (kbd "C-c r") 'nd/config-reload)
(global-set-key (kbd "C-c s") 'sudo-edit)
2018-07-14 20:42:20 -04:00
(global-set-key (kbd "C-x 2") 'nd/split-and-follow-horizontally)
(global-set-key (kbd "C-x 3") 'nd/split-and-follow-vertically)
2018-07-18 12:06:51 -04:00
(global-unset-key (kbd "C-x c"))
2018-07-18 10:35:37 -04:00
(global-set-key (kbd "C-x k") 'nd/kill-current-buffer)
2018-07-24 17:18:17 -04:00
(global-set-key (kbd "C-x C-d") 'helm-bookmarks)
2018-11-02 00:07:18 -04:00
(global-set-key (kbd "C-x C-c C-d") 'nd/helm-devices)
2018-07-14 23:36:42 -04:00
(global-set-key (kbd "C-x C-f") 'helm-find-files)
(global-set-key (kbd "C-x C-b") 'helm-buffers-list)
2018-09-16 13:22:36 -04:00
(global-set-key (kbd "C-M-S-k") 'nd/close-all-buffers)
(global-set-key (kbd "C-M-S-o") 'nd/org-close-all-buffers)
(global-set-key (kbd "C-M-S-a") 'org-agenda-kill-all-agenda-buffers)
2018-07-18 10:35:37 -04:00
2018-07-14 23:36:42 -04:00
(global-set-key (kbd "M-b") 'nd/switch-to-previous-buffer)
(global-set-key (kbd "M-o") 'ace-window)
(global-set-key (kbd "M-s") 'avy-goto-char)
(global-set-key (kbd "M-x") 'helm-M-x)
2018-07-14 20:42:20 -04:00
#+END_SRC