jwinder emacs config
introduction
getting started
I prefer to clone this repository as $HOME/emacs-config and symlink it to $HOME/.emacs.d
git clone git@github.com:jwinder/emacs-config.git $HOME/emacs-config
ln -s $HOME/emacs-config $HOME/.emacs.dYou can also create symlinks to a private directory or private.org file in a safe place, containing private or personal settings. This works well for irc passwords, tramp helpers, etc.
ln -s /path/to/your/safe/directory $HOME/emacs-config/private # directory of elisp files
ln -s /path/to/your/safe/private.org $HOME/emacs-config/private.org # file containing elisp segmentsNow, start emacs.
org configs
personal info
(defconst jw-config-author-name "Joe Winder")
(defconst jw-config-author-url "http://jwinder.github.io")
(defconst jw-config-github-url "https://github.com/jwinder/emacs-config")dependencies
packages
common
(use-package afternoon-theme :pin melpa)
(use-package dash :pin melpa)
(use-package f :pin melpa)
(use-package s :pin melpa
:config (progn
(defalias 's-empty? 's-blank?)
(defalias 's-nonempty? 's-present?)
(defalias 's-nonempty-or-nil 's-presence)))
(use-package scratch :pin melpa
:config (progn
(defalias 'tmp-scratch-buffer 'scratch)))
(use-package ob-http)
(use-package ob-translate)
(use-package ob-async :pin melpa)
(use-package org-pomodoro)
(use-package interleave)
(use-package htmlize)
(use-package magit
:config (global-magit-file-mode t))
(use-package browse-at-remote :pin melpa
:config (progn
(defalias 'git-browse-at-remote 'browse-at-remote)
(defalias 'github-browse-file 'browse-at-remote)))
(use-package gist
:config (setq gist-view-gist t))
(use-package expand-region)
(use-package multiple-cursors
:config (progn
(defun mc/prompt-for-inclusion-in-whitelist (original-command)
"Rewrite of `mc/prompt-for-inclusion-in-whitelist' to not ask yes/no for every newly seen command."
(add-to-list 'mc/cmds-to-run-for-all original-command)
(mc/save-lists)
t)))
(use-package smartparens
:config (progn (require 'smartparens-config)
(smartparens-global-mode t)))
(use-package company
:config (progn (global-company-mode t)
(setq company-idle-delay nil
company-tooltip-idle-delay nil)))
(use-package flycheck
:pin melpa-stable
:config (progn (setq flycheck-standard-error-navigation nil
flycheck-display-errors-function nil)
(global-flycheck-mode)))
(use-package yasnippet)
(use-package yasnippet-snippets)
(use-package helm)
(use-package helm-ag)
(use-package helm-projectile)
(use-package helm-flycheck)
(use-package helm-flyspell :pin melpa)
(use-package helm-descbinds)
(use-package wgrep
:config (setq wgrep-auto-save-buffer t))
(use-package wgrep-helm)
(use-package docker)
(use-package dumb-jump
:config (setq dumb-jump-selector 'helm))
(use-package xah-math-input :pin melpa
:config (progn
(xah-math-input--add-to-hash [ ["def" "≝"] ["pm" "±"] ["cdot" "·"] ["wedge" "∧"] ["doublesharp" "𝄪"]])
(xah-math-input--add-cycle ["≔" "≝"])
(xah-math-input--add-cycle ["∫" "∬" "∭" "⨌"])
(xah-math-input--add-cycle ["∮" "∯" "∰" "∱" "∲" "∳"])))
;; not working well after emacs 26 upgrade
;; (use-package ess
;; :config (setq save-abbrevs 'silently)) ;; ess R sets some abbrevs when installedlanguages
(use-package yaml-mode)
(use-package markdown-mode)
(use-package dockerfile-mode)
(use-package scala-mode)
(use-package sbt-mode)
(use-package inf-ruby)
(use-package go-mode
:config (add-hook 'before-save-hook 'gofmt-before-save))
(use-package haskell-mode
:config (add-hook 'haskell-mode-hook 'turn-on-haskell-indent))
(use-package coffee-mode
:config (setq coffee-tab-width 2))
(use-package terraform-mode
:mode ("\\.tfstate$" . js-mode))
(use-package protobuf-mode)
(use-package groovy-mode
:mode ("Jenkinsfile$" . groovy-mode))
(use-package markdown-mode
:mode (("\\.md$" . gfm-mode)
("\\.markdown$" . gfm-mode)))
;; (use-package graphviz-dot-mode) ;; does not work after emacs 26.1 upgradehelper functions
These are non-interactive library functions useful in other parts of this config
(require 'dash)
(require 's)
(require 'f)
(require 'vc)
(defconst jw--mode-line-color "#22083397778B")
(defun jw--font-name (&optional size)
(if size (concat "Monaco " size) "Monaco"))
(defun jw--set-font-size (size)
(set-face-attribute 'default nil :font (jw--font-name size)))
(defun jw--login-shell ()
(file-name-nondirectory (getenv "SHELL")))
(defun jw--all-minor-modes ()
(sort minor-mode-list 's-less-p))
(defun jw--all-major-modes ()
(sort (-distinct (mapcar 'cdr (-filter '(lambda (entry) (and (cdr entry) (atom (cdr entry)))) auto-mode-alist))) 's-less-p))
(defmacro jw--define-menu (name doc &rest args)
(declare (indent defun))
(require 'magit-popup)
`(progn (magit-define-popup ,name ,doc ,@args)))
(defmacro jw--save-current-message (&rest body)
"Saves `current-message', executes the body, then `message' the saved message to the echo area. Any `message' calls within the body will likely not be seen."
(declare (indent defun))
`(let ((msg (current-message)))
(progn ,@body)
(message msg)))
(defun jw--write-to-file (string file &optional append)
(jw--save-current-message
(let ((file-dir (file-name-directory file)))
(unless (f-exists? file-dir) (make-directory file-dir 'mk-parents)))
(if append (f-append string 'utf-8 file) (f-write string 'utf-8 file))))
(defun jw--make-uuid ()
(downcase (shell-command-to-string "uuidgen | tr -d '\n'")))
(defun jw--pwd ()
(file-truename default-directory))
(defun jw--vc-root-dir ()
(let ((vc-root-dir (ignore-errors (vc-call-backend (vc-responsible-backend (jw--pwd)) 'root (jw--pwd)))))
(if vc-root-dir (file-truename vc-root-dir) nil)))
(defun jw--git-root-dir ()
(let ((git-root-dir (ignore-errors (vc-find-root (jw--pwd) ".git"))))
(if git-root-dir (file-truename git-root-dir) nil)))
(defun jw--git-config-get (key)
(s-presence (s-trim (shell-command-to-string (format "git config --get %s 2>/dev/null" key)))))
(defun jw--iso-current-time-string ()
(concat (format-time-string "%Y-%m-%dT%T")
((lambda (x) (concat (substring x 0 3) ":" (substring x 3 5))) (format-time-string "%z"))))
(defun jw--current-date-string ()
(format-time-string "%Y-%m-%d"))
(defun jw--symbol-name (symbol-or-string)
(if (symbolp symbol-or-string) (symbol-name symbol-or-string) symbol-or-string))
(defun jw--http-get-request-to-string (url)
(with-current-buffer (url-retrieve-synchronously url)
(goto-char url-http-end-of-headers)
(delete-region (point-min) (point))
(s-trim (buffer-string))))
(defun jw--do-when-process-finishes (process fn)
"Invoke function `fn' after process `process' finishes or exits. `fn' is a one-arg function providing the finished process."
(when process
(set-process-sentinel process
`(lambda (proc change)
(when (string-match "\\(?:finished\\|exited\\)" change)
(funcall ,fn proc))))))
(setq jw--run-cmd-shell "bash")
(defun jw--run-cmd (command &optional process-name before-process-creation after-process-creation after-process-finish delete-tmp-script-after)
"A wrapper around `make-comint-in-buffer'.
For commands that have already finished, this will clean up the process buffer and re-run the command.
For long running processes, this will always toggle back and forth between the process buffer and the other buffer as long as the process is alive.
`process-name' can be used to override the automatic naming of the process & buffer (from the `command').
`before-process-creation' is an optional zero-arg function that is run before the process is started.
`after-process-creation' is an optional one-arg function (providing the process an arg) that is run after the process is started.
`after-process-finish' is an optional one-arg function (providing the process as an arg) that is run after the process finishes."
(require 'comint)
(let* ((prepared-cmd (string-trim command))
(cmd-process-name (or process-name (s-collapse-whitespace (s-left 100 prepared-cmd))))
(cmd-buffer-name (format "*%s*" cmd-process-name)))
(if (s-empty? prepared-cmd)
(message "Empty command! Doing nothing.")
(if (process-live-p (get-process cmd-process-name))
(if (string= (buffer-name) cmd-buffer-name) (switch-to-buffer (other-buffer)) (switch-to-buffer cmd-buffer-name))
(let* ((tmp-script-dir "/tmp/emacs-jw-run-cmd/")
(tmp-script-rel-filename (replace-regexp-in-string "[^a-zA-Z0-9]+" "-" cmd-process-name))
(tmp-script-abs-filename (concat tmp-script-dir tmp-script-rel-filename))
(tmp-script-sh-executable (or (ignore-errors (executable-find jw--run-cmd-shell))
(executable-find (jw--login-shell))))
(tmp-script-contents (format "#!%s\n\ncd %s\n\n%s" tmp-script-sh-executable (jw--pwd) prepared-cmd)))
(when (get-buffer cmd-buffer-name) (kill-buffer cmd-buffer-name))
(jw--write-to-file tmp-script-contents tmp-script-abs-filename)
(unless (file-executable-p tmp-script-abs-filename) (chmod tmp-script-abs-filename #o744))
(let ((process-buffer (get-buffer-create cmd-buffer-name)))
(when before-process-creation (funcall before-process-creation))
(apply 'make-comint-in-buffer cmd-process-name process-buffer tmp-script-abs-filename nil nil)
(let ((proc (get-buffer-process process-buffer)))
(when after-process-creation (funcall after-process-creation proc))
(when after-process-finish (jw--do-when-process-finishes proc `(lambda (proc) (funcall ,after-process-finish proc))))
(when delete-tmp-script-after (jw--do-when-process-finishes proc `(lambda (proc) (f-delete ,tmp-script-abs-filename 'force)))))
(switch-to-buffer process-buffer)))))))
(defun jw--run-cmd-tmux (command tmux-session)
"Create session `tmux-session' if needed, and send `command' to it."
(call-process "tmux" nil nil nil "new-session" "-d" "-s" tmux-session) ;; this does nothing if the session already exists
(call-process "tmux" nil nil nil "send-keys" "-t" tmux-session command "C-m"))
(defun jw--sql-pretty-print (begin end)
"Formats SQL on region between `begin' and `end' using underlying sql-formatter-cli."
(if (executable-find "sql-formatter-cli")
(shell-command-on-region begin end "sql-formatter-cli" nil 'replace)
(message "Formatter not found. Please run: npm install -g sql-formatter-cli")))A macro to set keybindings from an org table
(defmacro keybinding-org-table (org-table)
"Sets up key bindings from an org table like:
| Key | Function | Scope | Hook | Notes |
|-------+----------+-----------------+---------------+-----------|
| C-c a | fn-1 | | | fun notes |
| C-c b | fn-2 | local | org-mode-hook | |
| C-c c | fn-3 | eshell-mode-map | | |
| C-c d | nil | | | |
| C-c e | nil | local | | |
| C-c f | nil | eshell-mode-map | | |
- C-c a gets set to fn-1 in the global map.
- C-c b gets set to fn-2 in the current local map, run during the org-mode-hook.
- C-c c gets set to fn-3 in the eshell-mode-map.
- C-c d gets unbound in the global map.
- C-c e gets unbound in the current local map.
- C-c f gets unbound in the eshell-mode-map.
- For a global binding, an empty cell or the value \"global\" can be provided in the Scope column.
- When unsetting a keybinding, an empty table cell can be provided instead of nil in the Function column.
- It is safe to leave out the Scope & Hook columns if only global keybindings are necessary.
- The ordering of the 4 columns cannot be changed (extra columns after the Hook column are ignored)."
(declare (indent defun))
`(let* ((org-table-name (symbol-name ,org-table))
(rows (symbol-value ,org-table))
(keys-var-name (format "jw-%s" org-table-name))
(keys-setter-def-name (format "jw-%s-set-bindings" org-table-name))
(keys-setter-def-symbol (intern keys-setter-def-name)))
;; add keys to their own variable: jw-[org-table]
(eval `(setq ,(intern keys-var-name) rows))
;; append keys to jw-all-custom-keys variable
(unless (boundp 'jw-all-keys) (setq jw-all-keys nil))
(-each rows (lambda (row) (add-to-list 'jw-all-keys row 'append)))
;; create interactive jw-[org-table]-set-bindings function to set all keys
(eval `(defun ,keys-setter-def-symbol ()
,(format "Auto-created function to set keybindings defined in the org table: %s\n\nOrg table keybindings cached in `%s'\n\nAll custom keybindings cached in `jw-all-keys'\n\nThis function is also stored in `jw-all-keys-set-bindings-functions', and `jw-all-keys-set-bindings' evaluates every function in this list." org-table-name (intern keys-var-name))
(interactive)
(-each ,(intern keys-var-name) ;; must call the dynamic jw-[org-table] var here, not the lexical rows var
(lambda (row)
(let* ((key (car row))
(command (if (cadr row) (intern (cadr row)) nil))
(scope (s-presence (nth 2 row)))
(hook-name (s-presence (nth 3 row))))
;; yucky but the functions must be setup differently inside of hooks
;; being explicit about the various cases is best
(cond
((and hook-name (s-equals? scope "local"))
(add-hook (intern hook-name)
`(lambda () (local-set-key (kbd ,key) (quote ,command)))))
((and hook-name (or (s-blank-str? scope) (s-equals? scope "global")))
(add-hook (intern hook-name)
`(lambda () (global-set-key (kbd ,key) (quote ,command)))))
((and hook-name (boundp (intern scope)))
(add-hook (intern hook-name)
`(lambda () (define-key ,(intern scope) (kbd ,key) (quote ,command)))))
((s-equals? scope "local") (local-set-key (kbd key) command))
((or (s-blank-str? scope) (s-equals? scope "global")) (global-set-key (kbd key) command))
((boundp (intern scope)) (define-key (eval (intern scope)) (kbd key) command))
(t (message "Unable to set command %s to keybinding %s from org table. Silently skipping." command key))
)
)
))
))
;; append jw-[org-table]-set-bindings to jw-all-keys-set-bindings-functions variable
(unless (boundp 'jw-all-keys-set-bindings-functions) (setq jw-all-keys-set-bindings-functions nil))
(add-to-list 'jw-all-keys-set-bindings-functions `,keys-setter-def-symbol 'append)
;; create jw-set-all-bindings to eval every function created with this macro
(unless (fboundp 'jw-all-keys-set-bindings)
(defun jw-all-keys-set-bindings ()
"Evaluate every function in `jw-all-keys-set-bindings-functions'."
(interactive)
(-each jw-all-keys-set-bindings-functions 'funcall)))
;; go ahead and eval jw-[org-table]-set-bindings
(eval `(,keys-setter-def-symbol))
))customization
env
(require 'eshell)
(defun jw-env-set ()
(interactive)
(let* ((cmd (format "%s -l -i -c env" (jw--login-shell)))
(env-big-str (shell-command-to-string cmd))
(lines (split-string env-big-str "\n")))
(dolist (line lines)
(unless (= 0 (length line))
(let* ((tokens (split-string line "="))
(name (car tokens))
(value (mapconcat 'identity (cdr tokens) "=")))
(setenv name value)
(when (string= name "PATH")
(setq exec-path (split-string value ":"))
(setq eshell-path-env value))))))
(setenv "EDITOR" "emacsclient"))
(jw-env-set)
(add-to-list 'eshell-mode-hook 'jw-env-set)
style
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(load-theme 'afternoon t)
(set-cursor-color "dark grey")
(set-background-color "black")
(set-face-background 'fringe nil)
(jw--set-font-size "14")
(set-face-attribute 'mode-line nil :font (jw--font-name "14") :background jw--mode-line-color :foreground "#7db5d6" :box '(:style released-button))
(set-face-attribute 'mode-line-inactive nil :background "#263238" :foreground "gray" :box '(:style released-button))
(set-face-attribute 'mode-line-buffer-id nil :foreground "white")
(set-face-attribute 'mode-line-highlight nil :foreground "#7db5d6")
(set-face-attribute 'header-line nil :background "#005858" :foreground "white")
(setq-default mode-line-format '(" " mode-line-buffer-identification (vc-mode vc-mode) " " mode-line-misc-info))
(setq frame-title-format nil)
(when (eq system-type 'darwin)
(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'default-frame-alist '(ns-appearance . dark))
(setq ns-use-proxy-icon nil))
(setq inhibit-startup-message t
initial-scratch-message ""
initial-major-mode 'org-mode)fix for cursor color in clients falling back to the default theme copied from stackoverflow
(require 'frame)
(defun fix-colors-for-emacs-clients (frame)
(modify-frame-parameters frame (list (cons 'cursor-color "dark grey")))
(modify-frame-parameters frame (list (cons 'background-color "black"))))
(add-hook 'after-make-frame-functions 'fix-colors-for-emacs-clients)settings
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file 'noerror)
(setq jw-org-scratch-file (f-expand "scratch.org" user-emacs-directory))
(setq enable-local-variables :all)
(ansi-color-for-comint-mode-on)
(show-paren-mode t)
(fset 'yes-or-no-p 'y-or-n-p)
(setq create-lockfiles nil)
(setq save-silently t)
(setq suggest-key-bindings nil)
(setq kill-whole-line t)
(global-auto-revert-mode 1)
(setq global-auto-revert-non-file-buffers t
auto-revert-verbose nil)
(setq-default indent-tabs-mode nil)
(setq tab-width 2)
(setq js-indent-level 2)
(delete-selection-mode t)
(winner-mode t)
(global-subword-mode t)
(put 'dired-find-alternate-file 'disabled nil)
(setq wdired-allow-to-change-permissions 'advanced)
(setq dired-listing-switches "-alh")
(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
(add-hook 'before-save-hook 'delete-trailing-whitespace)
(add-hook 'next-error-hook 'delete-other-windows)
(setq uniquify-buffer-name-style 'forward)
(setq ring-bell-function 'ignore)
(setq enable-recursive-minibuffers t)
(add-to-list 'auto-mode-alist '("\\.scss$" . css-mode))
(add-to-list 'auto-mode-alist '("Gemfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Vagrantfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Berksfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.irbrc$" . ruby-mode))
(add-hook 'text-mode-hook 'flyspell-mode)
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(put 'narrow-to-region 'disabled nil)
;; (setq calc-angle-mode 'rad)
(setq calc-angle-mode 'deg)
(setq tramp-default-method "ssh")
;; comint doesn't recognize a password prompt in one of my scripts. consider reporting this as a bug.
(setq comint-password-prompt-regexp (concat comint-password-prompt-regexp "\\|^.*Password:\\s *\\'"))
(defun shell-command--advice--ignore-message-with-no-output (&rest args)
(when (and (current-message) (string-match "Shell command succeeded with no output" (current-message))) (message nil)))
(advice-add 'shell-command-on-region :after 'shell-command--advice--ignore-message-with-no-output)
(setq user-auto-save-directory (expand-file-name "auto-saves/" user-emacs-directory ))
(unless (file-exists-p user-auto-save-directory) (make-directory user-auto-save-directory)) ;; auto-save won't create directories
(setq auto-save-file-name-transforms `((".*" ,user-auto-save-directory t)))
(setq user-backup-directory (expand-file-name "backups/" user-emacs-directory))
(unless (file-exists-p user-backup-directory) (make-directory user-backup-directory))
(setq version-control t
vc-make-backup-files t
kept-new-versions 10
kept-old-versions 0
backup-by-copying t ;; deep copy of symlinks
delete-old-versions t)
(setq backup-directory-alist `(("." . ,user-backup-directory)))
(when (eq system-type 'gnu/linux)
(setq interprogram-paste-function 'x-cut-buffer-or-selection-value
browse-url-browser-function 'browse-url-generic
browse-url-generic-program "google-chrome"))
(when (eq system-type 'darwin)
(setq ns-command-modifier 'meta
browse-url-browser-function 'browse-url-default-macosx-browser
ispell-program-name "aspell"))functions
common
(defalias 'life-is-too-much 'save-buffers-kill-terminal)
(defalias 'filter-lines 'keep-lines)
(defalias 'filter-out-lines 'flush-lines)
(defalias 'elisp-shell 'ielm)
(defun life-might-be-too-much (arg)
(interactive "P")
(if (or arg (yes-or-no-p "Is life too much? "))
(life-is-too-much)
(message "Life continues.")))
(defun font-size-normal ()
(interactive)
(jw--set-font-size "14"))
(defun font-size-big ()
(interactive)
(jw--set-font-size "18"))
(defun font-size-set (size)
(interactive "sSize: ")
(jw--set-font-size size))
(defun ns-raise-chrome ()
(interactive)
(when (fboundp 'ns-do-applescript)
(ns-do-applescript "tell application \"Google Chrome\" to activate")))
(defun kill-ring-cleanup-last-kill (&optional in-major-mode)
"Cleans whitespace and reindents the text in the head of the kill ring as if in the major mode.
NOTICE: Sometimes this acts funky, e.g. after removing items from the kill ring via helm."
(interactive)
(with-temp-buffer
(jw--save-current-message
(let ((mode (or in-major-mode (completing-read "Major mode to mimic: " (jw--all-major-modes) nil t))))
(yank)
(funcall (intern-soft mode))
(indent-region (point-min) (point-max))
(whitespace-cleanup)
(kill-new (buffer-substring (point-min) (point-max)) t)))))
(defun kill-ring-save-region-or-line (arg)
(interactive "P")
(let ((cleanup-kill arg))
(if (region-active-p)
(kill-ring-save (mark) (point))
(kill-ring-save (line-beginning-position) (line-end-position)))
(when cleanup-kill (kill-ring-cleanup-last-kill major-mode))))
(defun kill-region-or-line (arg)
(interactive "P")
(let ((cleanup-kill arg))
(if (region-active-p)
(kill-region (mark) (point))
(progn (beginning-of-line) (kill-line)))
(when cleanup-kill (kill-ring-cleanup-last-kill major-mode))))
(defun kill-save-file-or-buffer-name (arg)
"Kill ring save the current file name. With prefix arg, save the fully qualified path + file name. If the buffer is not visiting a file, use the buffer name."
(interactive "P")
(if buffer-file-name
(if arg
(kill-new buffer-file-name)
(kill-new (f-filename buffer-file-name)))
(kill-new (buffer-name))))
(defun unique-lines ()
(interactive)
(if (region-active-p)
(delete-duplicate-lines (region-beginning) (region-end))
(delete-duplicate-lines (point-min) (point-max))))
(defun date (&optional arg)
"Display current date time.
With default prefix arg (e.g. C-u M-x date), also display calendar around current date.
With prefix arg of 4 (e.g. C-u 4 M-x date), also prompt for year/month for calendar display."
(interactive "P")
(when arg (calendar (if (equal arg 4) arg nil)))
(message (current-time-string)))
(defun computer-power-status ()
"Alternative to the default battery functions, which currently don't extract the information correctly on macOS."
(interactive)
(case system-type
('darwin (shell-command "pmset -g ps"))
(t (message "This is only setup for macOS."))))
(defun iso-date ()
(interactive)
(message (jw--iso-current-time-string)))
(defun insert-iso-date ()
(interactive)
(insert (jw--iso-current-time-string)))
(defun insert-date ()
(interactive)
(insert (jw--current-date-string)))
(defun weather ()
(interactive)
(jw--run-cmd "curl wttr.in" "weather"))
(defun scratch-buffer ()
"Save the scratch buffer in a file."
(interactive)
(find-file jw-org-scratch-file)
(cd (getenv "HOME"))
(when (get-buffer "*scratch*") (kill-buffer "*scratch*")))
(defun toggle-scratch-buffer ()
(interactive)
(if (s-equals? (buffer-name) (f-filename jw-org-scratch-file))
(progn
(save-buffer)
(switch-to-buffer (other-buffer)))
(scratch-buffer)))
(defun ping-google ()
(interactive)
(ping "google.com"))
(defun uuid ()
(interactive)
(insert (jw--make-uuid)))
(defun json-prettify ()
(interactive)
(if (region-active-p)
(json-pretty-print (region-beginning) (region-end))
(json-pretty-print-buffer)))
(defun sql-prettify ()
(interactive)
(if (region-active-p)
(jw--sql-pretty-print (region-beginning) (region-end))
(jw--sql-pretty-print (point-min) (point-max))))
(defun math-symbol-at-point (arg)
(interactive "P")
(if arg
(xah-math-input-list-math-symbols)
(xah-math-input-change-to-symbol)))
(defun cmd (command)
(interactive "sCommand: ")
(jw--run-cmd command))
(defun cmd-tmux (command &optional tmux-session)
(interactive "sCommand: ")
(let ((ts (or tmux-session "emacs")))
(jw--run-cmd-tmux command ts)
(message "Sent to tmux session: %s" ts)))
(defun cmd-dwim (arg &optional command)
"Shell command dwim.
M-x `cmd-dwim' will run an async shell command in a new buffer.
C-u M-x `cmd-dwim' will run a shell command and print the response in the echo area.
C-u C-u M-x `cmd-dwim' will run a shell command and insert the response in the buffer on the next line.
C-u C-u C-u M-x `cmd-dwim' will send a shell command to the default tmux session using `cmd-tmux'.
Interactively:
- If a region is selected, the region will be used as the shell command.
- If the point is on a line beginning with a dollar sign (e.g. \"$ whoami\"), the entire line will be used as the shell command.
- Otherwise, the shell command is read from prompt."
(interactive "P")
(let ((prepared-cmd (or command (if (region-active-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(if (s-starts-with? "$" (s-trim (or (thing-at-point 'line t) "")))
(s-trim-left (s-chop-prefix "$" (s-trim (thing-at-point 'line t))))
(read-shell-command "Command: "))))))
(if arg
(case (prefix-numeric-value arg)
(16 (save-excursion (open-line-next) (insert (s-trim (shell-command-to-string prepared-cmd)))))
(64 (cmd-tmux prepared-cmd))
(t (message (string-trim (shell-command-to-string prepared-cmd)))))
(cmd prepared-cmd))))
(jw--define-menu cmd-menu 'cmd-menu
:actions '("Command menu (C-c m !)"
(?! "sh cmd async M-! (C-u echo area / C-u C-u at point)" cmd-dwim)
(?: "elisp evaluate M-:" helm-eval-expression-with-eldoc)
(?* "calc evaluate M-*" helm-calcul-expression))
:max-action-columns 1)
(defun transpose-windows (arg)
(interactive "p")
(let ((selector (if (>= arg 0) 'next-window 'previous-window)))
(while (/= arg 0)
(let ((this-win (window-buffer))
(next-win (window-buffer (funcall selector))))
(set-window-buffer (selected-window) next-win)
(set-window-buffer (funcall selector) this-win)
(select-window (funcall selector)))
(setq arg (if (plusp arg) (1- arg) (1+ arg))))))
(defun toggle-window-split ()
(interactive)
(if (= (count-windows) 2)
(let* ((this-win-buffer (window-buffer))
(next-win-buffer (window-buffer (next-window)))
(this-win-edges (window-edges (selected-window)))
(next-win-edges (window-edges (next-window)))
(this-win-2nd (not (and (<= (car this-win-edges)
(car next-win-edges))
(<= (cadr this-win-edges)
(cadr next-win-edges)))))
(splitter
(if (= (car this-win-edges)
(car (window-edges (next-window))))
'split-window-horizontally
'split-window-vertically)))
(delete-other-windows)
(let ((first-win (selected-window)))
(funcall splitter)
(if this-win-2nd (other-window 1))
(set-window-buffer (selected-window) this-win-buffer)
(set-window-buffer (next-window) next-win-buffer)
(select-window first-win)
(if this-win-2nd (other-window 1))))))
(defun beginning-of-line-or-indentation ()
(interactive)
(let ((previous-point (point)))
(back-to-indentation)
(if (equal previous-point (point))
(beginning-of-line))))
(defun indent-region-or-buffer--org-mode (arg)
"Do not indent the entire buffer, only indent active regions.
My org files can get pretty big, and I tend to indent certain parts of them manually as I see fit."
(save-excursion
(when (region-active-p)
(indent-region (region-beginning) (region-end)))))
(defun indent-region-or-buffer--default (arg)
(save-excursion
(if (region-active-p)
(indent-region (region-beginning) (region-end))
(indent-region (point-min) (point-max))))
(when arg (whitespace-cleanup)))
(defun indent-region-or-buffer (arg)
(interactive "P")
(jw--save-current-message
(if (equal major-mode 'org-mode)
(indent-region-or-buffer--org-mode arg)
(indent-region-or-buffer--default arg))))
(defun comment-dwim-dwim (&optional arg)
"When the region is active, then toggle comments over it.
Otherwise, toggle commenting the current line.
If there is a prefix arg, then append a comment to the end of the line instead.
If the prefix arg is 4, then kill the comment on the current line."
(interactive "*P")
(if (region-active-p)
(comment-dwim arg)
(if arg
(if (equal arg 4)
(save-excursion (comment-dwim arg))
(comment-dwim nil))
(comment-or-uncomment-region (line-beginning-position) (line-end-position)))))
(defun open-line-next ()
(interactive)
(end-of-line)
(open-line 1)
(next-line 1)
(indent-according-to-mode))
(defun open-line-previous ()
(interactive)
(beginning-of-line)
(open-line 1)
(indent-according-to-mode))
(defun newline-and-open-line-previous ()
(interactive)
(let ((was-at-end-of-line (equal (point) (line-end-position))))
(newline-and-indent)
(unless was-at-end-of-line (open-line-previous))))
(defun split-window-down-last-buffer-or-scratch (arg)
(interactive "P")
(split-window-vertically)
(other-window 1 nil)
(if arg (scratch-buffer) (switch-to-buffer (other-buffer))))
(defun split-window-right-last-buffer-or-scratch (arg)
(interactive "P")
(split-window-horizontally)
(other-window 1 nil)
(if arg (scratch-buffer) (switch-to-buffer (other-buffer))))
(defun kill-matching-buffers-silently (pattern)
(interactive "sKill buffers matching: ")
(dolist (buffer (buffer-list))
(when (string-match pattern (buffer-name buffer))
(kill-buffer buffer))))
(defun set-transparency (value)
(interactive "n0 - 100 (percent): ")
(set-frame-parameter (selected-frame) 'alpha value))
(defun transparency-on ()
(interactive)
(set-transparency 75))
(defun transparency-off ()
(interactive)
(set-transparency 100))
(defun display-current-prefix-arg (arg)
(interactive "P")
(message "%s" arg))contact
(defun config-insert-author ()
(interactive)
(insert jw-config-author-name))
(defun config-goto-homepage ()
(interactive)
(browse-url jw-config-author-url))
(defun config-goto-github ()
(interactive)
(browse-url jw-config-github-url))emacs
(defun emacs-config ()
(interactive)
(find-file (expand-file-name "emacs.org" user-emacs-directory)))
(defun emacs-private-config ()
(interactive)
(find-file (expand-file-name "private.org" user-emacs-directory)))
(defun emacs-configs-toggle (arg)
(interactive "P")
(if arg
(if (string= (buffer-name) "private.org") (switch-to-buffer (other-buffer)) (emacs-private-config))
(if (string= (buffer-name) "emacs.org") (switch-to-buffer (other-buffer)) (emacs-config))))
(defun emacs-reload-config ()
(interactive)
(load-file (expand-file-name "init.el" user-emacs-directory)))
(defun emacs-archive-packages-and-reload-config ()
(interactive)
(emacs-archive-packages)
(emacs-reload-config))
(defun emacs-archive-packages-and-die ()
(interactive)
(emacs-archive-packages)
(life-is-too-much))
(defun emacs-archive-packages ()
(when (f-exists? package-user-dir)
(let ((archive-dir (format "/tmp/emacs-elpa--%s" (jw--iso-current-time-string))))
(f-move package-user-dir archive-dir))))
(defun emacs-byte-compile-elpa-package-files ()
(interactive)
(-each (f-directories package-user-dir)
(lambda (dir)
(-each (f-entries dir)
(lambda (entry) (when (s-matches? ".*el$" entry) (byte-compile-file entry)))))))key bindings
base-keys (keys not in other parts of this config)
| Key | Function | Scope | Hook | Notes |
|---|---|---|---|---|
| C-z | nil | remove suspend | ||
| C-x C-z | nil | |||
| C-x C-c | life-might-be-too-much | |||
| C-h | nil | remove original help | ||
| C-M-? | help-command | |||
| <return> | toggle-frame-maximized | ctl-x-5-map | ||
| S-<return> | toggle-frame-fullscreen | ctl-x-5-map | ||
| M-! | cmd-dwim | |||
| M-& | cmd-dwim | |||
| C-s | isearch-forward-regexp | |||
| C-r | isearch-backward-regexp | |||
| C-M-g | goto-line | |||
| C-M-9 | winner-undo | |||
| C-M-0 | winner-redo | |||
| t | transpose-windows | ctl-x-4-map | ||
| s | toggle-window-split | ctl-x-4-map | ||
| C-w | kill-region-or-line | |||
| M-w | kill-ring-save-region-or-line | |||
| C-a | beginning-of-line-or-indentation | |||
| C-o | open-line-previous | |||
| C-<return> | open-line-next | |||
| C-j | newline-and-open-line-previous | |||
| C-x 2 | split-window-down-last-buffer-or-scratch | |||
| C-x 3 | split-window-right-last-buffer-or-scratch | |||
| M-; | comment-dwim-dwim | |||
| C-M-\ | indent-region-or-buffer | |||
| M-/ | dabbrev-expand | helm-dabbrev doesn’t work | ||
| C-M-/ | company-complete | |||
| M-g | magit-status | |||
| S-M-SPC | math-symbol-at-point | |||
| C-= | er/expand-region | |||
| C-+ | er/contract-region | |||
| C-? | mc/mark-all-like-this | |||
| C-< | mc/mark-previous-like-this | |||
| C-> | mc/mark-next-like-this | |||
| C-x r t | mc/edit-lines | |||
| M-s j | dumb-jump-go | |||
| M-s J | dumb-jump-go-other-window | |||
| C-c d | docker | |||
| M-<backspace> | nil | sp-keymap | ||
| C-M-p | nil | sp-keymap | ||
| C-M-n | nil | sp-keymap | ||
| C-x m | jw-keymap | |||
| C-c m | jw-keymap | |||
| m | jw-keymap | ctl-x-4-map | ||
| m | jw-keymap | ctl-x-5-map | ||
| ! | cmd-menu | jw-keymap | ||
| & | cmd-menu | jw-keymap | ||
| q | emacs-configs-toggle | jw-keymap | ||
| d | date | jw-keymap | ||
| w | weather | jw-keymap | ||
| b | computer-power-status | jw-keymap | ||
| i | toggle-scratch-buffer | jw-keymap | ||
| I | tmp-scratch-buffer | jw-keymap | ||
| C-c p | projectile-command-map |
(define-prefix-command 'jw-keymap)
(keybinding-org-table 'base-keys)eshell
eshell-keys
| Key | Function | Scope |
|---|---|---|
| e | eshell-e | jw-keymap |
| E | eshell-E | jw-keymap |
(defun eshell-e (arg)
"A wrapper for `eshell', except that this function provides ordered cycling through all eshells creating using prefix arguments."
(interactive "P")
(eshell--exec arg nil))
(defun eshell-E (arg)
"Similar to `eshell-e' except the cycling function is reversed."
(interactive "P")
(eshell--exec arg t))
(defun eshell-cleanup-eshells (arg)
"Kill all eshells. If a prefix arg is provided, then leave the original eshell alive."
(interactive "P")
(-each (eshell--buffers-list)
(lambda (buffer)
(unless (and arg (s-equals? "*eshell*" (buffer-name buffer)))
(kill-buffer buffer)))))
(defun eshell--exec (prefix-arg cycle-backward)
(let ((eshells (eshell--buffer-names-list)))
(if (or prefix-arg
(not (eq major-mode 'eshell-mode))
(not eshells))
(eshell prefix-arg)
(eshell--cycle-to-next eshells cycle-backward))))
(defun eshell--extract-buffer-name-digit (buffer)
(string-to-number (or (car (s-match "[[:digit:]]+" (buffer-name buffer))) "-1")))
(defun eshell--buffers-list-ordering (b1 b2)
(< (eshell--extract-buffer-name-digit b1) (eshell--extract-buffer-name-digit b2)))
(defun eshell--buffers-list ()
(-sort
'eshell--buffers-list-ordering
(-filter
(lambda (buffer) (eq (buffer-local-value 'major-mode buffer) 'eshell-mode))
(buffer-list))))
(defun eshell--buffer-names-list ()
(-map (lambda (b) (buffer-name b)) (eshell--buffers-list)))
(defun eshell--cycle-to-next (eshells cycle-backward)
(let* ((num-eshells (length eshells))
(idx (or (-elem-index (buffer-name) eshells) num-eshells))
(next-idx (mod (if cycle-backward (- idx 1) (+ idx 1)) num-eshells))
(next-eshell (nth next-idx eshells)))
(switch-to-buffer next-eshell)))
(defun eshell--last-command-status-prompt-string ()
(if (= 0 eshell-last-command-status)
""
(propertize (format "-%s-\n" eshell-last-command-status) 'face '(:foreground "red3"))))
(defun eshell--git-prompt-string ()
(require 'vc)
(if (jw--git-root-dir)
;; vc-git-branches returns (list nil) instead of nil when there is no branch name instead of just nil (i.e. after a git-init)
(let* ((git-branch-name (or (car (vc-git-branches)) "(in the beginning there was darkness)"))
(git-is-clean (s-blank? (shell-command-to-string "git status --porcelain")))
(git-is-clean-marker (if git-is-clean "✔" "✘"))
(git-is-clean-color (if git-is-clean "green" "red1"))
(git-branch-name-string (propertize git-branch-name 'face '(:foreground "yellow3")))
(git-is-clean-string (propertize git-is-clean-marker 'face `(:foreground ,git-is-clean-color))))
(format "%s %s" git-branch-name-string git-is-clean-string))
""))
(defun eshell--prompt-function ()
(let* ((last-status-string (eshell--last-command-status-prompt-string))
(dir-string (propertize (abbreviate-file-name (eshell/pwd)) 'face '(:foreground "CornflowerBlue")))
(git-string (eshell--git-prompt-string))
(prompt-string (propertize (if (= (user-uid) 0) "#" "»") 'face '(:foreground "red3")))
(right-pad-string (propertize " " 'face '(:foreground nil)))
(prompt-string (s-collapse-whitespace (format "%s %s %s %s" dir-string git-string prompt-string right-pad-string))))
(concat last-status-string prompt-string)))
(setq eshell-prompt-function 'eshell--prompt-function)
(setq eshell-prompt-regexp "^[^#$»\n]* [#$»] ")
(keybinding-org-table 'eshell-keys)
(require 'em-alias)
(eshell/alias "l" "ls -alh")
(eshell/alias "d" "dired $1")
(eshell/alias "e" "find-file $1")
(eshell/alias "emacs" "find-file $1")
(eshell/alias "vi" "find-file $1")
(eshell/alias "vim" "find-file $1")
(eshell/alias "less" "find-file $1")
(eshell/alias "cat" "find-file $1")
(eshell/alias ":q" "exit")
(eshell/alias ":Q" "exit")
(add-to-list 'eshell-mode-hook (lambda ()
(add-to-list 'eshell-visual-commands "htop")
(add-to-list 'eshell-visual-subcommands '("git" "log" "diff" "show"))
(add-to-list 'eshell-visual-subcommands '("g" "log" "diff" "show"))))
(defun eshell/which--advice--add-login-shell-which-output (eshell/which-function &rest names)
(eshell-printn "\neshell/which:")
(apply eshell/which-function names)
(let* ((login-shell-program (jw--login-shell))
(raw-result (shell-command-to-string (format "%s -c \"which %s\"" login-shell-program (s-join " " names))))
(login-shell-which-result (format "\n%s's which:\n%s" login-shell-program raw-result)))
(eshell-printn login-shell-which-result)))
(advice-add 'eshell/which :around 'eshell/which--advice--add-login-shell-which-output)
ansi-term additions
(defun eshell/ansi (&rest args)
(interactive)
(ansi-term (jw--login-shell))
(when args
(insert (s-join " " args))
(term-send-input)))
(setq ansi-term-kill-on-exit t)
(defun ansi-term-life-is-too-much ()
(interactive)
(if (not ansi-term-kill-on-exit)
(bury-buffer)
(kill-buffer (current-buffer))))
(defun ansi-term--exit-hook ()
(let ((ansi-process (get-buffer-process (current-buffer))))
(jw--do-when-process-finishes ansi-process
(lambda (proc)
(switch-to-buffer (process-buffer proc))
(ansi-term-life-is-too-much)))))
(add-hook 'term-mode-hook 'ansi-term--exit-hook)yasnippet
yas-keys
| Key | Function |
|---|---|
| M-? | yas-dwim |
(defun yas-dwim (arg)
(interactive "P")
(if (equal arg 4) (yas-new-snippet)
(if arg (yas-visit-snippet-file)
(yas-insert-snippet))))
(yas-global-mode 1)
(keybinding-org-table 'yas-keys)
(setq yas-indent-line nil)
(setq yas-dynamic-snippets-dir (f-expand "snippets-dynamic" user-emacs-directory))
(add-to-list 'yas-snippet-dirs yas-dynamic-snippets-dir)
(defun yas-write-dynamic-snippet (mode shortcut contents)
(let* ((mode-string (jw--symbol-name mode))
(shortcut-string (jw--symbol-name shortcut))
(file-location (f-expand (format "%s/%s" mode-string shortcut-string) yas-dynamic-snippets-dir))
(file-contents-format-string "# -*- mode: snippet -*-\n# name: %s\n# key: %s_\n# --\n%s")
(file-contents (format file-contents-format-string shortcut-string shortcut-string contents)))
(jw--write-to-file file-contents file-location)))rcirc
(require 'rcirc)
(defun rcirc-connect-dwim (&optional server port nick user-name full-name startup-channels password encryption)
"Alternative to `rcirc-connect'.
If the server is not connected, then connect to it.
If no server is provided, then a prompt will ask the user for a server.
If the server is connected, then toggle to it's process buffer.
If the server is connected and a prefix arg is provided, then invoke a quick /msg on the server and toggle back to the other-buffer."
(interactive)
(if server
(let ((existing-sp (get-process server)))
(if (process-live-p existing-sp)
(if current-prefix-arg
(save-window-excursion
(switch-to-buffer (process-buffer existing-sp))
(call-interactively 'rcirc-cmd-msg))
(switch-to-buffer (process-buffer existing-sp)))
(rcirc-connect server port nick user-name full-name startup-channels password encryption)))
(rcirc t)))
(setq rcirc-buffer-maximum-lines 2000)
(add-to-list 'rcirc-omit-responses "MODE")
(custom-set-faces '(rcirc-my-nick ((t (:foreground "#00ffff"))))
'(rcirc-other-nick ((t (:foreground "#90ee90"))))
'(rcirc-server ((t (:foreground "#a2b5cd"))))
'(rcirc-server-prefix ((t (:foreground "#00bfff"))))
'(rcirc-timestamp ((t (:foreground "#7d7d7d"))))
'(rcirc-nick-in-message ((t (:foreground "#00ffff"))))
'(rcirc-prompt ((t (:foreground "#00bfff"))))
'(rcirc-keyword ((t :foreground "#00ffff")))
'(rcirc-nick-in-message-full-line ((t ())))
'(rcirc-track-nick ((t (:foreground "#00ffff"))))
'(rcirc-track-keyword ((t (:foreground "#00ffff")))))
(defun rcirc-hook--initial-config ()
(jw--save-current-message
(turn-on-flyspell)
(rcirc-track-minor-mode t)
(rcirc-omit-mode)
(cd (getenv "HOME"))))
(add-hook 'rcirc-mode-hook 'rcirc-hook--initial-config)
(defun rcirc-hook--span-window-width ()
(setq rcirc-fill-column (- (window-width) 2)))
(add-hook 'window-configuration-change-hook 'rcirc-hook--span-window-width)
(defun rcirc-handler-NOTICE--advice--ignore-KEEPALIVE (original-function &rest args)
(let* ((function-args (nth 2 args))
(msg (cadr function-args)))
(unless (string-match "keepalive" msg)
(apply original-function args))))
(advice-add 'rcirc-handler-NOTICE :around 'rcirc-handler-NOTICE--advice--ignore-KEEPALIVE)here are some useful rcirc configs to set in in the safe private location
(setq rcirc-default-nick "nick"
rcirc-default-user-name "username"
rcirc-default-full-name "full name"
rcirc-keywords '("nick1" "nick2")
rcirc-server-alist '(("irc.freenode.net"
:port 6697
:encryption tls
:user-name "freenode username"
:password "free node pass"
:channels ("##doctorwho"))))example of defining specific functions to connect to various irc servers
(defun freenode-irc-connect ()
(interactive)
(rcirc-connect-dwim "irc.freenode.net" 6697 "nick" "username" "full name" '("##doctorwho" "#emacs") "your password" 'tls)
(defun twitch-irc-connect ()
(interactive)
(rcirc-connect-dwim "irc.chat.twitch.tv" 6667 "nick" "username" "full name" nil "your password"))helm
helm-keys
| Key | Function | Scope | Hook | Notes |
|---|---|---|---|---|
| C-c h | helm-command-prefix | |||
| C-x c | nil | undo default helm prefix | ||
| M-x | helm-M-x | |||
| M-: | helm-eval-expression-with-eldoc | |||
| M-* | helm-calcul-expression | |||
| C-x C-b | helm-buffers-list | |||
| C-x C-f | helm-find-files | |||
| M-y | helm-show-kill-ring | |||
| M-s s | helm-do-grep-ag | |||
| M-s o | helm-occur | |||
| M-s i | helm-semantic-or-imenu | |||
| C-x r l | helm-bookmarks | |||
| C-x r j | helm-register-jump-dwim | |||
| C-h a | helm-apropos | |||
| C-h b | helm-descbinds | |||
| C-h r | helm-info-emacs | |||
| C-h d | helm-info-at-point | |||
| C-h i | helm-info | |||
| h | helm-descbinds | helm-command-map | ||
| M-s s | helm-ff-run-grep-ag | helm-find-files-map | ||
| C-s | helm-ff-run-grep-ag | helm-find-files-map | ag instead of grep | |
| C-c ! l | helm-flycheck | flycheck-mode-map | ||
| C-M-i | helm-flyspell-correct | flyspell-mode-map | ||
| <tab> | helm-esh-pcomplete | eshell-mode-map | eshell-mode-hook | |
| M-p | helm-eshell-history | eshell-mode-map | eshell-mode-hook |
(require 'helm)
(require 'helm-config)
(require 'helm-dabbrev)
(setq helm-split-window-in-side-p t
helm-ff-search-library-in-sexp t
helm-scroll-amount 8
helm-buffer-max-length nil
helm-ff-file-name-history-use-recentf t
helm-quick-update t
helm-move-to-line-cycle-in-source nil
helm-mode-fuzzy-match t
helm-completion-in-region-fuzzy-match t
helm-case-fold-search t
helm-ag-insert-at-point 'symbol
helm-show-completion-display-function nil ;; do not use separate window for completion selection
)
(when (eq system-type 'darwin)
(setq helm-man-format-switches "%s"))
(defalias 'kill-ring-show 'helm-show-kill-ring)
(defalias 'list-colors-display 'helm-colors)
(defalias 'proced 'helm-top)
(defun helm-register-jump-dwim (arg)
(interactive "P")
(if arg (helm-register) (call-interactively 'jump-to-register)))
(set-face-attribute 'helm-source-header nil :height 1.0 :weight 'normal :family (jw--font-name) :box '(:style released-button))
(set-face-attribute 'helm-candidate-number nil :background jw--mode-line-color :foreground "goldenrod")
(keybinding-org-table 'helm-keys)
(helm-mode 1)
(helm-autoresize-mode 1)
(projectile-global-mode)
(helm-projectile-on)
(setq projectile-completion-system 'helm
projectile-mode-line "" ;; this slowed tramp down sometimes
projectile-switch-project-action 'helm-projectile)
(when (executable-find "ag")
(setq helm-grep-ag-command "ag -i --nogroup --nocolor --line-numbers %s %s %s")
(setq helm-ag-base-command "ag -i --nogroup --nocolor --line-numbers"))
(defun helm-projectile-projects-helm-projectile-ag (dir)
(interactive)
(with-temp-buffer
(let ((default-directory dir))
(call-interactively 'helm-projectile-ag))))
(helm-add-action-to-source "Ag in project `M-s a'" 'helm-projectile-projects-helm-projectile-ag helm-source-projectile-projects)
(helm-projectile-define-key helm-projectile-projects-map (kbd "M-s s") 'helm-projectile-projects-helm-projectile-ag)
(helm-projectile-define-key helm-projectile-projects-map (kbd "C-s") 'helm-projectile-projects-helm-projectile-ag) ;; hijack grep's keybinding
(defalias 'projectile-empty-garbage 'projectile-cleanup-known-projects)
(defun projectile-clear-known-projects--advice--ask-y-or-n (original-function)
(if (yes-or-no-p "This will REMOVE ALL projects from projectile. Are you sure?")
(apply original-function)
(message "Did NOT clear the projectile projects.")))
(advice-add 'projectile-clear-known-projects :around 'projectile-clear-known-projects--advice--ask-y-or-n)
(add-to-list 'helm-dabbrev-major-mode-assoc '(scala-mode . sbt-mode))
make company-complete dropdown look more like helm
(require 'company)
(custom-set-faces `(company-tooltip ((t (:background ,jw--mode-line-color))))
`(company-scrollbar-bg ((t (:background "black"))))
`(company-scrollbar-fg ((t (:background "#005858"))))
`(company-tooltip-selection ((t (:inherit 'helm-selection))))
`(company-tooltip-common ((t (:inherit 'helm-match))))
`(company-tooltip-common-selection ((t (:inherit 'helm-match))))
`(company-tooltip-annotation ((t (:inherit 'helm-bookmark-file))))
`(company-preview-common ((t :inherit 'company-echo)))
`(company-echo-common ((t :inherit 'company-echo)))
`(company-template-field ((t :inherit 'helm-match-item))))org
org-keys
| Key | Function | Scope | Hook |
|---|---|---|---|
| o | jw-todo | jw-keymap | |
| a | org-agenda | jw-keymap | |
| A | jw-org-agenda | jw-keymap | |
| c | jw-org-capture | jw-keymap | |
| <tab> | org-pomodoro | jw-keymap | |
| C-c < | org-time-stamp | local | org-mode-hook |
| C-c . | org-time-stamp-inactive | local | org-mode-hook |
| C-c C-x g | org-feed-update-all-or-one | local | org-mode-hook |
(require 'org)
(require 'org-pomodoro)
(unless (boundp 'jw-org-todo-file)
(setq jw-org-todo-file (f-expand "todo.org" user-emacs-directory)))
(defun jw-todo ()
(interactive)
(if (s-equals? (buffer-name) (f-filename jw-org-todo-file))
(switch-to-buffer (other-buffer))
(find-file jw-org-todo-file)
(cd (getenv "HOME"))))
(setq jw-org-agenda-pre-hook nil)
(defun jw-org-agenda (arg)
"Enriched `org-agenda' that runs `jw-org-agenda-pre-hook' before `org-agenda' is opened. `org-agenda-mode-hook' can be used for a post-hook"
(interactive "P")
(run-hooks 'jw-org-agenda-pre-hook)
(org-agenda arg))
(defun org-feed-update-all-or-one (arg)
"When called with a prefix argument, interactively call `org-feed-update'. Otherwise call `org-feed-update-all'."
(interactive "P")
(if arg
(call-interactively 'org-feed-update)
(org-feed-update-all)))
(defun org-id (arg)
"Ensure an org-id exists and copy to kill ring. With prefix arg, force creation of a new org-id."
(interactive "P")
(org-id-get-create arg)
(org-id-copy))
(defun jw-org-capture (arg)
(interactive "P")
(if arg
(org-capture '(16))
(helm-org-capture-templates)))
(keybinding-org-table 'org-keys)
(add-to-list 'org-latex-packages-alist '("" "physics"))
(setq org-latex-remove-logfiles nil) ;; evaluating latex blocks was causing errors because ox-latex couldn't find the logfiles
(setq org-latex-caption-above '(image table src-block special-block))
(setq org-use-speed-commands t
org-enforce-todo-dependencies t
org-enforce-todo-checkbox-dependencies t
org-return-follows-link t
org-hide-leading-stars t
org-clock-clocked-in-display 'mode-line
org-refile-targets '((org-agenda-files :maxlevel . 10))
org-refile-use-outline-path t
org-refile-allow-creating-parent-nodes '(confirm)
org-tags-column -100
org-src-preserve-indentation t
org-src-tab-acts-natively t
org-src-window-setup 'current-window
org-cycle-open-archived-trees t
org-hide-block-startup t
org-ellipsis " …"
org-fontify-done-headline t
org-todo-keywords '((sequence "⚑" "⚐" "|" "✔"))
org-agenda-todo-list-sublevels nil
org-startup-with-inline-images t
org-confirm-babel-evaluate nil
org-confirm-shell-link-function nil
org-confirm-elisp-link-function nil
org-id-link-to-org-use-id 'create-if-interactive
org-agenda-window-setup 'only-window)
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)
(setq org--todo-todo-boxed-states '("todo" "incoming" "captured" "unread" "question")
org--todo-todo-states '("⚑")
org--blocked-todo-boxed-states '("blocked" "halted" "stalled" "paused")
org--doing-todo-boxed-states '("doing" "going")
org--doing-todo-states '("⚐")
org--delegated-todo-boxed-states '("delegated" "assigned" "pr" "waiting" "deploying")
org--done-todo-boxed-states '("done" "cancelled" "canceled" "finished" "boom" "read" "answered")
org--done-todo-states '("✘" "✔"))
(defun org--red-box-state (s) `(,s :background "DarkRed" :foreground white :box (:style released-button)))
(defun org--red-state (s) `(,s :foreground "Coral"))
(defun org--blue-box-state (s) `(,s :background "DeepSkyBlue4" :foreground white :box (:style released-button)))
(defun org--blue-state (s) `(,s :foreground "DeepSkyBlue1"))
(defun org--green-box-state (s) `(,s :background "DarkGreen" :foreground white :box (:style released-button)))
(defun org--green-state (s) `(,s :foreground "LimeGreen"))
(setq org-todo-keyword-faces (append (mapcar 'org--red-box-state org--todo-todo-boxed-states)
(mapcar 'org--red-box-state (mapcar 'upcase org--todo-todo-boxed-states))
(mapcar 'org--red-box-state org--blocked-todo-boxed-states)
(mapcar 'org--red-box-state (mapcar 'upcase org--blocked-todo-boxed-states))
(mapcar 'org--red-state org--todo-todo-states)
(mapcar 'org--blue-box-state org--doing-todo-boxed-states)
(mapcar 'org--blue-box-state (mapcar 'upcase org--doing-todo-boxed-states))
(mapcar 'org--blue-box-state org--delegated-todo-boxed-states)
(mapcar 'org--blue-box-state (mapcar 'upcase org--delegated-todo-boxed-states))
(mapcar 'org--blue-state org--doing-todo-states)
(mapcar 'org--green-box-state org--done-todo-boxed-states)
(mapcar 'org--green-box-state (mapcar 'upcase org--done-todo-boxed-states))
(mapcar 'org--green-state org--done-todo-states)
))
(setq org-pomodoro-format "Pomodoro %s"
org-pomodoro-short-break-format "Short Break %s"
org-pomodoro-long-break-format "Long Break %s"
org-pomodoro-ask-upon-killing nil
org-pomodoro-short-break-sound-p nil
org-pomodoro-long-break-sound-p nil)
(custom-set-faces `(org-headline-done ((t (:inherit shadow))))
`(org-pomodoro-mode-line ((t (:foreground "#2aa198"))))
`(org-link ((t (:underline nil))))
`(org-date ((t (:underline nil)))))
(defun org-babel-src-yasnippet (ob-lang &optional ob-src-header-override)
(let* ((yas-src-shortcut (concat "src-" (jw--symbol-name ob-lang)))
(ob-src-string (format "#+BEGIN_SRC %s\n$0\n#+END_SRC" (jw--symbol-name (or ob-src-header-override ob-lang)))))
(yas-write-dynamic-snippet 'org-mode yas-src-shortcut ob-src-string)))
(defun org-babel-support-langs (langs)
(org-babel-do-load-languages 'org-babel-load-languages (-map (lambda (lang) `(,lang . t)) langs))
(-each langs (lambda (lang) (org-babel-src-yasnippet lang))))
(org-babel-support-langs
(list 'awk 'calc 'C 'dot 'emacs-lisp 'haskell 'http 'java 'js 'latex 'lisp
'makefile 'matlab 'org 'perl 'plantuml 'python 'R 'ruby 'scheme 'shell 'sql 'translate))
(add-to-list 'org-src-lang-modes '("dot" . graphviz-dot)) ;; "dot" src blocks don't use graphviz-dot-mode by default
(org-babel-src-yasnippet 'bash)
(org-babel-src-yasnippet 'markdown)
(org-babel-src-yasnippet 'gfm)
(org-babel-src-yasnippet 'conf)
(org-babel-src-yasnippet 'text)
(org-babel-src-yasnippet 'json)
(org-babel-src-yasnippet "translate :src es :dest en")
(org-babel-src-yasnippet "translate :src en :dest es")
(setq org-babel-default-header-args:sh '((:results . "output"))
org-babel-default-header-args:shell '((:results . "output"))
org-babel-default-header-args:bash '((:results . "output"))
org-babel-default-header-args:js '((:results . "output")) ;; doesn't work with "value" for some reason, it just prints "undefined"
org-babel-default-header-args:python '((:results . "output")) ;; doesn't work with "value" for some reason, it just prints "None"
org-babel-default-header-args:http '((:pretty . "yes")))support cmd function in org-babel and cmd org link
(defconst org-babel-header-args:cmd '((bg . :any) (tmux . :any)))
;; warning: cmd does not work with the :async header since ob-cmd is never provided (which org-babel-do-load-languages requires)
(defun org-babel-execute:cmd (body params)
(let* ((bg-option (assoc :bg params))
(in-bg (and bg-option (not (string= (cdr bg-option) "no"))))
(tmux-option (assoc :tmux params))
(tmux-session (or (cdr tmux-option) "emacs")))
(if tmux-option
(progn (cmd-tmux body tmux-session) (format "Sent to tmux session: %s" tmux-session))
(progn
(cmd body)
(when in-bg (switch-to-buffer (other-buffer)))
"Running command"))))
(add-to-list 'org-src-lang-modes '("cmd" . sh))
(define-derived-mode cmd-mode sh-mode "cmd")
(setq org-babel-default-header-args:cmd '((:results . "silent")))
(org-babel-src-yasnippet 'cmd)
(org-babel-src-yasnippet 'tmux "cmd :tmux")
(add-to-list 'org-link-parameters '("cmd" :follow (lambda (ref) (cmd ref))))
(add-to-list 'org-link-parameters '("cmd+tmux" :follow (lambda (ref) (cmd-tmux ref))))support gist and gist+raw org links
(defun org-gist-link-follow (ref &optional raw)
(let ((url-segment (if (s-contains? "/" ref) ref
(concat (or (jw--git-config-get "github.user") (jw--git-config-get "user.name")) "/" ref)))
(raw-segment (if raw "raw" "")))
(browse-url (format "https://gist.github.com/%s/%s" url-segment raw-segment))))
(add-to-list 'org-link-parameters '("gist" :follow (lambda (ref) (org-gist-link-follow ref))))
(add-to-list 'org-link-parameters '("gist+raw" :follow (lambda (ref) (org-gist-link-follow ref 'raw))))hacky way of using org tables for markdown tables copied from stackoverflow
(require 'org-table)
(defun markdown-cleanup-org-tables ()
(interactive)
(when (or (eq major-mode 'markdown-mode) (eq major-mode 'gfm-mode))
(save-excursion
(goto-char (point-min))
(while (search-forward "-+-" nil t) (replace-match "-|-")))))
(add-hook 'markdown-mode-hook 'turn-on-orgtbl)
(advice-add 'org-table-align :after 'markdown-cleanup-org-tables)
(defalias 'markdown-table-create 'org-table-create)
(defalias 'markdown-table-insert-column 'org-table-insert-column)
(defalias 'markdown-table-delete-column 'org-table-delete-column)
(defalias 'markdown-table-insert-row 'org-table-insert-row)
(defalias 'markdown-table-delete-row 'org-table-delete-row)
scala
scala-keys
| Key | Function | Scope |
|---|---|---|
| C-c s | sbt-command-prefix | |
| s | jw-sbt | sbt-keymap |
| c | sbt-compile | sbt-keymap |
| o | sbt-test-only-current-test | sbt-keymap |
| l | sbt-run-previous-command | sbt-keymap |
(defun jw-sbt ()
(interactive)
(if (eq major-mode 'sbt-mode)
(switch-to-buffer (other-buffer))
(with-temp-buffer
(if (sbt:find-root)
(sbt-start)
(call-interactively 'jw-sbt-run-or-create-new)))))
(defun jw-sbt-run-or-create-new (dir)
(interactive "DSBT run or create new project in: ")
(when (not (f-exists? dir)) (make-directory dir 'make-parents))
(let ((default-directory dir))
(with-temp-buffer
(if (sbt:find-root)
(sbt-start)
(cmd "sbt-new")))))
(defun sbt-current-tests-in-buffer ()
(interactive)
(save-excursion
(let* ((pkg-name-components)
(test-names))
(goto-char (point-min))
(while (re-search-forward "package " nil t)
(push (filter-buffer-substring (point) (point-at-eol)) pkg-name-components))
(goto-char (point-min))
(while (re-search-forward "\\(object\\|class\\) " nil t)
(push (filter-buffer-substring (point) (progn (re-search-forward " ")
(forward-char -1)
(point)))
test-names))
(let* ((full-pkg-name (string-join (reverse pkg-name-components) "."))
(full-test-names (mapcar #'(lambda (test-name) (string-join (list full-pkg-name "." test-name))) test-names))
(full-test-names-str (string-join full-test-names " ")))
(message full-test-names-str)))))
(defun sbt-test-only-current-test (only-zzz)
(interactive "P")
(if only-zzz
(sbt-command (concat "testOnly " (sbt-current-tests-in-buffer) " -- showtimes -- ex zzz"))
(sbt-command (concat "testOnly " (sbt-current-tests-in-buffer) " -- showtimes"))))
(defun sbt-compile (test-compile)
(interactive "P")
(if test-compile
(sbt-command "test:compile")
(sbt-command "compile")))
(setq sbt-keymap (make-sparse-keymap))
(fset 'sbt-command-prefix sbt-keymap)
(keybinding-org-table 'scala-keys)
(add-to-list 'auto-mode-alist '("\\.scala$" . scala-mode))
(add-to-list 'auto-mode-alist '("\\.sbt$" . scala-mode))
(setq scala-indent:align-forms t
scala-indent:align-parameters t)support ammonite repl in org babel, requires `amm` command, or ammonite-repl
(require 'org)
(require 'ob)
(defun org-babel-execute:ammonite (body params)
(jw--write-to-file body "/tmp/ob-ammonite-input.scala")
(shell-command-to-string "amm --silent /tmp/ob-ammonite-input.scala"))
(add-to-list 'org-src-lang-modes '("ammonite" . scala))
(org-babel-src-yasnippet 'ammonite)
(org-babel-src-yasnippet 'scala "ammonite") ;; default ob-scala requires brew scala & ensime, which I don't use.adding sbt shortcut to helm projectile
(require 'helm-projectile)
;; sbt mode uses some local variables which causes issues from inside of the helm and switching between multiple projects
;; e.g. `sbt:buffer-project-root'
;; using with-temp-buffer to avoid that
(defun helm-projectile-projects-sbt (dir)
(interactive)
(with-temp-buffer
(let ((default-directory dir)) (call-interactively 'jw-sbt))))
(defun helm-projectile-projects-sbt-compile (dir)
(interactive)
(with-temp-buffer (let ((default-directory dir)) (call-interactively 'sbt-compile))))
(helm-add-action-to-source "Dispatch sbt `C-c s ...'" 'helm-projectile-projects-sbt helm-source-projectile-projects)
(helm-projectile-define-key helm-projectile-projects-map (kbd "C-c s s") 'helm-projectile-projects-sbt)
(helm-projectile-define-key helm-projectile-projects-map (kbd "C-c s c") 'helm-projectile-projects-sbt-compile)remove flycheck from *.sbt files
(defun disable-flycheck-scala-in-sbt-files ()
(when (and buffer-file-name (s-equals? "sbt" (file-name-extension buffer-file-name)))
(flycheck-mode -1)))
(add-hook 'scala-mode-hook 'disable-flycheck-scala-in-sbt-files)sonic pi
sonic-pi-keys
| Key | Function | Scope |
|---|---|---|
| m | sonic-pi-stop-or-play | jw-keymap |
(require 'org)
(require 'ob)
(defun sonic-pi-play (&optional ruby)
"Sends snippet of ruby code to Sonic Pi GUI application via a custom shell script."
(interactive)
(let ((prepared-ruby (or ruby (if (region-active-p)
(buffer-substring-no-properties (point) (mark))
(buffer-substring-no-properties (point-min) (point-max))))))
(shell-command (format "echo '%s' | sonic-pi" prepared-ruby))))
(defun sonic-pi-stop ()
(interactive)
(shell-command "sonic-pi stop"))
(defun sonic-pi-stop-or-play (arg)
(interactive "P")
(if arg (sonic-pi-stop) (sonic-pi-play)))
(keybinding-org-table 'sonic-pi-keys)
;; warning: sonic-pi does not work with the :async header since ob-sonic-pi is never provided (which org-babel-do-load-languages requires)
(defun org-babel-execute:sonic-pi (body params)
(sonic-pi-play body)
"Sent to Sonic Pi")
(add-to-list 'org-src-lang-modes '("sonic-pi" . ruby))
(define-derived-mode sonic-pi-mode ruby-mode "sonic-pi")
(setq org-babel-default-header-args:sonic-pi '((:results . "silent")))
(org-babel-src-yasnippet 'sonic-pi)private
load the private directory and the private.org file if they exist
(let ((path (expand-file-name "private" user-emacs-directory)))
(when (file-exists-p path)
(add-to-list 'load-path path)
(mapcar 'load-file (directory-files path t "\.el$"))))
(let ((private-org (expand-file-name "private.org" user-emacs-directory)))
(when (file-exists-p private-org)
(org-babel-load-file private-org)))finally
(yas-reload-all)
(scratch-buffer)
(transparency-on)
(cd (getenv "HOME"))
(toggle-frame-maximized)
(unless (server-running-p) (server-start))