legacy-dotfiles/emacs/init.el
Tom Willemse a134eef988 Use init.el directly again
I'm getting tired of maintaining a such a document...
2013-06-13 23:21:13 +02:00

1156 lines
39 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; init.el --- My Emacs init
;;; Commentary:
;;; Code:
(require 'uniquify)
(eval-when-compile
(require 'cl)
(require 'esh-io)
(require 'esh-proc)
(require 'dash))
(autoload 'define-slime-contrib "slime")
(autoload 'gtags-mode "gtags" nil t)
(autoload 'jabber-connect "jabber" nil t)
(autoload 'jabber-message-libnotify "jabber-libnotify")
(autoload 'jabber-muc-libnotify "jabber-libnotify")
(autoload 'php-mode "php-mode" nil t)
(autoload 'po-mode "po-mode" nil t)
(autoload 'pony-mode "pony-mode" nil t)
(autoload 'sawfish-mode "sawfish" nil t)
(autoload 'server-running-p "server")
(autoload 'slime-js-minor-mode "slime-js" nil t)
(autoload 'tagedit-mode "tagedit" nil t)
(autoload 'w3m-bookmark-view "w3m" nil t)
(autoload 'w3m-goto-url "w3m" nil t)
(autoload 'xmodmap-mode "xmodmap-mode" nil t)
(defadvice org-agenda-redo (after ext:org-agenda-redo-add-appts)
"Pressing `r' on the agenda will also add appointments."
(progn
(setq appt-time-msg-list nil)
(org-agenda-to-appt)))
(defadvice term-handle-exit (after oni:kill-buffer-after-exit activate)
"Kill the term buffer if the process finished."
(kill-buffer (current-buffer)))
(defmacro eval-after-init (&rest body)
"Defer execution of BODY until after Emacs init."
(declare (indent 0))
`(add-hook 'emacs-startup-hook #'(lambda () ,@body)))
(defmacro mode-hooks (&rest lst)
"Apply `add-mode-hooks' to each element of LST."
(declare (indent 0))
`(progn
,@(level (mapcar
#'(lambda (itm)
(add-mode-hooks (car itm) (list 'quote (cadr itm)))) lst))))
(defmacro stante-after (feature &rest forms)
"After FEATURE is loaded, evaluate FORMS.
FEATURE may be an unquoted feature symbol or a file name, see
`eval-after-load'."
(declare (indent 1) (debug t))
;; Byte compile the body. If the feature is not available, ignore
;; warnings. Taken from
;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2012-11/msg01262.html
(let ((loaded (if (symbolp feature)
(require feature nil :no-error)
(load feature :no-error :no-message))))
`(,(if loaded
'progn
(message "stante-after: cannot find %s" feature)
'with-no-warnings)
(eval-after-load ',feature
`(funcall (function ,(lambda () ,@forms)))))))
(eval-and-compile
(defun add-hooks (hooks function &optional append local)
"`add-hook' for each in HOOKS."
(mapcar (lambda (h)
`(add-hook (quote ,h) ,function ,append ,local))
hooks))
(defun add-mode-hooks (modes function &optional append local)
"`add-hooks' with MODES renamed to mode-mode-hook."
(let ((mode-names (mapcar #'make-mode-hook-name modes)))
(add-hooks mode-names function append local))))
(defun enable (functions)
"Set the `disabled' property for each item in FUNCTIONS to nil."
(mapc #'(lambda (f) (put f 'disabled nil)) functions))
(defun hostname ()
"Get the current machine's hostname."
(substring (shell-command-to-string "hostname") 0 -1))
(defun indent-defun ()
"Indent the current defun."
(interactive)
(save-excursion
(mark-defun)
(indent-region (region-beginning) (region-end))))
(eval-when-compile
(defun level (lst)
(let ((lsts (mapcar (lambda (l) (if (listp l) l (list l))) lst)))
(apply #'append lsts))))
(defun loadpath-add-and-autoload (path)
"Add PATH to `load-path' and load a `loaddefs.el' if it exists."
(add-to-list 'load-path path)
(let ((loaddefs (concat path "/loaddefs.el")))
(when (file-exists-p loaddefs)
(load loaddefs))))
(eval-and-compile
(defun make-mode-hook-name (mode)
"Get the hook name for MODE."
(intern (concat (symbol-name mode) "-mode-hook"))))
(defun move-beginning-of-dwim ()
"Move to beginning of line either after indentation or before."
(interactive)
(let ((start (point)))
(back-to-indentation)
(if (= start (point))
(move-beginning-of-line 1))))
(defun oni-eshell-prompt ()
"Show a pretty shell prompt."
(let ((status (if (zerop eshell-last-command-status) ?+ ?-))
(hostname (hostname))
(dir (abbreviate-file-name (eshell/pwd)))
(branch
(shell-command-to-string
"git branch --contains HEAD 2>/dev/null | sed -e '/^[^*]/d'")))
(concat
(propertize (char-to-string status)
'face `(:foreground ,(if (= status ?+)
"green"
"red")))
" "
(propertize hostname 'face 'mode-line-buffer-id)
" "
(propertize (oni:shorten-dir dir) 'face 'font-lock-string-face)
" "
(when (not (string= branch ""))
(propertize
;; Cut off "* " and "\n"
(substring branch 2 -1)
'face 'font-lock-function-name-face))
" \n> ")))
(defun pp^L-ruler (win)
"Just make a string ruler.
Of either `fci-rule-column' or `fill-column' length -1. Use the
`-' character. WIN is ignored."
(ignore win)
(make-string
(1- (if (boundp 'fci-rule-column) fci-rule-column fill-column)) ?-))
(defun raise-eshell ()
"Start or switch back to `eshell'.
Also change directories to current working directory."
(interactive)
(let ((dir (file-name-directory
(or (buffer-file-name) "~/")))
(hasfile (not (eq (buffer-file-name) nil)))
(started (and (boundp 'eshell-buffer-name) eshell-buffer-name
(buffer-live-p (get-buffer eshell-buffer-name)))))
(eshell)
(when (and hasfile (eq eshell-process-list nil))
(eshell/cd dir)
(when started
(eshell-reset)))))
(defun reload-buffer ()
"Reload current buffer."
(interactive)
(revert-buffer nil t nil))
(defun set-smartparens-keys ()
(local-set-key [remap backward-delete-char] 'sp-backward-delete-char)
(local-set-key [remap delete-char] 'sp-delete-char)
(local-set-key [remap kill-word] 'sp-kill-word)
(local-set-key [remap backward-kill-word] 'sp-backward-kill-word)
(local-set-key (kbd "<C-left>") 'sp-forward-barf-sexp)
(local-set-key (kbd "<C-right>") 'sp-forward-slurp-sexp))
(defun turn-off (modes)
"Turn off each mode in MODES."
(mapc (lambda (m) (funcall m -1)) modes))
(defun turn-on-compilation-shell-for-pony ()
(add-hook 'pony-minor-mode-hook 'compilation-shell-minor-mode nil t))
(defalias 'yes-or-no-p 'y-or-n-p)
(defalias 'list-buffers 'ibuffer)
(defalias 'dabbrev-expand 'hippie-expand)
;; Get rid of annoying and useless
(turn-off '(menu-bar-mode scroll-bar-mode tool-bar-mode blink-cursor-mode
column-number-mode line-number-mode tooltip-mode))
(mapc #'loadpath-add-and-autoload
'("~/.emacs.d/site-lisp" "~/projects/emacs/pony-mode/src"
"~/projects/emacs/php-mode" "~/.emacs.d/vendor-lisp/org/lisp"
"~/.emacs.d/vendor-lisp/org/contrib/lisp"
"~/.emacs.d/vendor-lisp/eap"))
(stante-after appt
(setq appt-disp-window-function #'oni:appt-display-window-and-jabber)
(setq appt-display-diary nil))
(stante-after "bindings"
(setq mode-line-default-help-echo ""))
(stante-after browse-url
(setq browse-url-browser-function 'browse-url-generic)
(setq browse-url-generic-program (getenv "BROWSER")))
(stante-after cc-vars
(setq-default c-basic-offset 4)
(setq c-offsets-alist
'((statement-block-intro . +)
(knr-argdecl-intro . 5)
(substatement-open . +)
(substatement-label . 0)
(label . 0)
(statement-case-open . +)
(statement-cont . +)
(arglist-intro . +)
(arglist-close . 0)
(inline-open . 0)
(brace-list-open . +)
(topmost-intro-cont first c-lineup-topmost-intro-cont
c-lineup-gnu-DEFUN-intro-cont))))
(stante-after compile
(setq compilation-scroll-output t))
(stante-after custom
(setq custom-theme-directory "~/.emacs.d/themes")
(eval-after-init (load-theme 'yoshi t)))
(stante-after desktop
(setq desktop-load-locked-desktop t)
(setq desktop-clear-preserve-buffers
(append (list (rx (and bol (or (and "+" (1+ anything))
"dailies" "work" "tasks"
(or "bookmarks.org"
"contacts.org")) eol))
(rx (or "*ielm*" "*-jabber-roster-*" "*eshell*"))
(rx (and "*" (or "magit" "scratch-") (1+ anything)
"*")))
desktop-clear-preserve-buffers))
(setq desktop-files-not-to-save
(rx (or (regexp "\\(^/[^/:]*:\\|(ftp)$\\)")
(and "/" (or "dailies" "tasks" "bookmarks.org"
"contacts.org" "work") eol)))))
(stante-after eap
(setq eap-music-library "/mnt/music")
(setq eap-playlist-library "~/music/playlists"))
(stante-after em-prompt
(setq eshell-highlight-prompt nil)
(setq eshell-prompt-function 'oni-eshell-prompt)
(setq eshell-prompt-regexp "^> "))
(stante-after em-term
(add-to-list 'eshell-visual-commands "unison"))
(stante-after emms
(emms-minimalistic)
(emms-default-players)
(require 'emms-player-mpd)
(require 'emms-mode-line))
(stante-after emms-mode-line
(setq emms-mode-line-mode-line-function 'oni:mode-line-current-song)
(emms-mode-line 1))
(stante-after emms-player-mpd
(add-to-list 'emms-player-list 'emms-player-mpd)
(setq emms-player-mpd-music-directory "/mnt/music/mp3"))
(stante-after erc
(setq erc-hide-list '("PART"))
(setq erc-nick "ryuslash"))
(stante-after erc-join
(setq erc-autojoin-channels-alist
'(("freenode.net" "#ninthfloor" "#emacs" "#dispass"))))
(stante-after erc-stamp
(setq erc-insert-timestamp-function 'erc-insert-timestamp-left)
(setq erc-timestamp-format "[%H:%M] ")
(setq erc-timestamp-only-if-changed-flag nil))
(stante-after files
(setq-default require-final-newline t)
(setq auto-mode-case-fold nil)
(setq auto-save-file-name-transforms
`((".*" "~/.local/share/emacs/autosave/" t)))
(setq backup-directory-alist
`((".*" . "~/.local/share/emacs/backup/")))
(setq auto-mode-alist
(append '(("/PKGBUILD$" . sh-mode)
(".install$" . sh-mode)
("\\.jl$" . sawfish-mode)
("\\.js\\(on\\)?$" . js2-mode)
("\\.m\\(ark\\)?d\\(?:o?wn\\)?$" . markdown-mode)
("\\.php[345]?$" . php-mode)
("\\.po\\'\\|\\.po\\." . po-mode)
("\\.tpl$" . html-mode)
("^\\.Xmodmap$" . xmodmap-mode))
auto-mode-alist)))
(stante-after fill-column-indicator
(setq-default fci-rule-column 73))
(stante-after flycheck
(mapc (lambda (c) (delq c flycheck-checkers))
'(python-pylint python-pyflakes)))
(stante-after geiser-repl
(setq geiser-repl-history-filename "~/.emacs.d/geiser-history"))
(stante-after gnus-start
(setq gnus-init-file "~/.emacs.d/gnus"))
(stante-after grep
(add-to-list 'grep-find-ignored-directories "migrations"))
(stante-after help-at-pt
(setq help-at-pt-display-when-idle t))
(stante-after ido
(setq ido-ignore-buffers
(list "^\\` " "^irc\\." "^\\#" "^\\*Customize Option:"
(rx (or "*-jabber-roster-*" "*Messages*" "*fsm-debug*"
"*magit-process*" "*magit-edit-log*" "*Backtrace*"
"*Ibuffer*"))))
(setq ido-auto-merge-work-directories-length -1)
(setq ido-default-buffer-method 'selected-window)
(setq ido-max-window-height 1)
(setq ido-save-directory-list-file nil))
(stante-after ido-ubiquitous
(setq ido-ubiquitous-command-exceptions
'(org-refile org-capture-refile)))
(stante-after jabber
(remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo)
(setq jabber-account-list
`((,(concat "tom@ryuslash.org/" (hostname))
(:connection-type . ssl)))))
(stante-after jabber-avatar
(setq jabber-avatar-cache-directory "~/.emacs.d/jabber-avatars/"))
(stante-after jabber-chat
(setq jabber-chat-buffer-format "+%n")
(setq jabber-chat-foreign-prompt-format "%t %u/%r <\n")
(setq jabber-chat-local-prompt-format "%t %u/%r >\n")
(setq jabber-chat-buffer-show-avatar nil))
(stante-after jabber-chat-states
(setq jabber-chatstates-confirm nil))
(stante-after jabber-history
(setq jabber-history-enabled t)
(setq jabber-use-global-history nil)
(setq jabber-history-dir "~/.emacs.d/jabber-hist"))
(stante-after jabber-muc
(setq jabber-groupchat-buffer-format "++%n")
(setq jabber-groupchat-prompt-format "%t %u --\n")
(setq jabber-muc-autojoin '("aethon@muc.ryuslash.org")))
(stante-after jabber-roster
(setq jabber-roster-show-bindings nil)
(setq jabber-show-offline-contacts nil))
(stante-after jabber-vcard-avatars
(setq jabber-vcard-avatars-publish nil)
(setq jabber-vcard-avatars-retrieve nil))
(stante-after jedi
(setcar jedi:server-command "python2")
(setq jedi:tooltip-method nil))
(stante-after jit-lock
(setq jit-lock-defer-time 0.2))
(stante-after magit
(setq magit-repo-dirs '("~/projects/")))
(stante-after message
(setq message-send-mail-function 'message-send-mail-with-sendmail)
(setq message-sendmail-extra-arguments '("-a" "ryuslash")))
(stante-after minibuf-eldef
(setq minibuffer-eldef-shorten-default t))
(stante-after org
(setq org-special-ctrl-a/e t))
(stante-after package
(setq package-archives
'(("melpa" . "http://melpa.milkbox.net/packages/")
("marmalade" . "http://marmalade-repo.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")))
(setq package-load-list '((htmlize "1.39")
(lua-mode "20111107")
(dispass "1.1.2.1")
all)))
(stante-after "paragraph"
(setq sentence-end-double-space nil))
(stante-after php-mode
(setq-default php-mode-warn-if-mumamo-off nil)
(setq php-function-call-face 'font-lock-function-name-face)
(setq php-mode-force-pear t))
(stante-after pp-c-l
(setq pp^L-^L-string-function 'pp^L-ruler)
(setq pp^L-^L-string-pre nil))
(stante-after sendmail
(setq send-mail-function 'sendmail-send-it)
(setq sendmail-program "/usr/bin/msmtp"))
(stante-after slime
(setq inferior-lisp-program "sbcl --noinform --no-linedit"))
(stante-after smex
(setq smex-key-advice-ignore-menu-bar t)
(setq smex-save-file "~/.emacs.d/smex-items"))
(stante-after "startup"
(setq inhibit-default-init t)
(setq inhibit-startup-message t)
(setq initial-major-mode 'emacs-lisp-mode)
(setq initial-scratch-message nil)
(setq user-mail-address "tom@ryuslash.org"))
(stante-after time-stamp
(setq time-stamp-active t)
(setq time-stamp-format "%04y-%02m-%02d %02H:%02M:%02S (%u)"))
(stante-after type-break
(setq type-break-good-rest-interval (* 60 10))
(setq type-break-interval (* 60 50))
(setq type-break-keystroke-threshold '(nil . nil)))
(stante-after uniquify
(setq uniquify-buffer-name-style 'post-forward))
(stante-after w3m
(setq w3m-fill-column 72))
(stante-after "window"
(setq split-height-threshold 40)
(add-to-list
'display-buffer-alist
'("^\\*\\(?:.+-\\)?scratch\\*$" display-buffer-same-window))
(add-to-list
'display-buffer-alist
'("^\\*git-project-list\\*$" git-project-show-window))
(add-to-list
'display-buffer-alist
'("^\\*magit: .*\\*$" display-buffer-same-window)))
(stante-after yasnippet
(setq yas-fallback-behavior nil)
(setq yas-prompt-functions '(yas-ido-prompt)))
(mode-hooks
((clojure emacs-lisp lisp sawfish scheme ielm geiser-repl slime-repl)
paredit-mode)
((comint) turn-on-compilation-shell-for-pony)
((css) rainbow-mode)
((emacs-lisp go html lua php python rst ruby rust sh) flycheck-mode)
((emacs-lisp ielm) eldoc-mode)
((eshell) buffer-disable-undo)
((html org prog) yas-minor-mode)
((html prog) fci-mode)
((python) smartparens-mode)
((html) tagedit-mode)
((js2) slime-js-minor-mode)
((markdown python) whitespace-mode)
((prog text) auto-fill-mode)
((prog) rainbow-delimiters-mode)
((python) jedi:setup)
((smartparens) set-smartparens-keys)
((tagedit) tagedit-add-experimental-features)
((tagedit) tagedit-add-paredit-like-keybindings)
((text) flyspell-mode)
((vala) oni:vala-mode-func))
(add-hook 'emacs-startup-hook 'pretty-control-l-mode)
(add-hook 'after-make-frame-functions
'(lambda (arg) (pretty-control-l-mode)))
(add-hook 'jabber-alert-message-hooks 'jabber-message-libnotify)
(add-hook 'jabber-alert-muc-hooks 'jabber-muc-libnotify)
(setq-default bidi-paragraph-direction 'left-to-right)
(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)
(setq-default truncate-lines t)
(setq custom-file "~/.emacs.d/custom.el")
(setq default-frame-alist
`((border-width . 0)
(internal-border-width . 0)
(vertical-scroll-bars . nil)
(menu-bar-lines . nil)
(tool-bar-lines . nil)
(font . "Envy Code R:pixelsize=16")))
(setq frame-title-format '(:eval (concat "emacs: " (buffer-name))))
(setq inhibit-local-menu-bar-menus t)
(setq message-log-max 1000)
(setq redisplay-dont-pause t)
(setq use-dialog-box nil)
(setq user-full-name "Tom Willemse")
(setq window-combination-resize t)
(add-to-list 'debug-ignored-errors "^Can't shift all lines enough")
;; Can't be put in an eval-after-load or such because by then it will
;; be too late.
(setq elnode-do-init nil)
(enable '(downcase-region narrow-to-page narrow-to-region scroll-left
upcase-region))
(eval-after-init (ido-ubiquitous-mode))
(eval-after-init
(load (expand-file-name "~/.local/share/quicklisp/slime-helper.el")))
(eval-after-load "org" '(require 'org-init))
(eval-after-init
(require 'auto-complete-config)
(ac-config-default))
(load "eap-autoloads")
(eval-after-init (smex-initialize))
(eval-after-init (global-diff-hl-mode))
(eval-after-init (mode-icons-mode))
(eval-after-init (desktop-registry-auto-register))
;; (setq pony-tpl-indent-moves t)
;; (setq rainbow-delimiters-max-face-count 12)
(add-hook 'after-save-hook 'oni:after-save-func t)
(add-hook 'before-save-hook 'oni:before-save-func)
(add-hook 'c-mode-hook 'oni:c-mode-func)
(add-hook 'css-mode-hook 'oni:css-mode-func)
(add-hook 'diary-display-hook 'oni:diary-display-func)
(add-hook 'go-mode-hook 'oni:go-mode-func)
(add-hook 'gtags-mode-hook 'oni:gtags-mode-func)
(add-hook 'haskell-mode-hook 'oni:haskell-mode-func)
(add-hook 'jabber-roster-mode-hook 'oni:jabber-roster-mode-func)
(add-hook 'java-mode-hook 'oni:java-mode-func)
(add-hook 'js-mode-hook 'oni:js-mode-func)
(add-hook 'js2-mode-hook 'oni:js2-mode-func)
(add-hook 'lua-mode-hook 'oni:lua-mode-func)
(add-hook 'markdown-mode-hook 'oni:markdown-mode-func)
(add-hook 'php-mode-hook 'oni:php-mode-func)
(add-hook 'prog-mode-hook 'oni:prog-mode-func)
(add-hook 'python-mode-hook 'oni:python-mode-func)
(add-hook 'term-mode-hook 'oni:term-mode-func)
(add-hook 'write-file-hooks 'oni:write-file-func)
(add-hook 'yas-minor-mode-hook 'oni:yas-minor-mode-func)
(global-set-key (kbd "'") 'oni:self-insert-dwim)
(global-set-key (kbd "<XF86HomePage>") 'oni:raise-scratch)
(global-set-key (kbd "<XF86Mail>") 'gnus)
(global-set-key (kbd "<f10>") 'git-project-show-files)
(global-set-key (kbd "<f5>") 'reload-buffer)
(global-set-key (kbd "<f6>") 'jabber-switch-to-roster-buffer)
(global-set-key (kbd "<f7>") 'magit-status)
(global-set-key (kbd "<f8>") 'raise-eshell)
(global-set-key (kbd "<hiragana>") 'oni:show-org-index)
(global-set-key (kbd "C-<") 'oni:indent-shift-left)
(global-set-key (kbd "C->") 'oni:indent-shift-right)
(global-set-key (kbd "C-M-4") 'split-window-vertically)
(global-set-key (kbd "C-M-SPC") 'er/expand-region)
(global-set-key (kbd "C-M-d") 'kill-word)
(global-set-key (kbd "C-M-w") 'backward-kill-word)
(global-set-key (kbd "C-M-x") 'smex-major-mode-commands)
(global-set-key (kbd "C-M-z") 'indent-defun)
(global-set-key (kbd "C-S-k") 'kill-whole-line)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)
(global-set-key (kbd "C-c d c") 'desktop-clear)
(global-set-key (kbd "C-c d d") 'desktop-registry-change-desktop)
(global-set-key (kbd "C-c d s") 'desktop-save)
(global-set-key (kbd "C-c i p") 'identica-update-status-interactive)
(global-set-key (kbd "C-c p") 'oni:show-buffer-position)
(global-set-key (kbd "C-c t") 'oni:raise-ansi-term)
(global-set-key (kbd "C-c w d") 'oni:downcase-prev)
(global-set-key (kbd "C-c w u") 'oni:upcase-prev)
(global-set-key (kbd "C-e") 'oni:move-end-of-dwim)
(global-set-key (kbd "M-0") 'delete-window)
(global-set-key (kbd "M-1") 'delete-other-windows)
(global-set-key (kbd "M-2") 'split-window-below)
(global-set-key (kbd "M-3") 'split-window-right)
(global-set-key (kbd "M-4") 'split-window-horizontally)
(global-set-key (kbd "M-n") 'helm-imenu)
(global-set-key (kbd "M-o") 'other-window)
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "\"") 'oni:self-insert-dwim)
(global-set-key [remap move-beginning-of-line] 'move-beginning-of-dwim)
(if (daemonp)
(global-set-key "\C-x\C-c" 'oni:close-client-window))
(when (or window-system (daemonp))
(global-unset-key "\C-z"))
(ido-mode)
(minibuffer-electric-default-mode)
(auto-insert-mode)
(electric-indent-mode)
(savehist-mode)
(show-paren-mode)
(winner-mode)
(help-at-pt-set-timer)
(windmove-default-keybindings)
;;; Popping up multiple frames out of the blue does not usually play
;;; well with (manual) tiling window managers.
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;;; Not being able to find newly written functions in imenu is a pain.
(setq imenu-auto-rescan t)
;;; Yanking at click makes not sense to me. I normally have my cursor
;;; where it needs to point and if I *have* to use the mouse I prefer
;;; just clicking it wherever it lands, without having to drag it all
;;; the way to the proper place.
(setq mouse-yank-at-point t)
;;; Always having to move the cursor around so much after scrolling
;;; gets annoying.
(setq scroll-preserve-screen-position t)
;;; I store my blog posts in `~/documents/blog', not the default
;;; `~/Blog'.
(setq eltuki-blog-dir "~/documents/blog")
(setq sp-cancel-autoskip-on-backward-movement nil)
(defun oni:scroll-down-or-prev-page (arg)
"Either scroll down or go to the previous page.
Depending on the value of `buffer-narrowed-p'."
(interactive "^P")
(if (buffer-narrowed-p)
(let ((scroll-error-top-bottom nil))
(condition-case nil
(scroll-down-command arg)
(beginning-of-buffer
(narrow-to-page -1)
(goto-char (point-min)))))
(scroll-down-command arg)))
(defun oni:scroll-up-or-next-page (arg)
"Either scroll up or go to the next page.
Depending on the value of `buffer-narrowed-p'."
(interactive "^P")
(if (buffer-narrowed-p)
(let ((scroll-error-top-bottom nil))
(condition-case nil
(scroll-up-command arg)
(end-of-buffer
(narrow-to-page 1)
(goto-char (point-min)))))
(scroll-up-command arg)))
(global-set-key (kbd "<prior>") 'oni:scroll-down-or-prev-page)
(global-set-key (kbd "<next>") 'oni:scroll-up-or-next-page)
;;;; Auto-complete
(setq-default ac-sources '(ac-source-imenu
ac-source-gtags
ac-source-abbrev
ac-source-yasnippet
ac-source-words-in-buffer
ac-source-words-in-same-mode-buffers
ac-source-dictionary
ac-source-functions
ac-source-symbols
ac-source-variables
ac-source-features))
;;;; Magit
(setq magit-default-tracking-name-function
'magit-default-tracking-name-branch-only)
(setq magit-diff-refine-hunk 'all)
;;; Finally, load any `customize' settings.
(load custom-file)
(autoload 'notifications-notify "notifications")
(autoload 'jabber-send-message "jabber-chat")
(defmacro oni:email (user at host dot com)
"Turn arguments into an email address.
The resulting email address will look like: USER@HOST.COM, AT and
DOT are intentionally being skipped."
(concat (symbol-name user) "@" (symbol-name host) "."
(symbol-name com)))
(defun oni:after-save-func ()
"Function for `after-save-hook'."
(oni:compile-el)
(executable-make-buffer-file-executable-if-script-p)
(let* ((dom-dir (locate-dominating-file (buffer-file-name) "Makefile"))
(TAGSp (not (string= "" (shell-command-to-string
(concat "grep \"^TAGS:\" " dom-dir "Makefile"))))))
(when (and dom-dir TAGSp)
(shell-command
(concat "make -C " dom-dir " TAGS >/dev/null 2>&1")))))
(defun oni:appt-display-window-and-jabber (min-to-app new-time appt-msg)
"Send a message to my phone jabber account."
(jabber-send-message (car jabber-connections) "phone@ryuslash.org"
nil (format "%s%s (in %s minutes)"
new-time appt-msg min-to-app) nil)
(appt-disp-window min-to-app new-time appt-msg))
;; (jabber-send-message (car jabber-connections)
;; "aethon@muc.ryuslash.org" nil "Hi, I'm a programmatic message; this
;; upens up possibilities :)" "groupchat")
(defun oni:before-save-func ()
"Function for `before-save-hook'."
(if (eq major-mode 'html-mode)
(oni:replace-html-special-chars))
(if (not (eq major-mode 'markdown-mode))
(delete-trailing-whitespace)))
(defun oni:c-mode-func ()
"Function for `c-mode-hook'."
(local-set-key [f9] 'compile)
(local-set-key "\C-j" 'oni:newline-and-indent))
(defun oni:change-prev-case (num dir)
(let ((regfunc (if (eq dir 'up) 'upcase-region 'downcase-region))
(wordfunc (if (eq dir 'up) 'upcase-word 'downcase-word)))
(if (> num 1)
(funcall regfunc (point) (- (point) num))
(funcall wordfunc -1))))
(defun oni:close-client-window ()
"Close a client's frames."
(interactive)
(server-save-buffers-kill-terminal nil))
(defun oni:color-for (object)
"Generate a hex color by taking the first 6 characters of OBJECT's MD5 sum."
(format "#%s" (substring (md5 object) 0 6)))
(defun oni:compile-el ()
"Compile the current buffer file if it is an .el file."
(let* ((full-file-name (buffer-file-name))
(file-name (file-name-nondirectory full-file-name))
(suffix (file-name-extension file-name)))
(if (and (not (string-equal file-name ".dir-locals.el"))
(string-equal suffix "el"))
(byte-compile-file full-file-name))))
(defun oni:css-mode-func ()
"Function for `css-mode-hook'."
(local-set-key "\C-j" 'oni:newline-and-indent))
(defun oni:current-jabber-status ()
"Return a string representing the current jabber status."
(or (and (not *jabber-connected*) "Offline")
(and (not (string= *jabber-current-status* ""))
*jabber-current-status*)
"Online"))
(defun oni:diary-display-func ()
"Function for `diary-display-hook'."
(diary-fancy-display))
(defun oni:downcase-prev (num)
(interactive "p")
(oni:change-prev-case num 'down))
(defun oni:go-mode-func ()
"Function for `go-mode-hook'."
(setq indent-tabs-mode nil)
(local-set-key "\C-j" 'oni:newline-and-indent))
(defun oni:gtags-mode-func ()
"Function for `gtags-mode-hook'."
(local-set-key "\M-," 'gtags-find-tag)
(local-set-key "\M-." 'gtags-find-rtag))
(defun oni:haskell-mode-func ()
"Function for `haskell-mode-hook'."
(turn-on-haskell-indentation))
(defun oni:indent-shift-left (start end &optional count)
"Rigidly indent region.
Region is from START to END. Move
COUNT number of spaces if it is non-nil otherwise use
`tab-width'."
(interactive
(if mark-active
(list (region-beginning) (region-end) current-prefix-arg)
(list (line-beginning-position)
(line-end-position)
current-prefix-arg)))
(if count
(setq count (prefix-numeric-value count))
(setq count tab-width))
(when (> count 0)
(let ((deactivate-mark nil))
(save-excursion
(goto-char start)
(while (< (point) end)
(if (and (< (current-indentation) count)
(not (looking-at "[ \t]*$")))
(error "Can't shift all lines enough"))
(forward-line))
(indent-rigidly start end (- count))))))
(defun oni:indent-shift-right (start end &optional count)
"Indent region between START and END rigidly to the right.
If COUNT has been specified indent by that much, otherwise look at
`tab-width'."
(interactive
(if mark-active
(list (region-beginning) (region-end) current-prefix-arg)
(list (line-beginning-position)
(line-end-position)
current-prefix-arg)))
(let ((deactivate-mark nil))
(if count
(setq count (prefix-numeric-value count))
(setq count tab-width))
(indent-rigidly start end count)))
(defun oni:jabber-alert-message-func (from buffer text title)
(notifications-notify :title title
:body text))
(defun oni:jabber-roster-mode-func ()
"Function for `jabber-roster-mode-hook'."
(setq mode-line-format
(list (propertize " %m" 'face 'mode-line-buffer-id))))
(defun oni:java-mode-func ()
"Function for `java-mode-hook'."
(local-set-key "\C-j" 'oni:newline-and-indent))
(defun oni:js-mode-func ()
"Function for `js-mode-hook'."
(local-set-key "\C-j" 'oni:newline-and-indent))
(defun oni:js2-mode-func ()
"Function for `js2-mode-hook'."
(oni:js-mode-func)
(local-set-key (kbd "<f5>") #'slime-js-reload))
(defun oni:lua-mode-func()
"Function for `lua-mode-hook'."
(local-unset-key (kbd ")"))
(local-unset-key (kbd "]"))
(local-unset-key (kbd "}")))
(defun oni:markdown-mode-func ()
"Function for `markdown-mode-hook'."
(setq-local whitespace-style '(face trailing)))
(defun oni:mini-fix-timestamp-string (date-string)
"A minimal version of Xah Lee's `fix-timestamp-string'.
Turn DATE-STRING into something else that can be worked with in
code. Found at http://xahlee.org/emacs/elisp_parse_time.html"
(setq date-string (replace-regexp-in-string "Jan" "01" date-string)
date-string (replace-regexp-in-string "Feb" "02" date-string)
date-string (replace-regexp-in-string "Mar" "03" date-string)
date-string (replace-regexp-in-string "Apr" "04" date-string)
date-string (replace-regexp-in-string "May" "05" date-string)
date-string (replace-regexp-in-string "Jun" "06" date-string)
date-string (replace-regexp-in-string "Jul" "07" date-string)
date-string (replace-regexp-in-string "Aug" "08" date-string)
date-string (replace-regexp-in-string "Sep" "09" date-string)
date-string (replace-regexp-in-string "Oct" "10" date-string)
date-string (replace-regexp-in-string "Nov" "11" date-string)
date-string (replace-regexp-in-string "Dec" "12" date-string))
(string-match
"^\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{4\\}\\)$"
date-string)
(format "%s-%s-%s"
(match-string 3 date-string)
(match-string 2 date-string)
(match-string 1 date-string)))
(defun oni:mode-line-current-song ()
"Extract current song information from a path.
EMMS only shows me the absolute path of a song, this function
extracts the parts I want to know about."
(let* ((song (emms-track-name (emms-playlist-current-selected-track)))
(matchp (string-match "\\([^/]+\\)/\\([0-9]\\{4\\}\\) - \\(.+\\)/\\([0-9]\\{2,3\\}\\) - \\(.+\\)\\..\\{3,4\\}$" song))
(band (substring song (match-beginning 1) (match-end 1)))
(year (substring song (match-beginning 2) (match-end 2)))
(album (substring song (match-beginning 3) (match-end 3)))
(track (substring song (match-beginning 4) (match-end 4)))
(title (substring song (match-beginning 5) (match-end 5))))
(format "[%s - %s]" band title)))
(defun oni:move-end-of-dwim ()
"Move to end of line, either before any comments or after."
(interactive)
(let ((start (point))
(eolpos (line-end-position)))
(beginning-of-line)
(if (and comment-start
(not (looking-at (regexp-quote comment-start)))
(comment-search-forward eolpos t))
(progn
(search-backward-regexp (concat "[^ \t" comment-start "]"))
(forward-char)
(when (or (bolp)
(= start (point)))
(end-of-line)))
(end-of-line))))
(defun oni:myepisodes-formatter (plist)
"Format RSS items from MyEpisodes as org tasks.
PLIST contains all the pertinent information."
(let ((str (plist-get plist :title)))
(string-match
"^\\[ \\([^\]]+\\) \\]\\[ \\([^\]]+\\) \\]\\[ \\([^\]]+\\) \\]\\[ \\([^\]]+\\) \\]$"
str)
(let* ((title (match-string 1 str))
(episode (match-string 2 str))
(name (match-string 3 str))
(date (oni:mini-fix-timestamp-string (match-string 4 str))))
(format "* ACQUIRE %s %s - %s \n SCHEDULED: <%s>"
title episode name date))))
(defun oni:newline-and-indent ()
"`newline-and-indent', but with a twist.
When dealing with braces, add another line and indent that too."
(interactive)
(if (and (not (or (= (point) (point-max))
(= (point) (point-min))))
(or (and (char-equal (char-before) ?{)
(char-equal (char-after) ?}))
(and (char-equal (char-before) ?\()
(char-equal (char-after) ?\)))))
(save-excursion (newline-and-indent)))
(newline-and-indent))
(defun oni:php-mode-func ()
"Function for `php-mode-hook'."
(local-set-key "\C-j" 'oni:newline-and-indent)
(c-set-offset 'arglist-intro '+)
(c-set-offset 'arglist-close '0)
(setq-local fci-rule-column 80))
(defun oni:prog-mode-func ()
"Function for `prog-mode-hook'."
(setq-local comment-auto-fill-only-comments t))
(defun oni:python-mode-func ()
"Function for `python-mode-hook'."
(local-set-key (kbd "C->") 'python-indent-shift-right)
(local-set-key (kbd "C-<") 'python-indent-shift-left)
(set (make-local-variable 'electric-indent-chars) nil)
(setq fci-rule-column 79
fill-column 72)
(setq-local whitespace-style '(tab-mark)))
(defun oni:raise-ansi-term (arg)
"Create or show an `ansi-term' buffer."
(interactive "P")
(let ((buffer (get-buffer "*ansi-term*")))
(if (and buffer (not arg))
(switch-to-buffer buffer)
(ansi-term (getenv "SHELL")))))
(defun oni:raise-scratch (&optional mode)
"Show the *scratch* buffer.
If called with a universal argument, ask the user which mode to
use. If MODE is not nil, open a new buffer with the name
*MODE-scratch* and load MODE as its major mode."
(interactive (list (if current-prefix-arg
(read-string "Mode: ")
nil)))
(let* ((bname (if mode
(concat "*" mode "-scratch*")
"*scratch*"))
(buffer (get-buffer bname))
(mode-sym (intern (concat mode "-mode"))))
(unless buffer
(setq buffer (generate-new-buffer bname))
(with-current-buffer buffer
(when (fboundp mode-sym)
(funcall mode-sym))))
(select-window (display-buffer buffer))))
(defun oni:replace-html-special-chars ()
"Replace special characters with HTML escaped entities."
(oni:replace-occurrences "é" "&eacute;"))
(defun oni:replace-occurrences (from to)
"Replace all occurrences of FROM with TO in the current buffer."
(save-excursion
(goto-char (point-min))
(while (search-forward from nil t)
(replace-match to))))
(defun oni:request-pull ()
"Start a mail to request pulling from a git repository."
(interactive)
(let* ((default-directory
(expand-file-name
(or (locate-dominating-file default-directory ".git")
(magit-read-top-dir nil))))
(refs (magit-list-interesting-refs magit-uninteresting-refs))
(from (cdr (assoc (completing-read "From: " refs) refs)))
(url (read-from-minibuffer "Pull URL: "))
(to (symbol-name (read-from-minibuffer "Up to (HEAD): "
nil nil t nil "HEAD")))
(patchp (and current-prefix-arg (listp current-prefix-arg))))
(message "Requesting pull for %s from %s to %s at %s with%s patch"
default-directory from to url (if patchp "" "out"))
(compose-mail
nil (concat
"Requesting pull for "
(file-name-base (directory-file-name default-directory))))
(save-excursion
(goto-char (point-max))
(insert
(shell-command-to-string
(concat "git --git-dir='" default-directory ".git' --work-tree='"
default-directory "' request-pull " (when patchp "-p ")
from " " url " " to))))))
(defun oni:self-insert-dwim ()
"Execute self insert, but when the region is active call self
insert at the end of the region and at the beginning."
(interactive)
(if (region-active-p)
(let ((electric-pair-mode nil)
(beginning (region-beginning))
(end (region-end)))
(goto-char end)
(self-insert-command 1)
(save-excursion
(goto-char beginning)
(self-insert-command 1)))
(self-insert-command 1)))
(defun oni:shorten-dir (dir)
"Shorten a directory, (almost) like fish does it."
(while (string-match "\\(/\\.?[^./]\\)[^/]+/" dir)
(setq dir (replace-match "\\1/" nil nil dir)))
dir)
(defun oni:show-buffer-position ()
"Show the position in the current buffer."
(interactive)
(message (format "%d:%d" (line-number-at-pos) (current-column))))
(defun oni:show-org-index ()
"Show the index of my org files."
(interactive)
(find-file "~/documents/org/index.org"))
(defun oni:skip-ex-tag ()
(let ((tags (org-entry-get (point) "TAGS")))
(when (and tags (string-match-p ":ex:" tags))
(save-excursion
(org-forward-element)
(point)))))
(defun oni:split-window-interactive (dir)
"Split windows in direction DIR.
Can also delete or switch to another window."
(interactive
(list (read-char "Direction (h,v,q,d,o): ")))
(case dir
((?v) (split-window-vertically))
((?h) (split-window-horizontally))
((?q) (delete-other-windows))
((?d) (delete-window))
((?o) (other-window 1))))
(defun oni:split-window-interactively (window)
"Ask for a direction and split WINDOW that way.
If no direction is given, don't split."
(let ((dir (read-char "Direction (h,v): ")))
(case dir
((?v) (split-window-vertically))
((?h) (split-window-horizontally))
(t window))))
(defun oni:start-python-test-mail-server ()
"Run the python test mailserver."
(interactive)
(start-process "python-test-mail-server" "*py-mail-server*" "python" "-m"
"smtpd" "-n" "-c" "DebuggingServer" "localhost:1025"))
(defun oni:stop-python-test-mail-server ()
"Stop the python test mailserver."
(interactive)
(kill-process "python-test-mail-server"))
(defun oni:term-mode-func ()
"Function for `term-mode-hook'."
(setq truncate-lines nil))
(defun oni:upcase-prev (num)
(interactive "p")
(oni:change-prev-case num 'up))
(defun oni:vala-mode-func ()
"Function for `vala-mode-hook'."
(setq indent-tabs-mode nil))
(defun oni:write-file-func ()
"Function for `write-file-hooks'."
(time-stamp))
(defun oni:yas-minor-mode-func ()
"Function for `yas-minor-mode-hook'."
(define-key yas-minor-mode-map (kbd "TAB") nil)
(define-key yas-minor-mode-map [(tab)] nil)
(define-key yas-minor-mode-map (kbd "C-\\") 'yas-expand))
(defvar oni:mailbox-map
'("top" ("menu"
("ryulash.org" . "ryuslash")
("ninthfloor" . "ninthfloor")
("gmail" . "gmail")
("aethon" . "aethon")))
"A mailbox map for use with `tmm-prompt'.")