Files
doomemacs/init/core-defuns.el
2014-11-29 20:21:03 -05:00

238 lines
7.7 KiB
EmacsLisp

(provide 'core-defuns)
;;;; Convenience ;;;;;;;;;;;;;;;;;;;
(defun associate-mode (match mode)
(add-to-list 'auto-mode-alist (cons match mode)))
(defun associate-minor-mode (match mode)
(add-to-list 'auto-minor-mode-alist (cons match mode)))
(defmacro λ (&rest body)
`(lambda () (interactive) ,@body))
(defmacro λ! (&rest body)
`(lambda () ,@body))
(defmacro add-hook! (hook &rest body)
`(add-hook ,hook (lambda() ,@body)))
;; Backwards compatibility
(unless (fboundp 'with-eval-after-load)
(defmacro with-eval-after-load (file &rest body)
`(eval-after-load ,file
`(funcall (function ,(lambda () ,@body))))))
(defmacro after (feature &rest forms)
`(,(if (or (not (boundp 'byte-compile-current-file))
(not byte-compile-current-file)
(if (symbolp feature)
(require feature nil :no-error)
(load feature :no-message :no-error)))
'progn
(message "after: cannot find %s" feature)
'with-no-warnings)
(with-eval-after-load ',feature ,@forms)))
;; vimmish keymapping shortcuts
(defalias 'defcmd 'evil-ex-define-cmd)
(defmacro ibind (key command)
`(key-chord-define evil-insert-state-map ,key ,command))
(defun bind (state &rest keys)
(let ((state-list state)
(is-global (or (stringp state)
(vectorp state)))
keymap)
(if is-global
(setq keys (-insert-at 0 state keys))
(progn
(if (keymapp (first keys))
(setq keymap (pop keys)))
(if (or (keymapp state)
(not (listp state)))
(setq state-list (list state)))))
(while keys
(let ((-key (pop keys))
(-def (pop keys)))
(if is-global
(global-set-key -key -def)
(dolist (-state state-list)
(cond ((evil-state-p -state)
(define-key
(if keymap
(evil-get-auxiliary-keymap keymap -state t)
(evil-state-property -state :keymap t)) -key -def))
((keymapp -state)
(define-key -state -key -def)))))))))
;; Hooks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun enable-comment-hard-wrap ()
(set (make-local-variable 'comment-auto-fill-only-comments) t)
(turn-on-auto-fill))
(defun enable-tab-width-2 ()
(setq tab-width 2
evil-shift-width 2))
(defun disable-final-newline ()
(set (make-local-variable 'require-final-newline) nil))
;;; Text Defuns ;;;;;;;;;;;;;;;;;;;;;;;;
(defun my/surrounded-p ()
(and (looking-back "[[{(]\\(\s+\\|\n\\)?\\(\s\\|\t\\)*")
(let* ((whitespace (match-string 1))
(match-str (concat whitespace (match-string 2) "[])}]")))
(looking-at-p match-str))))
(defun my/empty-line-p ()
(zerop (length (s-trim (my/get-line)))))
(defun my/get-line ()
(buffer-substring (line-beginning-position) (line-end-position)))
(defun my.backward-kill-to-bol-and-indent ()
"Kill line to the first non-blank character. If invoked again
afterwards, kill line to column 1."
(interactive)
(let ((empty-line (my/empty-line-p)))
(evil-delete (point-at-bol) (point))
(if (not empty-line)
(indent-according-to-mode))))
(defun my.point-at-first-non-blank()
(save-excursion (evil-first-non-blank) (point)))
(defun my.move-to-bol ()
"Moves cursor to the first non-blank character on the line. If
already there, move it to the true bol."
(interactive)
(evil-save-goal-column
(let ((point-at-bol (my.point-at-first-non-blank))
(point (point)))
(if (= point-at-bol point)
(evil-move-beginning-of-line)
(unless (= (point-at-bol) point)
(evil-first-non-blank))))))
(defun my.move-to-eol ()
(interactive)
(evil-save-goal-column
(let ((old-point (point)))
(when (comment-search-forward (point-at-eol) t)
(goto-char (match-beginning 0))
(skip-syntax-backward " ^<*" (my.point-at-first-non-blank))
(if (eq old-point (point)) ;
(evil-move-end-of-line))))))
;; Mimic expandtab in vim
(defun my.backward-delete-whitespace-to-column ()
"Delete back to the previous column of whitespace, or as much
whitespace as possible, or just one char if that's not possible."
(interactive)
(cond ;; If in a string
((sp-point-in-string)
(call-interactively 'backward-delete-char-untabify))
;; If using tabs (or at bol), just delete normally
((or indent-tabs-mode
(= (point-at-bol) (point)))
(call-interactively 'backward-delete-char))
;; Otherwise, delete up to the nearest tab column
(t (let ((movement (% (current-column) tab-width))
(p (point)))
(when (= movement 0)
(setq movement tab-width))
(save-match-data
(if (string-match "\\w*\\(\\s-+\\)$" (buffer-substring-no-properties (- p movement) p))
(backward-delete-char (- (match-end 1) (match-beginning 1)))
(call-interactively 'backward-delete-char-untabify)))))))
(defun my.dumb-indent ()
"Inserts a tab character (or spaces x tab-width). Checks if the
auto-complete window is open."
(interactive)
(if indent-tabs-mode
(insert "\t")
(let* ((movement (% (current-column) tab-width))
(spaces (if (zerop movement) tab-width (- tab-width movement))))
(insert (s-repeat spaces " ")))))
(defun my.inflate-space-maybe ()
"Checks if point is surrounded by {} [] () delimiters and adds a
space on either side of the point if so."
(interactive)
(if (my/surrounded-p)
(progn (call-interactively 'self-insert-command)
(save-excursion (call-interactively 'self-insert-command)))
(call-interactively 'self-insert-command)))
(defun my.deflate-space-maybe ()
"Checks if point is surrounded by {} [] () delimiters, and deletes
spaces on either side of the point if so. Resorts to
`my.backward-delete-whitespace-to-column' otherwise."
(interactive)
(save-match-data
(if (my/surrounded-p)
(let ((whitespace-match (match-string 1)))
(cond ((not whitespace-match)
(call-interactively 'delete-backward-char))
((string-match "\n" whitespace-match)
(evil-delete (point-at-bol) (point))
(delete-char -1)
(save-excursion (delete-char 1)))
(t
(just-one-space 0))))
(my.backward-delete-whitespace-to-column))))
(defun my.newline-and-indent ()
"Newline and indent; if in a comment, auto-comment and properly
indent the next line."
(interactive)
(cond ((sp-point-in-string)
(evil-ret))
((evil-in-comment-p)
(if (eq major-mode 'js2-mode)
(js2-line-break)
(call-interactively 'indent-new-comment-line)))
(t
(evil-ret-and-indent))))
(defun s-lines? (s) (length (s-lines s)))
;; Utility ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun what-face (pos)
"Tells you the name of the face (point) is on."
(interactive "d")
(let ((face (or (get-char-property (point) 'read-face-name)
(get-char-property (point) 'face))))
(if face (message "Face: %s" face) (message "No face at %d" pos))))
(defun what-col ()
(interactive)
(message "Column %d" (current-column)))
(defun my/append-to-list (list-var elements)
"Append ELEMENTS to the end of LIST."
(unless (consp elements)
(error "ELEMENTS must be a list"))
(let ((list (symbol-value list-var)))
(if list
(setcdr (last list) elements)
(set list-var elements)))
(symbol-value list-var))
(defun my/project-root (&optional force-pwd)
(if (and (not force-pwd)
(projectile-project-p))
(projectile-project-root)
default-directory))
(defmacro f--exists? (file dir)
`(f-exists? (expand-file-name ,file ,dir)))