Skip to content
No description, website, or topics provided.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
snippets
.gitignore
README.org
emacs.org
init.el

README.org

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.d

You 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 segments

Now, 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 installed

languages

(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 upgrade

helper 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)

KeyFunctionScopeHookNotes
C-znilremove suspend
C-x C-znil
C-x C-clife-might-be-too-much
C-hnilremove original help
C-M-?help-command
<return>toggle-frame-maximizedctl-x-5-map
S-<return>toggle-frame-fullscreenctl-x-5-map
M-!cmd-dwim
M-&cmd-dwim
C-sisearch-forward-regexp
C-risearch-backward-regexp
C-M-ggoto-line
C-M-9winner-undo
C-M-0winner-redo
ttranspose-windowsctl-x-4-map
stoggle-window-splitctl-x-4-map
C-wkill-region-or-line
M-wkill-ring-save-region-or-line
C-abeginning-of-line-or-indentation
C-oopen-line-previous
C-<return>open-line-next
C-jnewline-and-open-line-previous
C-x 2split-window-down-last-buffer-or-scratch
C-x 3split-window-right-last-buffer-or-scratch
M-;comment-dwim-dwim
C-M-\indent-region-or-buffer
M-/dabbrev-expandhelm-dabbrev doesn’t work
C-M-/company-complete
M-gmagit-status
S-M-SPCmath-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 tmc/edit-lines
M-s jdumb-jump-go
M-s Jdumb-jump-go-other-window
C-c ddocker
M-<backspace>nilsp-keymap
C-M-pnilsp-keymap
C-M-nnilsp-keymap
C-x mjw-keymap
C-c mjw-keymap
mjw-keymapctl-x-4-map
mjw-keymapctl-x-5-map
!cmd-menujw-keymap
&cmd-menujw-keymap
qemacs-configs-togglejw-keymap
ddatejw-keymap
wweatherjw-keymap
bcomputer-power-statusjw-keymap
itoggle-scratch-bufferjw-keymap
Itmp-scratch-bufferjw-keymap
C-c pprojectile-command-map
(define-prefix-command 'jw-keymap)
(keybinding-org-table 'base-keys)

eshell

eshell-keys

KeyFunctionScope
eeshell-ejw-keymap
Eeshell-Ejw-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

KeyFunction
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

KeyFunctionScopeHookNotes
C-c hhelm-command-prefix
C-x cnilundo default helm prefix
M-xhelm-M-x
M-:helm-eval-expression-with-eldoc
M-*helm-calcul-expression
C-x C-bhelm-buffers-list
C-x C-fhelm-find-files
M-yhelm-show-kill-ring
M-s shelm-do-grep-ag
M-s ohelm-occur
M-s ihelm-semantic-or-imenu
C-x r lhelm-bookmarks
C-x r jhelm-register-jump-dwim
C-h ahelm-apropos
C-h bhelm-descbinds
C-h rhelm-info-emacs
C-h dhelm-info-at-point
C-h ihelm-info
hhelm-descbindshelm-command-map
M-s shelm-ff-run-grep-aghelm-find-files-map
C-shelm-ff-run-grep-aghelm-find-files-mapag instead of grep
C-c ! lhelm-flycheckflycheck-mode-map
C-M-ihelm-flyspell-correctflyspell-mode-map
<tab>helm-esh-pcompleteeshell-mode-mapeshell-mode-hook
M-phelm-eshell-historyeshell-mode-mapeshell-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

KeyFunctionScopeHook
ojw-todojw-keymap
aorg-agendajw-keymap
Ajw-org-agendajw-keymap
cjw-org-capturejw-keymap
<tab>org-pomodorojw-keymap
C-c <org-time-stamplocalorg-mode-hook
C-c .org-time-stamp-inactivelocalorg-mode-hook
C-c C-x gorg-feed-update-all-or-onelocalorg-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

KeyFunctionScope
C-c ssbt-command-prefix
sjw-sbtsbt-keymap
csbt-compilesbt-keymap
osbt-test-only-current-testsbt-keymap
lsbt-run-previous-commandsbt-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

KeyFunctionScope
msonic-pi-stop-or-playjw-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))
You can’t perform that action at this time.