Before anything else, we need to bootstrap up a working implementation of use-package so that we can install all the other packages that we desire
(setq package-archives
(quote
(("gnu" . "http://elpa.gnu.org/packages/")
("org" . "http://orgmode.org/elpa/")
; ("marmalade" . "http://marmalade-repo.org/packages/")
("melpa" . "http://melpa.milkbox.net/packages/"))))
(package-initialize)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
(customize-set-variable 'use-package-always-ensure t)
Load the string package. We need this for a lot of the other code.
(use-package s)
(use-package evil
:demand t
:init (setq evil-want-integration nil)
:hook (git-commit-mode . evil-insert-state)
:custom
(evil-insert-state-modes
'(comint-mode erc-mode eshell-mode geiser-repl-mode gud-mode
inferior-apl-mode inferior-caml-mode inferior-emacs-lisp-mode
inferior-j-mode inferior-python-mode inferior-scheme-mode
inferior-sml-mode internal-ange-ftp-mode prolog-inferior-mode
reb-mode shell-mode slime-repl-mode term-mode wdired-mode))
:config
(evil-mode)
(add-hook 'git-commit-mode-hook #'evil-insert-state)
(evil-define-operator evil-narrow-op (begin end type)
"Evil indirect *narrow* operator."
(interactive "<R>")
(cond ((buffer-narrowed-p) (widen))
(t (narrow-to-region begin end))))
(define-key evil-motion-state-map (kbd "g n") #'evil-narrow-op))
The general package is a set of convenience scripts for defining key bindings
(use-package general
:custom
(general-default-prefix "SPC")
(general-default-non-normal-prefix "M-SPC")
(general-default-states '(normal insert emacs))
:config
(general-simulate-key "C-c C-c"
:docstring "Run whatever the native mode's C-c C-c command would be"
:name general-simulate-C-c_C-c-in-emacs-state)
(general-define-key
:keymaps 'override
"cc" #'general-simulate-C-c_C-c-in-emacs-state)
(general-define-key
:keymaps 'with-editor-mode-map
"ck" 'with-editor-cancel)
(general-define-key
:infix "x"
:keymaps 'override
"s" 'save-buffer
"B" 'ibuffer
"k" 'kill-this-buffer
"e" 'eval-last-sexp))
(defun avy-jump-link ()
(interactive)
(avy--generic-jump "https://" nil 'pre))
(general-define-key
:prefix 'nil
:infix 'nil
"M-o" 'avy-jump-link)
A set of evil bindings for multiple modes. This should make life less frustrating
(use-package evil-collection
:after evil
:custom
(evil-collection-setup-minibuffer t)
:config
(evil-collection-init))
(use-package which-key
:diminish which-key-mode
:custom
(which-key-show-operator-state-maps t)
:config
(which-key-mode))
(use-package evil-magit
:after (evil magit))
(use-package evil-org
:diminish evil-org-mode
:after (org evil)
:hook ((org-mode . evil-org-mode)
(evil-org-mode . evil-org-set-key-theme)))
Evil indent plus does a great job at handling Python and Haskell source code
(use-package evil-indent-plus
:after evil
:config
(evil-indent-plus-default-bindings))
evil quickscope highlight unique characters in the words around the cursor to identify the best options for using the f/t/F/T keys for navigation. If there is no best single character, it uses a blue highlight to indicate that a 2f/2F will still find the correct word.
(use-package evil-quickscope
:after evil
:config
(global-evil-quickscope-mode 1))
Evil google should make learning evil slightly easier, as it shows the exact regions chosen.
(use-package evil-goggles
:after evil
:config
(evil-goggles-mode))
This package allows for using evil operations on the structure of python statements, instead of just looking at things on a line by line basis. Due to Python’s whitespace sensitive setup, this might be necessary.
(use-package evil-text-object-python
:after evil
:hook (python-mode . evil-text-object-python-add-bindings))
(use-package evil-matchit
:after evil
:config
(global-evil-matchit-mode 1))
(use-package evil-escape
:after evil
:diminish evil-escape-mode
:custom
(evil-escape-unordered-key-sequence t)
(evil-escape-key-sequence "jk")
:config
(evil-escape-mode))
easymotion helps with the fact that I don’t instantly know how many lines or characters I’m looking at 90% of the time when using evil.
(use-package evil-easymotion
:after evil
:config
(evilem-default-keybindings "RET"))
Evil commentary should hopefully give me the commenting options that evil-nerd-commenter sould never get working right
(use-package evil-commentary
:after evil
:config
(evil-commentary-mode))
This should allow for easier number manipulation in evil mode
(use-package evil-numbers
:after evil
:general
(:prefix 'nil :infix "g"
"+" 'evil-numbers/inc-at-pt
"-" 'evil-numbers/dec-at-pt))
Since different computers have different file structures and capabilities, Emacs needs to customise itself for the specific computer that it is running on. To this end, the functions below identify computers and operating systems. This should simplify much of the code.
(defun insert-system-name ()
"Get current system's name."
(interactive)
(insert (format "%s" (system-name))))
(defun insert-system-type ()
"Get the current system OS."
(interactive)
(insert (format "%s" system-type)))
(defun system-is-darwin ()
"Are we on a Mac?"
(string-equal system-type "darwin"))
(defun system-is-windows ()
"Are we on (*shudder*) Windows?"
(string-equal system-type "windows-nt"))
(defun system-is-linux ()
"Are we on Linux?"
(string-equal system-type "gnu/linux"))
(defun system-is-arch ()
"Are we on the Arch Virtualbox?"
(or
(s-starts-with? "NDLT969a" (system-name))
(s-starts-with? "NDW1748" (system-name))))
(defun system-is-sheffield ()
"Are we on the old Sheffield workstation?"
(s-ends-with? "shef.ac.uk" (system-name)))
(defun system-is-macbook ()
"Are we on my Sheffield Macbook?"
(or
(s-starts-with? "adams-mbp" (system-name))
(s-starts-with? "Adams-MBP" (system-name))
(s-starts-with? "Adams-MacBook" (system-name))))
(let
((mypaths
(cond
((system-is-sheffield)
(list
"$NPM_PACKAGES/bin"
"/home/adam/.local/bin"
"/home/adam/bin"
"/usr/local/texlive/2015/bin/x86_64-linux"
"/usr/local/MATLAB/MATLAB_Compiler_Runtime/v82/runtime/glnxa64"
"/usr/local/MATLAB/MATLAB_Compiler_Runtime/v82/bin/glnxa64"
"/usr/local/MATLAB/MATLAB_Compiler_Runtime/v82/sys/os/glnxa64"
"/usr/local/MATLAB/MATLAB_Compiler_Runtime/v82/sys/java/jre/glnxa64/jre/lib/amd64/native_threads"
"/usr/local/MATLAB/MATLAB_Compiler_Runtime/v82/sys/java/jre/glnxa64/jre/lib/amd64/server"
"/usr/local/MATLAB/MATLAB_Compiler_Runtime/v82/sys/java/jre/glnxa64/jre/lib/amd64"
"/home/adam/.cabal/bin"
"/home/adam/.npm-packages/bin/"
"/usr/local/bin"
"/home/adam/Science/LINUX64"
"/opt/maple18/bin"
"/usr/local/cuda-7.5/bin"
"/usr/bin"
"/bin"
(getenv "PATH")))
((system-is-macbook)
(list
"/Users/adam/Library/Python/2.7/bin/"
"/Users/adam/.local/bin/"
"/opt/local/bin"
"/opt/local/sbin"
"/usr/local/bin"
"/usr/bin"
"/bin"
"/usr/sbin"
"/sbin"
"/opt/X11/bin"
"/Library/Frameworks/Mono.framework/Versions/Current/Commands"))
((system-is-arch)
(append
(split-string (getenv "PATH") ":")
(list "~/bin")))
('t (split-string (getenv "PATH") ":")))))
(if
(not (system-is-windows))
(progn
(setenv "PATH" (mapconcat 'identity mypaths ":"))
(setq exec-path (append mypaths (list "." exec-directory))))))
(setq w32-apps-modifier 'super)
Next, let’s get rid of the window chrome. It’s just so ugly.
(tool-bar-mode -1)
(scroll-bar-mode -1)
(menu-bar-mode -1)
Similarly, get rid of the awful startup screen.
(setq inhibit-startup-screen t)
Let’s set the default font and size
(set-fontset-font "fontset-default" nil
(font-spec :size 12 :name "DejaVu Sans"))
(set-fontset-font "fontset-default" nil
(font-spec :size 20 :name "DejaVu Sans"))
Make everything pretty!
(global-prettify-symbols-mode t)
Use diminish to stop minor modes from taking over the entire taskbar.
(use-package diminish
:config
(diminish 'auto-revert-mode "")
(diminish 'auto-fill-mode "")
(diminish 'visual-line-mode "")
(diminish 'flyspell-mode "")
(diminish 'undo-tree-mode "")
(diminish 'auto-fill-function ""))
Always use spaces instead of tabs to avoid complaints from bored people on the internet.
'(indent-tabs-mode nil)
Use the TeX input method to get those glorious unicode characters.
(setq default-input-method "TeX")
(toggle-input-method)
Emacs gives us line numbers by default, but not column numbers. I think that that’s a legacy decision left over from the terminal days? Either way, I disagree with it, so we’ll put the column numbers in.
(setq column-number-mode t)
Tell emacs to treat all themes as safe. This is, honestly, a gapping security hole, but I only install themes from trusted sources and I’m not auditing them as it currently is. Plus, this gets the terrible custom-safe-themes variable out of customize
(setq custom-safe-themes t)
Give a default e-mail address.
(setq user-mail-address "[email protected]")
I don’t like emacs backup files. They’re coarse and rough and irritating, and the get everywhere. I’m going to confine them to a single directory.
(setq backup-by-copying t)
(setq backup-directory-alist (quote (("." . "~/.saves"))))
(setq delete-old-versions t)
(setq kept-new-versions 6)
(setq vc-make-backup-files t)
(setq version-control t)
Load a theme based on my base16 configurations
(load-file "~/Code/dotfiles/base16/emacs")
Dired is a wonderful way of handling directories.
(use-package dired
:commands dired
:custom
(dired-dwim-target t)
(dired-listing-switches "-alh"))
Get dired to intergate with imenu, since that just makes sense.
(use-package dired-imenu)
Direct Quick Sort offers more sorting options than just name and time
(use-package dired-quick-sort
:config
(dired-quick-sort-setup))
Dired-collapse gets rid of annoying chains of single file directories
(use-package dired-collapse)
When eshell can’t find a completion, let fish take a shot at it
(use-package fish-completion
:after eshell
:config
(global-fish-completion-mode))
Load images as images, instead of as bye arrays
(setq auto-image-file-mode t)
Always revert images files without asking.
(setq revert-without-query '(".png"))
(use-package magit
:commands (magit)
:custom
(diff-switches "-u")
(magit-commit-arguments (quote ("--gpg-sign=0D2B93AB0C87BAF1")))
(magit-bury-buffer-function 'magit-mode-quit-window)
:init
(if
(system-is-macbook)
(setq magit-git-executable "/usr/bin/git")))
This package let’s me interface with github through magit. Anything to stay out of the browser.
(use-package magithub
:after magit
:config (magithub-feature-autoinject t))
(use-package ledger-mode
:mode "\\.ledger\\'")
Which-function mode helps me when I’m stuck in some giant routine and lose track of where I am in the program. There’s the function, right there on the modeline.
(which-function-mode 't)
(set-face-foreground 'which-func (face-foreground font-lock-variable-name-face))
Handles the generation of project skeletons
(use-package skeletor
:custom
(skeletor-project-directory "~/Code"))
Set the C♯ compiler for linux
(setq csharp-make-tool "mcs")
Let’s try and make elisp symbols pretty!
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(push '("<=" . ?≤) prettify-symbols-alist)
(push '("**2" . ?²) prettify-symbols-alist)))
(use-package haskell-mode
:mode "\\.hs\\'"
:custom
(haskell-tags-on-save t)
:config
(add-hook
'haskell-mode-hook
(lambda ()
(push '("\\" . ?λ) prettify-symbols-alist)
(push '(">>=" . ?↣) prettify-symbols-alist)
(push '("->" . ?→) prettify-symbols-alist)
(push '("<-" . ?←) prettify-symbols-alist)
(push '("=>" . ?⇒) prettify-symbols-alist)
(push '("not" . ?¬) prettify-symbols-alist)
(push '("==" . ?≟) prettify-symbols-alist)
(push '("/=" . ?≠) prettify-symbols-alist)
(push '("<=" . ?≤) prettify-symbols-alist)
(push '(">=" . ?≥) prettify-symbols-alist)
(push '("=" . ?≡) prettify-symbols-alist)
(push '("pi" . ?π) prettify-symbols-alist)
(push '(">>" . ?≫) prettify-symbols-alist)
(push '("<<" . ?≪) prettify-symbols-alist)
(push '("++" . ?⧺) prettify-symbols-alist)
(push '("*" . ?⋅) prettify-symbols-alist)
(push '(" . " . ?∘) prettify-symbols-alist)
(push '("<*>" . ?⊛) prettify-symbols-alist)
(push '("<+>" . ?⊕) prettify-symbols-alist)
(push '("::" . ?⁝) prettify-symbols-alist))))
I’ve added command line completion for cabal and stack, since I’m too lazy to type out my executable names on my own.
(defconst pcmpl-cabal-commands
'("update" "install" "help" "info" "list" "fetch" "user" "get" "init" "configure" "build"
"clean" "run" "repl" "test" "bench" "check" "sdist" "upload" "report" "freeze" "gen"
"haddock" "hscolour" "copy" "register" "sandbox" "exec" "repl"))
(defun pcmpl-cabal-get-execs ()
(with-temp-buffer
(message "Loading")
(insert (shell-command-to-string "cat *.cabal"))
(goto-char (point-min))
(let ((ref-list))
(while (re-search-forward "^executable +\\(.+\\) *$" nil t)
(message "Insert")
(add-to-list 'ref-list (match-string 1)))
ref-list)))
(defun pcomplete/cabal ()
"Completion for `cabal'"
(pcomplete-here* pcmpl-cabal-commands)
(cond
((pcomplete-match (regexp-opt '("run")) 1)
(pcomplete-here* (pcmpl-cabal-get-execs)))))
(defconst pcmpl-stack-commands
'( "build" "install" "uninstall" "test" "bench" "haddock" "new" "templates" "init" "solver"
"setup" "path" "unpack" "update" "upgrade" "upload" "sdist" "dot" "exec" "ghc" "ghci"
"repl" "runghc" "runhaskell" "eval" "clean" "list" "query" "ide" "docker" "config" "image" "hpc")
"List of Stack Commands")
(defun pcomplete/stack ()
"Completion for `stack'"
(pcomplete-here* pcmpl-stack-commands)
(cond
((pcomplete-match (regexp-opt '("exec")) 1)
(pcomplete-here* (pcmpl-cabal-get-execs)))))
(use-package intero
:hook haskell-mode)
Let’s make our python prettier, too!
(add-hook 'python-mode-hook
(lambda ()
(push '("<=" . ?≤) prettify-symbols-alist)
(push '(">=" . ?≥) prettify-symbols-alist)
(push '("!=" . ?≠) prettify-symbols-alist)
(push '("np.pi" . ?π) prettify-symbols-alist)
(push '("np.sum" . ?Σ) prettify-symbols-alist)
(push '("np.sqrt" . ?√) prettify-symbols-alist)
(push '("sqrt" . ?√) prettify-symbols-alist)
(push '("sum" . ?Σ) prettify-symbols-alist)
(push '("alpha" . ?α) prettify-symbols-alist)
(push '("sigma" . ?σ) prettify-symbols-alist)
(push '("lambda" . ?λ) prettify-symbols-alist)
(push '("**2" . ?²) prettify-symbols-alist)))
(defun switch-to-python (&rest r)
(interactive)
(message "Switching! %S" r)
(switch-to-buffer-other-window "*Python*"))
(advice-add 'run-python :after #'switch-to-python)
Add support to python mode for finding errors
Add mypy for doing type checking
(use-package flycheck-mypy)
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
I need to be able to edit systemd service files.
(use-package systemd)
Add nix-mode for editting nix files
(use-package nix-mode)
We need spell checking in generic Mail mode.
(add-hook 'mail-mode-hook 'flyspell-mode)
Also, there are some generic message mode settings that I need to review again so that I can remember exactly how they work. FIXME
(setq message-send-mail-function 'message-send-mail-with-sendmail)
(setq message-sendmail-envelope-from 'header)
(setq message-sendmail-extra-arguments '("--read-envelope-from"))
(setq message-sendmail-f-is-evil t)
We will use eww
as our default browser, with the option to escape
to firefox if things get bad.
(setq browse-url-browser-function 'eww-browse-url)
I customise the eww bindings to make them more VimFx
(use-package jabber
:commands (jabber-connect jabber-connect-all)
:custom
(jabber-chat-buffer-show-avatar nil)
(jabber-vcard-avatars-retrieve nil)
:config
(setq jabber-account-list
(let
((passwd (funcall (plist-get (car (auth-source-search :max 1 :host "talk.google.com")) :secret))))
`(("[email protected]"
(:port . 5223)
(:password . ,passwd)
(:network-server . "talk.google.com")
(:connection-type . ssl)))))
(progn
(defun x-urgency-hint (frame arg &optional source)
(let* ((wm-hints (append (x-window-property
"WM_HINTS" frame "WM_HINTS" source nil t) nil))
(flags (car wm-hints)))
(setcar wm-hints
(if arg
(logior flags #x100)
(logand flags (lognot #x100))))
(x-change-window-property "WM_HINTS" wm-hints frame "WM_HINTS" 32 t)))
(defun jabber-notify-taffy ()
(if (equal "0" jabber-activity-count-string) t
(progn
;; (notifications-notify
;; :title jabber-activity-make-string
;; :body jabber-activity-count-string)
(x-urgency-hint (selected-frame) t))))
(add-hook 'jabber-chat-mode-hook 'flyspell-mode)
(add-hook 'jabber-activity-update-hook 'jabber-notify-taffy)))
(use-package twittering-mode
:bind (("C-c t" . twit))
:hook (twittering-edit-mode . company-mode)
:custom
(twittering-use-master-password t)
(twittering-timer-interval 30))
(use-package sx)
(defun gnus-keys () (local-set-key ["S-delete"] 'gnus-summary-delete-article))
(use-package gnus
:custom
(gnus-select-method '(nntp "news.gwene.org"))
(send-mail-function (quote smtpmail-send-it))
(sendmail-program "msmtp")
(message-send-mail-function (quote message-send-mail-with-sendmail))
(message-sendmail-envelope-from (quote header))
(message-sendmail-extra-arguments (quote ("--read-envelope-from")))
(message-sendmail-f-is-evil t)
(gnus-secondary-select-methods
(quote
((nnmaildir "Professional" (directory "~/Maildir/Professional"))
(nnmaildir "Work" (directory "~/Maildir/Work"))
(nnmaildir "Personal" (directory "~/Maildir/Personal")))))
:hook (gnus-summary-mode-hook . gnus-keys))
notmuch is a wonderful little utility for managing my mail
(use-package notmuch
;; :bind
;; (:map notmuch-search-mode-map
;; ("a" . my-notmuch-archive))
:commands notmuch
:init
(defun my-notmuch-archive (&optional arg)
(interactive "p")
(kmacro-exec-ring-item (quote ([45 117 110 114 101 97 100 32 45 105 110 98 111 120 return] 0 "%d")) arg))
:custom
(notmuch-archive-tags (quote ("-inbox" "-unread")))
(notmuch-fcc-dirs
(quote
(("[email protected]" . "Personal/[Gmail].Sent Mail")
("[email protected]" . "Work/Sent -inbox -unread +sent"))))
(notmuch-hello-thousands-separator ",")
(notmuch-saved-searches
(quote
((:name "inbox" :query "tag:inbox" :key "i")
(:name "unread" :query "tag:unread" :key "u")
(:name "flagged" :query "tag:flagged" :key "f")
(:name "sent" :query "tag:sent" :key "t")
(:name "drafts" :query "tag:draft" :key "d")
(:name "all mail" :query "*" :key "a")
(:name "Today's mail" :query "date:0d..")
(:name "promotional" :query "to:promotional tag:inbox")
(:name "SasView" :query "Sas from:[email protected]"))))
:custom-face
(notmuch-search-unread-face ((t (:foreground "#859900")))))
(use-package elfeed
:bind (("C-c c" . org-capture))
:commands (elfeed)
:custom
(elfeed-feeds
'(("http://www.xkcd.org/atom.xml" comic)
("http://phdcomics.com/gradfeed.php" comic)
("http://www.merriam-webster.com/wotd/feed/rss2" education)
("http://sachachua.com/blog/feed/" sw emacs)
("https://planet.haskell.org/rss20.xml" sw haskell)
("https://wordsmith.org/awad/rss1.xml" education)
("http://emacsninja.com/feed.atom" sw emacs)
("http://emacshorrors.com/feed.atom" sw emacs)
("https://blogs.msdn.microsoft.com/oldnewthing/feed" sw tech)
("http://endlessparentheses.com/atom.xml" sw emacs)
("http://pragmaticemacs.com/feed/" sw emacs)
("https://www.reddit.com/r/emacs/.rss" sw emacs)
("https://www.reddit.com/r/haskell/.rss" sw haskell)
("https://www.reddit.com/r/julia/.rss" sw julia)
("https://hnrss.org/newest?points=300" sw tech)
("https://yager.io/feed/" sw haskell)
"http://us10.campaign-archive1.com/feed?u=49a6a2e17b12be2c5c4dcb232&id=ffbbbbd930")))
(use-package slack
:commands (slack-start)
:custom
(slack-buffer-emojify t) ;; if you want to enable emoji, default nil
(slack-prefer-current-team t)
:general
(:keymaps 'slack-info-mode-map :infix ","
"u" 'slack-room-update-messages)
(:keymaps 'slack-edit-message-mode-map :infix ","
"k" 'slack-message-cancel-edit
"s" 'slack-message-send-from-buffer
"2" 'slack-message-embed-mention
"3" 'slack-message-embed-channel)
(:keymaps 'slack-mode-map :infix ","
"c" 'slack-buffer-kill
"j" 'slack-buffer-goto-next-message
"k" 'slack-buffer-goto-prev-message
"ra" 'slack-message-add-reaction
"rr" 'slack-message-remove-reaction
"rs" 'slack-message-show-reaction-users
"pl" 'slack-room-pins-list
"pa" 'slack-message-pins-add
"pr" 'slack-message-pins-remove
"mm" 'slack-message-write-another-buffer
"me" 'slack-message-edit
"md" 'slack-message-delete
"u" 'slack-room-update-messages
"2" 'slack-message-embed-mention
"3" 'slack-message-embed-channel)
:config
(slack-register-team
:name "SasView"
:client-id "165525662918.164903213860"
:client-secret (funcall (plist-get (car (auth-source-search :max 1 :host "sasview.slack.com")) :secret))
:token (funcall (plist-get (car (auth-source-search :max 1 :host "token.sasview.slack.com")) :secret))
:subscribed-channels '(general random build github trac jenkins)))
Tramp is emacs’ builtin system for handling remote files
(use-package tramp
:config
(setq my-tramp-ssh-completions
'((tramp-parse-sconfig "~/.ssh/config")
(tramp-parse-sknownhosts "~/.ssh/known_hosts")))
(mapc
(lambda (method)
(tramp-set-completion-function method my-tramp-ssh-completions))
'("fcp" "rsync" "scp" "scpc" "scpx" "sftp" "ssh" "sshx")))
EUDC is the LDAP client for emacs. It should allow me to query the directory of STFC.
(use-package eudc
:commands
(eudc-get-email eudc-get-phone eudc-query-form)
:custom
(eudc-server-hotlist (quote (("126.0.0.1:1389" . ldap))))
:config
(setq ldap-host-parameters-alist
`(("127.0.0.1:1389"
base "ou=people"
binddn "CLRC\\auv61894"
passwd ,(funcall (plist-get (car (auth-source-search :max 1 :host "127.0.0.1" :port 1389)) :secret))
auth simple))))
Excorporate pulls calendar data from an exchange server. I’ve then written way too much code to allow this to interface with the org-mode agenda, allowing me to insert my outlook agenda directly into org.
(use-package excorporate
:commands excorporate
:custom
(excorporate-configuration "[email protected]"))
This is my little code to put my Exchange calendar into my org-agenda. It’s probably horribly broken. Additionally, it depends on latch.el, which isn’t available as a package and had to be installed manually.
At some point, I need to turn this into a proper package.
(add-to-list 'load-path "/home/adam/.emacs.d/scripts")
(require 'latch)
(defun excorporate-first-meeting (&optional mark)
(if exco--connections
(let
((meeting (car-safe (adam-get-meetings date))))
(if meeting
(format
"%s %s"
(if (plist-get meeting 'all-day)
""
(adam-relative-date-format
(plist-get meeting 'start)
(plist-get meeting 'stop)
date))
(plist-get meeting 'subject))))))
(defun excorporate-second-meeting (&optional mark)
(if exco--connections
(let
((meeting (car-safe (cdr-safe (adam-get-meetings date)))))
(if meeting
(format
"%s %s"
(if (plist-get meeting 'all-day)
""
(adam-relative-date-format
(plist-get meeting 'start)
(plist-get meeting 'stop)
date))
(plist-get meeting 'subject))))))
(defun adam-relative-date-format (begin end local)
(pcase-let
((`(,month ,day ,year) local)
(`(,es ,em ,eh ,eD ,eM ,eY) begin)
(`(,bs ,bm ,bh ,bD ,bM ,bY) end))
(cond
((and (= day eD) (= month eM) (= year eY)
(= day bD) (= month bM) (= year bY))
(format "%2d:%02d--%2d:%02d" bh bm eh em))
((and (= day eD) (= month eM) (= year eY))
(format "%2d:%02d" eh em))
((and (= day bD) (= month bM) (= year bY))
(format "%2d:%02d" bh bm))
"")))
(defun adam-parse-calendar-item (item)
(setq result '(all-day ()))
(dolist (key item result)
(if (listp key)
(cond
((eq 'Subject (car key))
(setq result
(plist-put result 'subject (cdr key))))
((eq 'End (car key))
(setq result
(plist-put result 'stop
(decode-time (date-to-time (cdr key))))))
((eq 'IsAllDayEvent (car key))
(setq result
(plist-put result 'all-day (cdr key))))
((eq 'Start (car key))
(setq result
(plist-put result 'start
(decode-time (date-to-time (cdr key))))))))))
(defun adam-get-meetings (date)
(lexical-let
((promise (make-promise))
(month (car date))
(day (cadr date))
(year (caddr date)))
(exco-get-meetings-for-day
"[email protected]"
month day year
(lambda (ident resp) (deliver promise resp)))
(-filter
(lambda (x)
(pcase-let
((`(,second ,minute ,hour ,date)
(plist-get x 'stop)))
(not
(and (eq date day) (eq hour 0) (eq minute 0)))))
(mapcar #'adam-parse-calendar-item
(cdar (last (car (last (cdr (cadaar (retrieve promise)))))))))))
(use-package org
:ensure org-plus-contrib
:bind (("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c b" . org-iswitchb))
:hook
((org-mode-hook . auto-fill-mode)
(org-mode-hook . flyspell-mode))
:general
(:keymaps 'org-mode-map :infix "c"
"'" 'org-edit-special
"vt" 'org-babel-tangle
"d" 'org-deadline
"s" 'org-schedule
"e" 'org-export-dispatch)
:custom
(org-agenda-files
(quote
("~/org/sync.org"
"~/org/appointments.org"
"~/org/personal-notes.org")))
(calendar-latitude 53.3836)
(calendar-longitude 1.4669)
(org-agenda-window-setup 'current-window)
(org-agenda-start-on-weekday nil)
(org-return-follows-link t)
(org-imenu-depth 4)
(org-agenda-start-on-weekday nil)
(org-babel-load-languages (quote ((emacs-lisp . t) (python . t))))
(org-confirm-babel-evaluate nil)
(org-src-fontify-natively t)
(org-agenda-include-diary nil)
(org-src-preserve-indentation t)
(org-table-convert-region-max-lines 99999)
(org-agenda-day-face-function (quote jd:org-agenda-day-face-holidays-function))
(org-file-apps
(quote
((auto-mode . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . system))))
(org-capture-templates
(quote
(("m" "Unsorted Mail Tasks" entry
(file+headline "~/org/appointments.org" "Unsorted Mail")
"** TODO%?\n SCHEDULED:%T\n\n %a")
("v" "Vocab" entry
(file+headline "~/org/appointments.org" "Vocab")
"** TODO %a\n SCHEDULED:%T%?\n\n %a"))))
(org-latex-listings (quote minted))
(org-latex-packages-alist (quote (("" "minted" nil))))
(org-latex-pdf-process
(quote
("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f")))
(holiday-other-holidays
(quote
(
(holiday-float 5 1 -1 "Spring Bank Holiday")
(holiday-float 5 1 1 "May Day Bank Holiday")
(holiday-float 8 1 -1 "Late Summer Bank Holiday")
)))
(org-agenda-custom-commands
'(("c" . "My Custom Agendas")
("cu" "Unscheduled TODO"
((todo ""
((org-agenda-overriding-header "\nUnscheduled TODO")
(org-agenda-skip-function '(org-agenda-skip-entry-if 'timestamp)))))
nil
nil)))
:custom-face
(org-table ((t (:inherit 'fixed-pitch))))
(org-block ((t (:inherit 'fixed-pitch))))
(org-block-begin-line ((t (:inherit 'fixed-pitch))))
(org-block-end-line ((t (:inherit 'fixed-pitch))))
(org-verbatim ((t (:inherit 'fixed-pitch))))
:config
(add-hook 'org-mode-hook
(lambda ()
(face-remap-add-relative 'default :inherit 'variable-pitch)))
(defun adam-org-sunrise ()
(concat
(nth 1 (split-string (diary-sunrise-sunset)))
" Sunrise for "
(string-remove-prefix "(" (nth 9 (split-string (diary-sunrise-sunset))))))
(defun adam-org-sunset ()
(concat
(nth 4 (split-string (diary-sunrise-sunset)))
" Sunset"))
(defface org-agenda-date-beam
`((t :foreground ,(face-attribute 'font-lock-keyword-face :foreground)
:inherit org-agenda-date))
"Face used for agenda entries on days when the ISIS beam is on"
:group 'org-faces)
(defface org-agenda-date-beam-weekend
`((t :foreground ,(face-attribute 'font-lock-keyword-face :foreground)
:inherit org-agenda-date-weekend))
"Face used for agenda entries on days when the ISIS beam is on"
:group 'org-faces)
(defun my-org-agenda-day-face-holidays-function (date)
"Compute DATE face for holidays."
(unless (org-agenda-todayp date)
(letrec
((day-of-week (calendar-day-of-week date))
(weekend (or (= day-of-week 0)
(= day-of-week 6)))
(files (org-agenda-files nil 'ifmode))
(entries (-flatten
(-map
(lambda (file) (org-agenda-get-day-entries file date))
files)))
(categories (-flatten (-map (lambda (entry)
(with-temp-buffer
(insert entry)
(org-get-category (point-min))))
entries))))
(cond
((and (-contains? categories "BeamOn")
(or weekend
(-contains? categories "Holidays")
(-contains? categories "Vacation")))
'org-agenda-date-beam-weekend)
((-contains? categories "BeamOn")
'org-agenda-date-beam)
((or weekend
(-contains? categories "Holidays")
(-contains? categories "Vacation"))
'org-agenda-date-weekend)
(t 'org-agenda-date)))))
(setq
org-agenda-day-face-function
(function
my-org-agenda-day-face-holidays-function))
; (require 'org-notify)
(bind-key "RET" 'org-agenda-goto org-agenda-mode-map)
(bind-key [tab] 'org-agenda-switch-to org-agenda-mode-map)
(require 'org-agenda))
The code below calculates uses the org-calendar to calculate the expected local contacting payment.
(defun get-timestamps (tags)
(-map
(lambda (x) (cdr (assoc "TIMESTAMP" x)))
(-filter (lambda (x) (assoc "TIMESTAMP" x))
(org-map-entries
(lambda ()
(org-entry-properties))
tags
'agenda))))
(defun timestamp-to-dates (stamp)
(-map
#'calendar-gregorian-from-absolute
(apply
#'number-sequence
(-map
#'org-time-string-to-absolute
(split-string
stamp
"--")))))
(defun local-contacting (dates)
(apply
'+
(-map
(lambda (x)
(pcase x
(`(,month ,day, year)
(pcase (org-day-of-week day month year)
(6 40.40)
(0 40.40)
(_ 20.20)
))))
dates)))
(defun calculate-local-contacting ()
"Calculate expected local contacting fees."
(interactive)
(print
(apply
'+
(-map
(lambda (x)
(local-contacting
(timestamp-to-dates x)))
(get-timestamps "+LocalContact+TODO=\"TODO\"")))))
Org-mode uses the htmlize library to highlight the code in the exported documentation. As long as I’ve installed the library, I should never need to think about it again.
(use-package htmlize)
We need to load the contrib package to get notmuch links into org
(require 'org-notmuch)
This package allow much finer control over the triggers and blocking in our org-mode files. The manual can be found at http://www.nongnu.org/org-edna-el/
(use-package org-edna
:config
(org-edna-load))
I like for each sentence in a LaTeX document to be its own line. That way, when I’m editing, only the relevant sections get marked in the version control, instead of the entire paragraph. This code tries to alleviate the problem. I’m not sure how well it work.
(defadvice LaTeX-fill-region-as-paragraph (around LaTeX-sentence-filling)
"Start each sentence on a new line."
(let ((from (ad-get-arg 0))
(to-marker (set-marker (make-marker) (ad-get-arg 1)))
tmp-end)
(while (< from (marker-position to-marker))
(forward-sentence)
;; might have gone beyond to-marker --- use whichever is smaller:
(ad-set-arg 1 (setq tmp-end (min (point) (marker-position to-marker))))
ad-do-it
(ad-set-arg 0 (setq from (point)))
(unless (or
(bolp)
(looking-at "\\s *$"))
(LaTeX-newline)))
(set-marker to-marker nil)))
(ad-activate 'LaTeX-fill-region-as-paragraph)
Auctex is a nice TeX environment for emacs. I used it constantly in working on my thesis
(use-package auctex
:custom
(TeX-PDF-mode t)
(TeX-view-program-list (quote (("Okular" "okular --unique %o#src:%n%b"))))
(TeX-view-program-selection
(quote
(((output-dvi style-pstricks)
"dvips and gv")
(output-dvi "Okular")
(output-pdf "Evince")
(output-html "xdg-open"))))
:hook
(LaTeX-mode-hook . visual-line-mode)
(LaTeX-mode-hook . auto-fill-mode)
(LaTeX-mode-hook . flyspell-mode)
(LaTeX-mode-hook . LaTeX-math-mode)
:mode ("\\.tex\\'" . TeX-latex-mode))
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'text-mode-hook 'visual-line-mode)
There didn’t used to be a built in word count function. I believe that there is now, so I may not need this any longer.
(defun count-words (&optional begin end)
"count words between BEGIN and END (region); if no region defined, count words in buffer"
(interactive "r")
(let ((b (if mark-active begin (point-min)))
(e (if mark-active end (point-max))))
(message "Word count: %s" (how-many "\\w+" b e))))
(use-package langtool
:custom
(langtool-language-tool-jar "~/bin/LanguageTool-3.5/languagetool-commandline.jar"))
(use-package writegood-mode
:diminish writegood-mode
:hook (text-mode latex-mode org-mode))
(use-package encourage-mode
:diminish encourage-mode
:init (encourage-mode))
(if
(file-exists-p "~/Code/tidal")
(progn
(add-to-list 'load-path "~/Code/tidal/" )
(require 'tidal)))
(use-package emojify
:hook ((text-mode jabber-console-mode) . emojify-mode)
:custom
(emojify-display-style 'unicode)) ; :-)
(use-package ace-window
:bind (("M-z" . ace-window))
:custom
(aw-keys '(?f ?j ?d ?k ?s ?l ?a ?g ?h ?r ?u ?e ?i ?w ?o ?n ?c ?m ?v )))
A basic emacs customication system. Slack uses this to handle system messages and other parts of emacs could probably benefit from it. I really need to tweak the customisation.
(use-package alert
:commands (alert)
:custom
(alert-default-style 'libnotify))
Use the all-the-icons package to get icon fonts.
(use-package all-the-icons)
Automatically display file icons in dired.
(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))
Display icons when switching buffers
(use-package all-the-icons-ivy
:config
(all-the-icons-ivy-setup))
I’ve been trying to get into avy, with moderate success.
(use-package avy
:bind
(("M-d" . avy-goto-char-timer)))
(use-package company
:hook (prog-mode . company-mode)
:bind (("M-/" . company-complete))
:custom
(company-dabbrev-code-modes
(quote
(prog-mode batch-file-mode csharp-mode css-mode erlang-mode haskell-mode
jde-mode lua-mode python-mode purescript-mode)))
:diminish company-mode)
This should allow me to more easily type emoji. Because that’s what my life has been missing.
(use-package company-emoji
:config
(add-to-list 'company-backends 'company-emoji))
Let’s use company-math mode so that we don’t have to keep using the TeX input method
(use-package company-math
:config
(add-to-list 'company-backends 'company-math-symbols-unicode))
😄
(use-package company-qml
:config
(add-to-list 'company-backends 'company-qml))
(use-package company-auctex
:after (company latex))
This package allows me to do the imenu jump to any buffer with the same major mode. This should be a big boon when working on multi-file projects (and not require greping my way around all of the time)
(use-package imenu-anywhere
:general (:keymaps 'override "i" 'ivy-imenu-anywhere))
(use-package eyebrowse
:disabled t
:general
(:infix "w"
"j" 'eyebrowse-create-window-config
"j" 'eyebrowse-next-window-config
"k" 'eyebrowse-prev-window-config
"r" 'eyebrowse-rename-window-config
"/" 'eyebrowse-switch-to-window-config
"x" 'eyebrowse-close-window-config
"0" 'eyebrowse-switch-to-window-config-0
"1" 'eyebrowse-switch-to-window-config-1
"2" 'eyebrowse-switch-to-window-config-2
"3" 'eyebrowse-switch-to-window-config-3
"4" 'eyebrowse-switch-to-window-config-4
"5" 'eyebrowse-switch-to-window-config-5
"6" 'eyebrowse-switch-to-window-config-6
"7" 'eyebrowse-switch-to-window-config-7
"8" 'eyebrowse-switch-to-window-config-8
"9" 'eyebrowse-switch-to-window-config-9)
:config
(eyebrowse-mode))
(use-package flycheck
:diminish flycheck-mode
:hook ((prog-mode haskell-mode) . flycheck-mode)
:config
(flycheck-define-checker
proselint
"A linter for plain prose"
:command ("proselint" source)
:standard-input f
:error-patterns
((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
:modes (markdown-mode text-mode org-mode))
(add-to-list 'flycheck-checkers 'proselint)
(flycheck-add-next-checker 'python-flake8 'python-pylint))
Hydra is a useful little utility for making custom keyboard DSLs.
(use-package hydra
:config
(defhydra hydra-flycheck ()
("X" (progn
(let ((current-prefix-arg 4))
(call-interactively 'flycheck-disable-checker))) "enable" :color blue)
("x" flycheck-disable-checker "disable")
("v" flycheck-verify-setup "verify")
("c" flycheck-select-checker "checkerer")
("e" flycheck-display-error-at-point "explain" :color blue)
("j" flycheck-next-error "next")
("k" flycheck-previous-error "previous"))
(general-define-key
:keymaps '(flycheck-mode-map)
"f" 'hydra-flycheck/body)
(defhydra hydra-flyspell ()
("j" flyspell-goto-next-error "next")
("l" flyspell-correct-previous-word-generic "fix")
("I" ispell-pdict-save "insert")
("a" flyspell-auto-correct-word "auto"))
(general-define-key
:keymaps '(flyspell-mode-map)
"f" 'hydra-flyspell/body)
(defhydra hydra-apropos (:color blue)
"Apropos"
("a" apropos "apropos")
("c" apropos-command "cmd")
("d" apropos-documentation "doc")
("e" apropos-value "val")
("l" apropos-library "lib")
("o" apropos-user-option "option")
("u" apropos-user-option "option")
("v" apropos-variable "var")
("i" info-apropos "info")
("t" tags-apropos "tags")
("z" hydra-customize-apropos/body "customize"))
(defhydra hydra-customize-apropos (:color blue)
"Apropos (customize)"
("a" customize-apropos "apropos")
("f" customize-apropos-faces "faces")
("g" customize-apropos-groups "groups")
("o" customize-apropos-options "options"))
(general-define-key
"h" 'hydra-apropos/body)
(defhydra hydra-windows (:hint nil)
"Manage Windows"
("z" ace-window "ace" :column "Movement")
("j" windmove-down "↓" :column "Movement")
("k" windmove-up "↑" :column "Movement")
("h" windmove-left "←" :column "Movement")
("l" windmove-right "→" :column "Movement")
("J" shrink-window "X↓" :column "Resize")
("K" enlarge-window "X↑" :column "Resize")
("H" shrink-window-horizontally "X←" :column "Resize")
("L" enlarge-window-horizontally "X→" :column "Resize")
("=" balance-windows "equalise" :column "Resize")
("-" split-window-below "vertical" :column "Split")
("|" split-window-right "horizontal" :column "Split")
("x" delete-window "close" :column "Split")
("d" purpose-toggle-window-purpose-dedicated "purpose" :column "Dedicate")
("D" purpose-toggle-window-buffer-dedicated "buffer" :column "Dedicate")
("q" nil "quit" :color blue :column nil))
(general-define-key
" W" 'hydra-windows/body))
Add hydra bindings to ivy
(use-package ivy-hydra)
I hate when emacs asks me which buffer to kill, because it’s my current buffer 99% of the time. Just change the key binding and be done with it.
(bind-key "C-x k" 'kill-this-buffer)
Refreshing buffers is a constant chore that really should have it’s own hotkey. Why not steal F5 from the browser?
(global-set-key
(kbd "<f5>")
(lambda (&optional force-reverting)
"Interactive call to revert-buffer. Ignoring the auto-save
file and not requesting for confirmation. When the current buffer
is modified, the command refuses to revert it, unless you specify
the optional argument: force-reverting to true."
(interactive "P")
;;(message "force-reverting value is %s" force-reverting)
(if (or force-reverting (not (buffer-modified-p)))
(revert-buffer :ignore-auto :noconfirm)
(error "The buffer has been modified"))))
(use-package keyfreq
:config
(keyfreq-mode 1)
(keyfreq-autosave-mode 1))
(use-package ivy
:general (:keymaps 'override :infix "x" "b" 'ivy-switch-buffer)
:diminish ivy-mode)
(use-package counsel
:after ivy
:demand t
:bind (("C-s" . swiper)
("C-c C-r" . ivy-resume)
("<f6>" . ivy-resume)
("C-x b" . ivy-switch-buffer)
("M-x" . counsel-M-x)
("M-y" . counsel-yank-pop)
("C-x C-f" . counsel-find-file)
("<f1> f" . counsel-describe-function)
("<f1> v" . counsel-describe-variable)
("<f1> l" . counsel-load-library)
("<f2> i" . counsel-info-lookup-symbol)
("C-x 8 RET" . counsel-unicode-char)
("<f2> u" . counsel-unicode-char))
:general
(:keymaps 'org-mode-map
"i" 'counsel-org-goto
"cq" 'counsel-org-tag)
(:infix "x" "f" 'counsel-find-file
"8 RET" 'counsel-unicode-char)
("/" 'swiper "?" 'swiper-all)
:diminish counsel-mode
:custom
(ivy-use-virtual-buffers t)
(counsel-find-file-at-point t)
(counsel-mode t)
:config
(ivy-mode 1))
Dash is an offline documentation framework. The open source version is Zeal. It’s useful for getting programming documentation without needing to load up a google search. It’s especially useful when there’s no internet access or the scipy website is down yet again.
FIXME: The current version of counsel-dash relies on helm-dash, which subsequently relies on Helm. I may be able to get rid of the helm dependency in the future if this changes. I need to check on this from time to time and see if anything has improved.
(defun python-set-docsets ()
(setq-local counsel-dash-docsets
'("SciPy" "NumPy" "Matplotlib" "Python_2" "Python_3" "Qt_5")))
(defun elisp-set-docsets ()
(setq-local counsel-dash-docsets
'("Emacs_Lisp")))
(defun haskell-set-docsets ()
(setq-local counsel-dash-docsets
'("Haskell")))
(defun html-set-docsets ()
(setq-local counsel-dash-docsets
'("HTML" "CSS")))
(use-package counsel-dash
:hook
((python-mode . python-set-docsets)
(elisp-mode . elisp-set-docsets)
(haskell-mode . haskell-set-docsets)
(html-mode . html-set-docsets))
:general
(:keymaps 'override :infix "z"
"d" 'counsel-dash)
:custom
(counsel-dash-browser-func 'eww)
(counsel-dash-docsets-path "~/.local/share/Zeal/Zeal/docsets"))
(use-package flyspell-correct-ivy
:config
(require 'flyspell-correct-ivy))
(use-package link-hint
:bind
("M-o" . link-hint-open-link))
(use-package ace-link
:general
(:prefix 'nil :infil 'nil :keymaps 'org-mode-map
"M-o" 'ace-link-org)
:config
(ace-link-setup-default))
Persp mode gives named window groups
(use-package persp-mode
:general
(:infix "w"
:keymaps 'override
"n" 'persp-next
"p" 'persp-prev
"s" 'persp-frame-switch
"S" 'persp-window-switch
"r" 'persp-rename
"c" 'persp-copy
"C" 'persp-kill
"a" 'persp-add-buffer
"b" 'persp-switch-to-buffer
"t" 'persp-temporarily-display-buffer
"i" 'persp-import-buffers
"I" 'persp-import-win-conf
"k" 'persp-remove-buffer
"K" 'persp-kill-buffer
"w" 'persp-save-state-to-file
"W" 'persp-save-to-file-by-names
"l" 'persp-load-state-from-file
"L" 'persp-load-from-file-by-names)
:config
(persp-mode 1))
(use-package projectile
:demand t
:general
(:infix "p"
:keymaps 'override
"xe" 'projectile-run-eshell
"xs" 'projectile-run-shell
"xt" 'projectile-run-term
"d" 'projectile-find-dir
"D" 'projectile-dired
"P" 'projectile-test-project
"s" 'projectile-save-project-buffers
"B" 'projectile-ibuffer
"k" 'projectile-kill-buffers
"c" 'projectile-compile-project
"v" 'projectile-vc
"t" 'projectile-find-tag
"T" 'projectile-regenerate-tags
"R" 'projectile-replace-regexp
"E" 'projectile-edit-dir-locals
"r" 'projectile-run-project)
:custom
(projectile-keymap-prefix (kbd "C-c C-p"))
(projectile-mode-line
'(:eval
(if
(file-remote-p default-directory)
""
(format " {%s}" (projectile-project-name)))))
(projectile-completion-system 'ivy)
:config
(projectile-global-mode))
(use-package counsel-projectile
:after (projectile counsel)
:general
(:infix "p"
:keymaps 'override
"f" 'counsel-projectile
"b" 'counsel-projectile-switch-to-buffer
"p" 'counsel-projectile-switch-project
"g" 'counsel-projectile-rg))
Recentf keeps track of recently edited files.
(require 'recentf)
(recentf-mode)
(use-package spaceline
:demand t
:custom
(spaceline-highlight-face-func 'spaceline-highlight-face-evil-state))
(use-package spaceline-all-the-icons
:demand t
:after (spaceline all-the-icons)
:config
(spaceline-all-the-icons-theme)
(spaceline-all-the-icons--setup-git-ahead)
(spaceline-toggle-all-the-icons-buffer-size-off)
(spaceline-toggle-all-the-icons-time-off)
(spaceline-toggle-all-the-icons-region-info-off)
(spaceline-toggle-all-the-icons-git-ahead-on)
(spaceline-toggle-all-the-icons-projectile-on))
Yasnippets provide programmable skeletons for filling out boilerplate
(use-package yasnippet
:custom
(yas-indent-line 'fixed)
:general
(:keymaps 'yas-minor-mode-map
"yv" 'yas-visit-snippet-file
"yn" 'yas-new-snippet
"ys" 'yas-insert-snippet)
:config
(yas-global-mode))
(defun mpa-parse-param (param)
(pcase-let
((`(,name . ,value) (split-string param "=")))
(cond
((string-equal name "OutputWorkspace")
"self.declareProperty(\n WorkspaceProperty(name=\"OutputWorkspace\",\n defaultValue=\"\",\n direction=Direction.Output))")
((eq value '())
(format "self.declareProperty(\"%s\", defaultValue=0)" name))
((string-match "[0-9]+" (car value))
(format "self.declareProperty(\"%s\", defaultValue=%s)"
name
(string-to-number (car value))))
((string-equal (car value) "file")
(format "self.declareProperty(\n FileProperty(name=\"%s\",\n defaultValue=\"\",\n action=FileAction.%s))" name (cadr value)))
((string-equal (car value) "wksp")
(format "self.declareProperty(\n WorkspaceProperty(name=\"%s\",\n defaultValue=\"\",\n direction=Direction.%s))" name (cadr value)))
(t (format "self.declareProperty(\"%s\", defaultValue=\"%s\")" name (car value))))))
(defun mpa-get-param (param)
(pcase-let
((`(,name . ,value) (split-string param "=")))
(cond
((string-equal name "OutputWorkspace") "")
('t (format "%s = self.getProperty(\"%s\").value" name name)))))
(defun mpf-parse-param (param)
(pcase-let
((`(,name . ,value) (split-string param "=")))
(cond
((eq value '())
(format "self.declareProperty(\"%s\", defaultValue=0.0)" name))
((string-match "[0-9]+" (car value))
(format "self.declareProperty(\"%s\", defaultValue=%s)"
name
(string-to-number (car value))))
(t (format "self.declareProperty(\"%s\", defaultValue=%s)" name (car value))))))
(defun mpf-get-param (param)
(pcase-let
((`(,name . ,value) (split-string param "=")))
(format "%s = self.getParameter(\"%s\")" name name)))
(use-package whitespace-cleanup-mode
:diminish whitespace-cleanup-mode
:config
(global-whitespace-cleanup-mode))
(use-package window-purpose
:after (ivy)
:general
(:infix "xr"
"p" 'ivy-purpose-switch-buffer-with-some-purpose
"P" 'ivy-purpose-switch-buffer-with-purpose)
(:infix ","
"d" 'purpose-toggle-window-buffer-dedicated
"D" 'purpose-toggle-window-purpose-dedicated
"1" 'purpose-delete-non-dedicated-windows
"b" 'purpose-switch-buffer-with-purpose
"s" 'purpose-save-window-layout
"l" 'purpose-load-window-layout)
:config
(purpose-mode)
(purpose-x-kill-setup)
(purpose-x-magit-single-on)
(add-to-list 'purpose-user-mode-purposes '(haskell-cabal-mode . edit))
(add-to-list 'purpose-user-mode-purposes '(eshell-mode . terminal))
(add-to-list 'purpose-user-mode-purposes '(jabber-chat-mode . chat))
(add-to-list 'purpose-user-mode-purposes '(slack-mode . chat))
(add-to-list 'purpose-user-mode-purposes '(notmuch-hello-mode . chat))
(add-to-list 'purpose-user-mode-purposes '(notmuch-message-mode . chat))
(add-to-list 'purpose-user-mode-purposes '(notmuch-search-mode . chat))
(add-to-list 'purpose-user-mode-purposes '(notmuch-show-mode . chat))
(add-to-list 'purpose-user-mode-purposes '(org-mode . edit))
(add-to-list 'purpose-user-mode-purposes '(ein:notebook-multilang-mode . edit))
(add-to-list 'purpose-user-mode-purposes '(systemd-mode . edit))
(add-to-list 'purpose-user-mode-purposes '(help-mode . help))
(add-to-list 'purpose-user-mode-purposes '(Info-mode . help))
(add-to-list 'purpose-user-mode-purposes '(Custom-mode . custom))
(purpose-compile-user-configuration))
Winner mode allows me to undo and redo changes to the window layout within emacs. Very useful when I make a mistake. It’s also handy for focusing on a single window, then returning to my previous, more complex layout with a single C-c ←
(winner-mode)