c9048dc0e3
The function spacemacs//gne-next can be used as next-error-function in any buffer where lines represent “entries” that can be visited.
1045 lines
37 KiB
EmacsLisp
1045 lines
37 KiB
EmacsLisp
;;; funcs.el --- Spacemacs Base Layer functions File
|
||
;;
|
||
;; Copyright (c) 2012-2016 Sylvain Benner & Contributors
|
||
;;
|
||
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
|
||
;; URL: https://github.com/syl20bnr/spacemacs
|
||
;;
|
||
;; This file is not part of GNU Emacs.
|
||
;;
|
||
;;; License: GPLv3
|
||
|
||
;; add emacs binary helper functions
|
||
(defun spacemacs/emacsbin-path ()
|
||
(interactive)
|
||
(concat exec-directory (if (spacemacs/system-is-mswindows) "bin/") "emacs"))
|
||
|
||
(defun spacemacs/emacs-start ()
|
||
(interactive)
|
||
(call-process (spacemacs/emacsbin-path) nil 0 nil)
|
||
(message "Started 'emacs' - it will be ready soon ..."))
|
||
|
||
(defun spacemacs/emacs-debug-init ()
|
||
(interactive)
|
||
(call-process (spacemacs/emacsbin-path) nil 0 nil "--debug-init")
|
||
(message "Started 'emacs --debug-init' - it will be ready soon ..."))
|
||
|
||
(defun spacemacs/emacs-reload ()
|
||
(interactive)
|
||
(load-file user-init-file)
|
||
(message ".emacs reloaded successfully"))
|
||
|
||
(defun spacemacs/emacs-Q ()
|
||
(interactive)
|
||
(call-process (spacemacs/emacsbin-path) nil 0 nil "-Q")
|
||
(message "Started 'emacs -Q' - it will be ready soon ..."))
|
||
|
||
;; from https://github.com/cofi/dotfiles/blob/master/emacs.d/config/cofi-util.el#L38
|
||
(defun spacemacs/add-to-hooks (fun hooks)
|
||
"Add function to hooks"
|
||
(dolist (hook hooks)
|
||
(add-hook hook fun)))
|
||
|
||
(defun spacemacs/add-all-to-hook (hook &rest funs)
|
||
"Add functions to hook."
|
||
(spacemacs/add-to-hook hook funs))
|
||
|
||
(defun spacemacs/add-to-hook (hook funs)
|
||
"Add list of functions to hook."
|
||
(dolist (fun funs)
|
||
(add-hook hook fun)))
|
||
|
||
(defun spacemacs/echo (msg &rest args)
|
||
"Display MSG in echo-area without logging it in *Messages* buffer."
|
||
(interactive)
|
||
(let ((message-log-max nil))
|
||
(apply 'message msg args)))
|
||
|
||
(defun spacemacs/jump-in-buffer ()
|
||
(interactive)
|
||
(call-interactively
|
||
(cond
|
||
((and (configuration-layer/layer-usedp 'helm)
|
||
(eq major-mode 'org-mode))
|
||
'helm-org-in-buffer-headings)
|
||
((configuration-layer/layer-usedp 'helm)
|
||
'helm-semantic-or-imenu)
|
||
((configuration-layer/layer-usedp 'ivy)
|
||
'counsel-imenu)
|
||
(t 'imenu))))
|
||
|
||
(defun spacemacs/split-and-new-line ()
|
||
"Split a quoted string or s-expression and insert a new line with
|
||
auto-indent."
|
||
(interactive)
|
||
(sp-split-sexp 1)
|
||
(sp-newline))
|
||
|
||
(defun spacemacs/push-mark-and-goto-beginning-of-line ()
|
||
"Push a mark at current location and go to the beginnign of the line."
|
||
(interactive)
|
||
(push-mark (point))
|
||
(evil-beginning-of-line))
|
||
|
||
(defun spacemacs/push-mark-and-goto-end-of-line ()
|
||
"Push a mark at current location and go to the end of the line."
|
||
(interactive)
|
||
(push-mark (point))
|
||
(evil-end-of-line))
|
||
|
||
;; insert one or several line below without changing current evil state
|
||
(defun spacemacs/evil-insert-line-below (count)
|
||
"Insert one of several lines below the current point's line without changing
|
||
the current state and point position."
|
||
(interactive "p")
|
||
(save-excursion
|
||
(evil-save-state (evil-open-below count))))
|
||
|
||
;; insert one or several line above without changing current evil state
|
||
(defun spacemacs/evil-insert-line-above (count)
|
||
"Insert one of several lines above the current point's line without changing
|
||
the current state and point position."
|
||
(interactive "p")
|
||
(save-excursion
|
||
(evil-save-state (evil-open-above count))))
|
||
|
||
(defun spacemacs/evil-goto-next-line-and-indent (&optional count)
|
||
(interactive "p")
|
||
(let ((counter (or count 1)))
|
||
(while (> counter 0)
|
||
(join-line 1)
|
||
(newline-and-indent)
|
||
(setq counter (1- counter)))))
|
||
|
||
;; from Prelude
|
||
;; TODO: dispatch these in the layers
|
||
(defvar spacemacs-indent-sensitive-modes
|
||
'(coffee-mode
|
||
elm-mode
|
||
haml-mode
|
||
haskell-mode
|
||
slim-mode
|
||
makefile-mode
|
||
makefile-bsdmake-mode
|
||
makefile-gmake-mode
|
||
makefile-imake-mode
|
||
python-mode
|
||
yaml-mode)
|
||
"Modes for which auto-indenting is suppressed.")
|
||
|
||
(defcustom spacemacs-yank-indent-threshold 1000
|
||
"Threshold (# chars) over which indentation does not automatically occur."
|
||
:type 'number
|
||
:group 'spacemacs)
|
||
|
||
(defcustom spacemacs-large-file-modes-list
|
||
'(archive-mode tar-mode jka-compr git-commit-mode image-mode
|
||
doc-view-mode doc-view-mode-maybe ebrowse-tree-mode
|
||
pdf-view-mode)
|
||
"Major modes which `spacemacs/check-large-file' will not be
|
||
automatically applied to."
|
||
:group 'spacemacs
|
||
:type '(list symbol))
|
||
|
||
|
||
(defun spacemacs/indent-region-or-buffer ()
|
||
"Indent a region if selected, otherwise the whole buffer."
|
||
(interactive)
|
||
(unless (member major-mode spacemacs-indent-sensitive-modes)
|
||
(save-excursion
|
||
(if (region-active-p)
|
||
(progn
|
||
(indent-region (region-beginning) (region-end))
|
||
(message "Indented selected region."))
|
||
(progn
|
||
(evil-indent (point-min) (point-max))
|
||
(message "Indented buffer.")))
|
||
(whitespace-cleanup))))
|
||
|
||
;; idea from http://www.reddit.com/r/emacs/comments/312ge1/i_created_this_function_because_i_was_tired_of/
|
||
(defun spacemacs/eval-current-form ()
|
||
"Looks for the current def* or set* command then evaluates, unlike `eval-defun', does not go to topmost function"
|
||
(interactive)
|
||
(save-excursion
|
||
(search-backward-regexp "(def\\|(set")
|
||
(forward-list)
|
||
(call-interactively 'eval-last-sexp)))
|
||
|
||
;; from magnars
|
||
(defun spacemacs/eval-and-replace ()
|
||
"Replace the preceding sexp with its value."
|
||
(interactive)
|
||
(backward-kill-sexp)
|
||
(condition-case-unless-debug nil
|
||
(prin1 (eval (read (current-kill 0)))
|
||
(current-buffer))
|
||
(error (message "Invalid expression")
|
||
(insert (current-kill 0)))))
|
||
|
||
;; from https://gist.github.com/3402786
|
||
(defun spacemacs/toggle-maximize-buffer ()
|
||
"Maximize buffer"
|
||
(interactive)
|
||
(if (and (= 1 (length (window-list)))
|
||
(assoc ?_ register-alist))
|
||
(jump-to-register ?_)
|
||
(progn
|
||
(window-configuration-to-register ?_)
|
||
(delete-other-windows))))
|
||
|
||
;; A small minor mode to use a big fringe adapted from
|
||
;; http://bzg.fr/emacs-strip-tease.html
|
||
(define-minor-mode spacemacs-centered-buffer-mode
|
||
"Minor mode to use big fringe in the current buffer."
|
||
:global t
|
||
:init-value nil
|
||
:group 'editing-basics
|
||
(if spacemacs-centered-buffer-mode
|
||
(progn
|
||
(window-configuration-to-register ?_)
|
||
(delete-other-windows)
|
||
(set-fringe-mode
|
||
(/ (- (frame-pixel-width)
|
||
(* 100 (frame-char-width)))
|
||
2)))
|
||
(set-fringe-style nil)
|
||
(when (assoc ?_ register-alist)
|
||
(jump-to-register ?_))))
|
||
|
||
(defun spacemacs/useless-buffer-p (buffer)
|
||
"Determines if a buffer is useful."
|
||
(let ((buf-paren-major-mode (get (with-current-buffer buffer
|
||
major-mode)
|
||
'derived-mode-parent))
|
||
(buf-name (buffer-name buffer)))
|
||
;; first find if useful buffer exists, if so returns nil and don't check for
|
||
;; useless buffers. If no useful buffer is found, check for useless buffers.
|
||
(unless (cl-loop for regexp in spacemacs-useful-buffers-regexp do
|
||
(when (or (eq buf-paren-major-mode 'comint-mode)
|
||
(string-match regexp buf-name))
|
||
(return t)))
|
||
(cl-loop for regexp in spacemacs-useless-buffers-regexp do
|
||
(when (string-match regexp buf-name)
|
||
(return t))))))
|
||
|
||
;; from magnars modified by ffevotte for dedicated windows support
|
||
(defun spacemacs/rotate-windows (count)
|
||
"Rotate your windows.
|
||
Dedicated windows are left untouched. Giving a negative prefix
|
||
argument takes the kindows rotate backwards."
|
||
(interactive "p")
|
||
(let* ((non-dedicated-windows (remove-if 'window-dedicated-p (window-list)))
|
||
(num-windows (length non-dedicated-windows))
|
||
(i 0)
|
||
(step (+ num-windows count)))
|
||
(cond ((not (> num-windows 1))
|
||
(message "You can't rotate a single window!"))
|
||
(t
|
||
(dotimes (counter (- num-windows 1))
|
||
(let* ((next-i (% (+ step i) num-windows))
|
||
|
||
(w1 (elt non-dedicated-windows i))
|
||
(w2 (elt non-dedicated-windows next-i))
|
||
|
||
(b1 (window-buffer w1))
|
||
(b2 (window-buffer w2))
|
||
|
||
(s1 (window-start w1))
|
||
(s2 (window-start w2)))
|
||
(set-window-buffer w1 b2)
|
||
(set-window-buffer w2 b1)
|
||
(set-window-start w1 s2)
|
||
(set-window-start w2 s1)
|
||
(setq i next-i)))))))
|
||
|
||
(defun spacemacs/rotate-windows-backward (count)
|
||
"Rotate your windows backward."
|
||
(interactive "p")
|
||
(spacemacs/rotate-windows (* -1 count)))
|
||
|
||
(defun spacemacs/next-useful-buffer ()
|
||
"Switch to the next buffer and avoid special buffers."
|
||
(interactive)
|
||
(let ((start-buffer (current-buffer)))
|
||
(next-buffer)
|
||
(while (and (spacemacs/useless-buffer-p (current-buffer))
|
||
(not (eq (current-buffer) start-buffer)))
|
||
(next-buffer))))
|
||
|
||
(defun spacemacs/previous-useful-buffer ()
|
||
"Switch to the previous buffer and avoid special buffers."
|
||
(interactive)
|
||
(let ((start-buffer (current-buffer)))
|
||
(previous-buffer)
|
||
(while (and (spacemacs/useless-buffer-p (current-buffer))
|
||
(not (eq (current-buffer) start-buffer)))
|
||
(previous-buffer))))
|
||
|
||
(defun spacemacs/rename-file (filename &optional new-filename)
|
||
"Rename FILENAME to NEW-FILENAME.
|
||
|
||
When NEW-FILENAME is not specified, asks user for a new name.
|
||
|
||
Also renames associated buffer (if any exists), invalidates
|
||
projectile cache when it's possible and update recentf list."
|
||
(interactive "f")
|
||
(when (and filename (file-exists-p filename))
|
||
(let* ((buffer (find-buffer-visiting filename))
|
||
(short-name (file-name-nondirectory filename))
|
||
(new-name (if new-filename new-filename
|
||
(read-file-name
|
||
(format "Rename %s to: " short-name)))))
|
||
(cond ((get-buffer new-name)
|
||
(error "A buffer named '%s' already exists!" new-name))
|
||
(t
|
||
(let ((dir (file-name-directory new-name)))
|
||
(when (and (not (file-exists-p dir)) (yes-or-no-p (format "Create directory '%s'?" dir)))
|
||
(make-directory dir t)))
|
||
(rename-file filename new-name 1)
|
||
(when buffer
|
||
(kill-buffer buffer)
|
||
(find-file new-name))
|
||
(when (fboundp 'recentf-add-file)
|
||
(recentf-add-file new-name)
|
||
(recentf-remove-if-non-kept filename))
|
||
(when (and (configuration-layer/package-usedp 'projectile)
|
||
(projectile-project-p))
|
||
(call-interactively #'projectile-invalidate-cache))
|
||
(message "File '%s' successfully renamed to '%s'" short-name (file-name-nondirectory new-name)))))))
|
||
|
||
;; from magnars
|
||
(defun spacemacs/rename-current-buffer-file ()
|
||
"Renames current buffer and file it is visiting."
|
||
(interactive)
|
||
(let ((name (buffer-name))
|
||
(filename (buffer-file-name)))
|
||
(if (not (and filename (file-exists-p filename)))
|
||
(error "Buffer '%s' is not visiting a file!" name)
|
||
(let ((new-name (read-file-name "New name: " filename)))
|
||
(cond ((get-buffer new-name)
|
||
(error "A buffer named '%s' already exists!" new-name))
|
||
(t
|
||
(let ((dir (file-name-directory new-name)))
|
||
(when (and (not (file-exists-p dir)) (yes-or-no-p (format "Create directory '%s'?" dir)))
|
||
(make-directory dir t)))
|
||
(rename-file filename new-name 1)
|
||
(rename-buffer new-name)
|
||
(set-visited-file-name new-name)
|
||
(set-buffer-modified-p nil)
|
||
(when (fboundp 'recentf-add-file)
|
||
(recentf-add-file new-name)
|
||
(recentf-remove-if-non-kept filename))
|
||
(when (and (configuration-layer/package-usedp 'projectile)
|
||
(projectile-project-p))
|
||
(call-interactively #'projectile-invalidate-cache))
|
||
(message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))))
|
||
|
||
(defun spacemacs/delete-file (filename &optional ask-user)
|
||
"Remove specified file or directory.
|
||
|
||
Also kills associated buffer (if any exists) and invalidates
|
||
projectile cache when it's possible.
|
||
|
||
When ASK-USER is non-nil, user will be asked to confirm file
|
||
removal."
|
||
(interactive "f")
|
||
(when (and filename (file-exists-p filename))
|
||
(let ((buffer (find-buffer-visiting filename)))
|
||
(when buffer
|
||
(kill-buffer buffer)))
|
||
(when (or (not ask-user)
|
||
(yes-or-no-p "Are you sure you want to delete this file? "))
|
||
(delete-file filename)
|
||
(when (and (configuration-layer/package-usedp 'projectile)
|
||
(projectile-project-p))
|
||
(call-interactively #'projectile-invalidate-cache)))))
|
||
|
||
;; from magnars
|
||
(defun spacemacs/delete-current-buffer-file ()
|
||
"Removes file connected to current buffer and kills buffer."
|
||
(interactive)
|
||
(let ((filename (buffer-file-name))
|
||
(buffer (current-buffer))
|
||
(name (buffer-name)))
|
||
(if (not (and filename (file-exists-p filename)))
|
||
(ido-kill-buffer)
|
||
(when (yes-or-no-p "Are you sure you want to delete this file? ")
|
||
(delete-file filename t)
|
||
(kill-buffer buffer)
|
||
(when (and (configuration-layer/package-usedp 'projectile)
|
||
(projectile-project-p))
|
||
(call-interactively #'projectile-invalidate-cache))
|
||
(message "File '%s' successfully removed" filename)))))
|
||
|
||
;; from magnars
|
||
(defun spacemacs/sudo-edit (&optional arg)
|
||
(interactive "p")
|
||
(let ((fname (if (or arg (not buffer-file-name)) (read-file-name "File: ") buffer-file-name)))
|
||
(find-file
|
||
(cond ((string-match-p "^/ssh:" fname)
|
||
(with-temp-buffer
|
||
(insert fname)
|
||
(search-backward ":")
|
||
(let ((last-match-end nil)
|
||
(last-ssh-hostname nil))
|
||
(while (string-match "@\\\([^:|]+\\\)" fname last-match-end)
|
||
(setq last-ssh-hostname (or (match-string 1 fname) last-ssh-hostname))
|
||
(setq last-match-end (match-end 0)))
|
||
(insert (format "|sudo:%s" (or last-ssh-hostname "localhost"))))
|
||
(buffer-string)))
|
||
(t (concat "/sudo:root@localhost:" fname))))))
|
||
|
||
;; check when opening large files - literal file open
|
||
(defun spacemacs/check-large-file ()
|
||
(let* ((filename (buffer-file-name))
|
||
(size (nth 7 (file-attributes filename))))
|
||
(when (and
|
||
(not (memq major-mode spacemacs-large-file-modes-list))
|
||
size (> size (* 1024 1024 dotspacemacs-large-file-size))
|
||
(y-or-n-p (format "%s is a large file, open literally to avoid performance issues?"
|
||
filename)))
|
||
(setq buffer-read-only t)
|
||
(buffer-disable-undo)
|
||
(fundamental-mode))))
|
||
|
||
;; our own implementation of kill-this-buffer from menu-bar.el
|
||
(defun spacemacs/kill-this-buffer ()
|
||
"Kill the current buffer."
|
||
(interactive)
|
||
(if (window-minibuffer-p)
|
||
(abort-recursive-edit)
|
||
(kill-buffer (current-buffer))))
|
||
|
||
;; found at http://emacswiki.org/emacs/KillingBuffers
|
||
(defun spacemacs/kill-other-buffers ()
|
||
"Kill all other buffers."
|
||
(interactive)
|
||
(when (yes-or-no-p (format "Killing all buffers except \"%s\"? " (buffer-name)))
|
||
(mapc 'kill-buffer (delq (current-buffer) (buffer-list)))
|
||
(message "Buffers deleted!")))
|
||
|
||
;; from http://dfan.org/blog/2009/02/19/emacs-dedicated-windows/
|
||
(defun spacemacs/toggle-current-window-dedication ()
|
||
"Toggle dedication state of a window."
|
||
(interactive)
|
||
(let* ((window (selected-window))
|
||
(dedicated (window-dedicated-p window)))
|
||
(set-window-dedicated-p window (not dedicated))
|
||
(message "Window %sdedicated to %s"
|
||
(if dedicated "no longer " "")
|
||
(buffer-name))))
|
||
|
||
;; http://camdez.com/blog/2013/11/14/emacs-show-buffer-file-name/
|
||
(defun spacemacs/show-and-copy-buffer-filename ()
|
||
"Show and copy the full path to the current file in the minibuffer."
|
||
(interactive)
|
||
;; list-buffers-directory is the variable set in dired buffers
|
||
(let ((file-name (or (buffer-file-name) list-buffers-directory)))
|
||
(if file-name
|
||
(message (kill-new file-name))
|
||
(error "Buffer not visiting a file"))))
|
||
|
||
;; adapted from bozhidar
|
||
;; http://emacsredux.com/blog/2013/05/18/instant-access-to-init-dot-el/
|
||
(defun spacemacs/find-user-init-file ()
|
||
"Edit the `user-init-file', in the current window."
|
||
(interactive)
|
||
(find-file-existing user-init-file))
|
||
|
||
(defun spacemacs/find-dotfile ()
|
||
"Edit the `dotfile', in the current window."
|
||
(interactive)
|
||
(find-file-existing (dotspacemacs/location)))
|
||
|
||
(defun spacemacs/ediff-dotfile-and-template ()
|
||
"ediff the current `dotfile' with the template"
|
||
(interactive)
|
||
(ediff-files (dotspacemacs/location)
|
||
(concat dotspacemacs-template-directory ".spacemacs.template")))
|
||
|
||
(defun spacemacs/new-empty-buffer ()
|
||
"Create a new buffer called untitled(<n>)"
|
||
(interactive)
|
||
(let ((newbuf (generate-new-buffer-name "untitled")))
|
||
(switch-to-buffer newbuf)))
|
||
|
||
;; from https://gist.github.com/timcharper/493269
|
||
(defun spacemacs/split-window-vertically-and-switch ()
|
||
(interactive)
|
||
(split-window-vertically)
|
||
(other-window 1))
|
||
|
||
(defun spacemacs/split-window-horizontally-and-switch ()
|
||
(interactive)
|
||
(split-window-horizontally)
|
||
(other-window 1))
|
||
|
||
(defun spacemacs/layout-triple-columns ()
|
||
" Set the layout to triple columns. "
|
||
(interactive)
|
||
(delete-other-windows)
|
||
(dotimes (i 2) (split-window-right))
|
||
(balance-windows))
|
||
|
||
(defun spacemacs/layout-double-columns ()
|
||
" Set the layout to double columns. "
|
||
(interactive)
|
||
(delete-other-windows)
|
||
(split-window-right))
|
||
|
||
(defalias 'spacemacs/home 'spacemacs-buffer/goto-buffer
|
||
"Go to home Spacemacs buffer")
|
||
|
||
(defun spacemacs/home-delete-other-windows ()
|
||
"Open home Spacemacs buffer and delete other windows.
|
||
Useful for making the home buffer the only visible buffer in the frame."
|
||
(interactive)
|
||
(spacemacs/home)
|
||
(delete-other-windows))
|
||
|
||
(defun spacemacs/insert-line-above-no-indent (count)
|
||
(interactive "p")
|
||
(let ((p (+ (point) count)))
|
||
(save-excursion
|
||
(if (eq (line-number-at-pos) 1)
|
||
(evil-move-beginning-of-line)
|
||
(progn
|
||
(evil-previous-line)
|
||
(evil-move-end-of-line)))
|
||
(while (> count 0)
|
||
(insert "\n")
|
||
(setq count (1- count))))
|
||
(goto-char p)))
|
||
|
||
(defun spacemacs/insert-line-below-no-indent (count)
|
||
"Insert a new line below with no identation."
|
||
(interactive "p")
|
||
(save-excursion
|
||
(evil-move-end-of-line)
|
||
(while (> count 0)
|
||
(insert "\n")
|
||
(setq count (1- count)))))
|
||
|
||
;; from https://github.com/gempesaw/dotemacs/blob/emacs/dg-defun.el
|
||
(defun spacemacs/kill-matching-buffers-rudely (regexp &optional internal-too)
|
||
"Kill buffers whose name matches the specified REGEXP. This
|
||
function, unlike the built-in `kill-matching-buffers` does so
|
||
WITHOUT ASKING. The optional second argument indicates whether to
|
||
kill internal buffers too."
|
||
(interactive "sKill buffers matching this regular expression: \nP")
|
||
(dolist (buffer (buffer-list))
|
||
(let ((name (buffer-name buffer)))
|
||
(when (and name (not (string-equal name ""))
|
||
(or internal-too (/= (aref name 0) ?\s))
|
||
(string-match regexp name))
|
||
(kill-buffer buffer)))))
|
||
|
||
;; advise to prevent server from closing
|
||
|
||
(defvar spacemacs-really-kill-emacs nil
|
||
"prevent window manager close from closing instance.")
|
||
|
||
(defun spacemacs/persistent-server-running-p ()
|
||
"Requires spacemacs-really-kill-emacs to be toggled and
|
||
dotspacemacs-persistent-server to be t"
|
||
(and (fboundp 'server-running-p)
|
||
(server-running-p)
|
||
dotspacemacs-persistent-server))
|
||
|
||
(defadvice kill-emacs (around spacemacs-really-exit activate)
|
||
"Only kill emacs if a prefix is set"
|
||
(if (and (not spacemacs-really-kill-emacs)
|
||
(spacemacs/persistent-server-running-p))
|
||
(spacemacs/frame-killer)
|
||
ad-do-it))
|
||
|
||
(defadvice save-buffers-kill-emacs (around spacemacs-really-exit activate)
|
||
"Only kill emacs if a prefix is set"
|
||
(if (or spacemacs-really-kill-emacs (not dotspacemacs-persistent-server))
|
||
ad-do-it
|
||
(spacemacs/frame-killer)))
|
||
|
||
(defun spacemacs/save-buffers-kill-emacs ()
|
||
"Save all changed buffers and exit Spacemacs"
|
||
(interactive)
|
||
(setq spacemacs-really-kill-emacs t)
|
||
(save-buffers-kill-emacs))
|
||
|
||
(defun spacemacs/kill-emacs ()
|
||
"Lose all changes and exit Spacemacs"
|
||
(interactive)
|
||
(setq spacemacs-really-kill-emacs t)
|
||
(kill-emacs))
|
||
|
||
(defun spacemacs/prompt-kill-emacs ()
|
||
"Prompt to save changed buffers and exit Spacemacs"
|
||
(interactive)
|
||
(setq spacemacs-really-kill-emacs t)
|
||
(save-some-buffers)
|
||
(kill-emacs))
|
||
|
||
(defun spacemacs/frame-killer ()
|
||
"Kill server buffer and hide the main Emacs window"
|
||
(interactive)
|
||
(condition-case-unless-debug nil
|
||
(delete-frame nil 1)
|
||
(error
|
||
(make-frame-invisible nil 1))))
|
||
|
||
(defun spacemacs/toggle-frame-fullscreen ()
|
||
"Respect the `dotspacemacs-fullscreen-use-non-native' variable when
|
||
toggling fullscreen."
|
||
(interactive)
|
||
(if dotspacemacs-fullscreen-use-non-native
|
||
(spacemacs/toggle-frame-fullscreen-non-native)
|
||
(toggle-frame-fullscreen)))
|
||
|
||
(defun spacemacs/toggle-fullscreen ()
|
||
"Toggle full screen on X11 and Carbon"
|
||
(interactive)
|
||
(cond
|
||
((eq window-system 'x)
|
||
(set-frame-parameter nil 'fullscreen
|
||
(when (not (frame-parameter nil 'fullscreen))
|
||
'fullboth)))
|
||
((eq window-system 'mac)
|
||
(set-frame-parameter
|
||
nil 'fullscreen
|
||
(when (not (frame-parameter nil 'fullscreen)) 'fullscreen)))))
|
||
|
||
(defun spacemacs/toggle-frame-fullscreen-non-native ()
|
||
"Toggle full screen non-natively. Uses the `fullboth' frame paramerter
|
||
rather than `fullscreen'. Useful to fullscreen on OSX w/o animations."
|
||
(interactive)
|
||
(modify-frame-parameters
|
||
nil
|
||
`((maximized
|
||
. ,(unless (memq (frame-parameter nil 'fullscreen) '(fullscreen fullboth))
|
||
(frame-parameter nil 'fullscreen)))
|
||
(fullscreen
|
||
. ,(if (memq (frame-parameter nil 'fullscreen) '(fullscreen fullboth))
|
||
(if (eq (frame-parameter nil 'maximized) 'maximized)
|
||
'maximized)
|
||
'fullboth)))))
|
||
|
||
;; taken from Prelude: https://github.com/bbatsov/prelude
|
||
(defmacro spacemacs|advise-commands (advice-name commands class &rest body)
|
||
"Apply advice named ADVICE-NAME to multiple COMMANDS.
|
||
The body of the advice is in BODY."
|
||
`(progn
|
||
,@(mapcar (lambda (command)
|
||
`(defadvice ,command
|
||
(,class ,(intern (format "%S-%s" command advice-name))
|
||
activate)
|
||
,@body))
|
||
commands)))
|
||
|
||
(defun spacemacs/safe-revert-buffer ()
|
||
"Prompt before reverting the file."
|
||
(interactive)
|
||
(revert-buffer nil nil))
|
||
|
||
(defun spacemacs/safe-erase-buffer ()
|
||
"Prompt before erasing the content of the file."
|
||
(interactive)
|
||
(if (y-or-n-p (format "Erase content of buffer %s ? " (current-buffer)))
|
||
(erase-buffer)))
|
||
|
||
(defun spacemacs/ert-run-tests-buffer ()
|
||
"Run all the tests in the current buffer."
|
||
(interactive)
|
||
(save-buffer)
|
||
(load-file (buffer-file-name))
|
||
(ert t))
|
||
|
||
(defun spacemacs/alternate-buffer ()
|
||
"Switch back and forth between current and last buffer in the
|
||
current window."
|
||
(interactive)
|
||
(if (evil-alternate-buffer)
|
||
(switch-to-buffer (car (evil-alternate-buffer)))
|
||
(switch-to-buffer (other-buffer (current-buffer) t))))
|
||
|
||
(defun current-line ()
|
||
"Return the line at point as a string."
|
||
(buffer-substring (line-beginning-position) (line-end-position)))
|
||
|
||
(defun spacemacs/open-in-external-app ()
|
||
"Open current file in external application."
|
||
(interactive)
|
||
(let ((file-path (if (eq major-mode 'dired-mode)
|
||
(dired-get-file-for-visit)
|
||
(buffer-file-name))))
|
||
(if file-path
|
||
(cond
|
||
((spacemacs/system-is-mswindows) (w32-shell-execute "open" (replace-regexp-in-string "/" "\\\\" file-path)))
|
||
((spacemacs/system-is-mac) (shell-command (format "open \"%s\"" file-path)))
|
||
((spacemacs/system-is-linux) (let ((process-connection-type nil))
|
||
(start-process "" nil "xdg-open" file-path))))
|
||
(message "No file associated to this buffer."))))
|
||
|
||
(defun spacemacs/switch-to-minibuffer-window ()
|
||
"switch to minibuffer window (if active)"
|
||
(interactive)
|
||
(when (active-minibuffer-window)
|
||
(select-window (active-minibuffer-window))))
|
||
|
||
(defun spacemacs/comint-clear-buffer ()
|
||
(interactive)
|
||
(let ((comint-buffer-maximum-size 0))
|
||
(comint-truncate-buffer)))
|
||
|
||
;; http://stackoverflow.com/a/10216338/4869
|
||
(defun spacemacs/copy-whole-buffer-to-clipboard ()
|
||
"Copy entire buffer to clipboard"
|
||
(interactive)
|
||
(clipboard-kill-ring-save (point-min) (point-max)))
|
||
|
||
(defun spacemacs/copy-clipboard-to-whole-buffer ()
|
||
"Copy clipboard and replace buffer"
|
||
(interactive)
|
||
(delete-region (point-min) (point-max))
|
||
(clipboard-yank)
|
||
(deactivate-mark))
|
||
|
||
;; BEGIN align functions
|
||
|
||
;; modified function from http://emacswiki.org/emacs/AlignCommands
|
||
(defun spacemacs/align-repeat (start end regexp &optional justify-right after)
|
||
"Repeat alignment with respect to the given regular expression.
|
||
If JUSTIFY-RIGHT is non nil justify to the right instead of the
|
||
left. If AFTER is non-nil, add whitespace to the left instead of
|
||
the right."
|
||
(interactive "r\nsAlign regexp: ")
|
||
(let ((complete-regexp (if after
|
||
(concat regexp "\\([ \t]*\\)")
|
||
(concat "\\([ \t]*\\)" regexp)))
|
||
(group (if justify-right -1 1)))
|
||
(align-regexp start end complete-regexp group 1 t)))
|
||
|
||
;; Modified answer from http://emacs.stackexchange.com/questions/47/align-vertical-columns-of-numbers-on-the-decimal-point
|
||
(defun spacemacs/align-repeat-decimal (start end)
|
||
"Align a table of numbers on decimal points and dollar signs (both optional)"
|
||
(interactive "r")
|
||
(require 'align)
|
||
(align-region start end nil
|
||
'((nil (regexp . "\\([\t ]*\\)\\$?\\([\t ]+[0-9]+\\)\\.?")
|
||
(repeat . t)
|
||
(group 1 2)
|
||
(spacing 1 1)
|
||
(justify nil t)))
|
||
nil))
|
||
|
||
(defmacro spacemacs|create-align-repeat-x (name regexp &optional justify-right default-after)
|
||
(let ((new-func (intern (concat "spacemacs/align-repeat-" name))))
|
||
`(defun ,new-func (start end switch)
|
||
(interactive "r\nP")
|
||
(let ((after (not (eq (if switch t nil) (if ,default-after t nil)))))
|
||
(spacemacs/align-repeat start end ,regexp ,justify-right after)))))
|
||
|
||
(spacemacs|create-align-repeat-x "comma" "," nil t)
|
||
(spacemacs|create-align-repeat-x "semicolon" ";" nil t)
|
||
(spacemacs|create-align-repeat-x "colon" ":" nil t)
|
||
(spacemacs|create-align-repeat-x "equal" "=")
|
||
(spacemacs|create-align-repeat-x "math-oper" "[+\\-*/]")
|
||
(spacemacs|create-align-repeat-x "ampersand" "&")
|
||
(spacemacs|create-align-repeat-x "bar" "|")
|
||
(spacemacs|create-align-repeat-x "left-paren" "(")
|
||
(spacemacs|create-align-repeat-x "right-paren" ")" t)
|
||
(spacemacs|create-align-repeat-x "backslash" "\\\\")
|
||
|
||
;; END align functions
|
||
|
||
(defun spacemacs/dos2unix ()
|
||
"Converts the current buffer to UNIX file format."
|
||
(interactive)
|
||
(set-buffer-file-coding-system 'undecided-unix nil))
|
||
|
||
(defun spacemacs/unix2dos ()
|
||
"Converts the current buffer to DOS file format."
|
||
(interactive)
|
||
(set-buffer-file-coding-system 'undecided-dos nil))
|
||
|
||
(defun spacemacs/copy-file ()
|
||
"Write the file under new name."
|
||
(interactive)
|
||
(call-interactively 'write-file))
|
||
|
||
(defun spacemacs//imagep (object)
|
||
"Tests whether the given object is an image (a list whose
|
||
first element is the symbol `image')."
|
||
(and (listp object)
|
||
object
|
||
(eq 'image (car object))))
|
||
|
||
(defun spacemacs/uniquify-lines ()
|
||
"Remove duplicate adjacent lines in region or current buffer"
|
||
(interactive)
|
||
(save-excursion
|
||
(save-restriction
|
||
(let ((beg (if (region-active-p) (region-beginning) (point-min)))
|
||
(end (if (region-active-p) (region-end) (point-max))))
|
||
(goto-char beg)
|
||
(while (re-search-forward "^\\(.*\n\\)\\1+" end t)
|
||
(replace-match "\\1"))))))
|
||
|
||
(defun spacemacs/sort-lines ()
|
||
"Sort lines in region or current buffer"
|
||
(interactive)
|
||
(let ((beg (if (region-active-p) (region-beginning) (point-min)))
|
||
(end (if (region-active-p) (region-end) (point-max))))
|
||
(sort-lines nil beg end)))
|
||
|
||
;; BEGIN linum mouse helpers
|
||
|
||
(defvar spacemacs-linum-mdown-line nil
|
||
"Define persistent variable for linum selection")
|
||
|
||
(defun spacemacs/line-at-click ()
|
||
"Determine the visual line at click"
|
||
(save-excursion
|
||
(let ((click-y (cddr (mouse-position)))
|
||
(debug-on-error t)
|
||
(line-move-visual t))
|
||
(goto-char (window-start))
|
||
(next-line (1- click-y))
|
||
(1+ (line-number-at-pos))
|
||
)))
|
||
|
||
(defun spacemacs/md-select-linum (event)
|
||
"Set point as spacemacs-linum-mdown-line"
|
||
(interactive "e")
|
||
(mouse-select-window event)
|
||
(goto-line (spacemacs/line-at-click))
|
||
(set-mark (point))
|
||
(setq spacemacs-linum-mdown-line
|
||
(line-number-at-pos)))
|
||
|
||
(defun spacemacs/mu-select-linum ()
|
||
"Select code block between point and spacemacs-linum-mdown-line"
|
||
(interactive)
|
||
(when spacemacs-linum-mdown-line
|
||
(let (mu-line)
|
||
(setq mu-line (spacemacs/line-at-click))
|
||
(goto-line (max spacemacs-linum-mdown-line mu-line))
|
||
(set-mark (line-end-position))
|
||
(goto-line (min spacemacs-linum-mdown-line mu-line))
|
||
(setq spacemacs-linum-mdown-line nil))))
|
||
|
||
(defun spacemacs/select-current-block ()
|
||
"Select the current block of text between blank lines."
|
||
(interactive)
|
||
(let (p1 p2)
|
||
(progn
|
||
(if (re-search-backward "\n[ \t]*\n" nil "move")
|
||
(progn (re-search-forward "\n[ \t]*\n")
|
||
(setq p1 (point)))
|
||
(setq p1 (point)))
|
||
(if (re-search-forward "\n[ \t]*\n" nil "move")
|
||
(progn (re-search-backward "\n[ \t]*\n")
|
||
(setq p2 (point)))
|
||
(setq p2 (point))))
|
||
(set-mark p1)))
|
||
|
||
;; END linum mouse helpers
|
||
|
||
;; From http://xugx2007.blogspot.ca/2007/06/benjamin-rutts-emacs-c-development-tips.html
|
||
(setq compilation-finish-function
|
||
(lambda (buf str)
|
||
|
||
(if (or (string-match "exited abnormally" str)
|
||
(string-match "FAILED" (buffer-string)))
|
||
|
||
;; there were errors
|
||
(message "There were errors. SPC-e-n to visit.")
|
||
(unless (or (string-match "Grep finished" (buffer-string))
|
||
(string-match "Ag finished" (buffer-string))
|
||
(string-match "nosetests" (buffer-name)))
|
||
|
||
;; no errors
|
||
(message "compilation ok.")))))
|
||
|
||
;; from http://www.emacswiki.org/emacs/WordCount
|
||
(defun spacemacs/count-words-analysis (start end)
|
||
"Count how many times each word is used in the region.
|
||
Punctuation is ignored."
|
||
(interactive "r")
|
||
(let (words alist_words_compare (formated ""))
|
||
(save-excursion
|
||
(goto-char start)
|
||
(while (re-search-forward "\\w+" end t)
|
||
(let* ((word (intern (match-string 0)))
|
||
(cell (assq word words)))
|
||
(if cell
|
||
(setcdr cell (1+ (cdr cell)))
|
||
(setq words (cons (cons word 1) words))))))
|
||
(defun alist_words_compare (a b)
|
||
"Compare elements from an associative list of words count.
|
||
Compare them on count first,and in case of tie sort them alphabetically."
|
||
(let ((a_key (car a))
|
||
(a_val (cdr a))
|
||
(b_key (car b))
|
||
(b_val (cdr b)))
|
||
(if (eq a_val b_val)
|
||
(string-lessp a_key b_key)
|
||
(> a_val b_val))))
|
||
(setq words (cl-sort words 'alist_words_compare))
|
||
(while words
|
||
(let* ((word (pop words))
|
||
(name (car word))
|
||
(count (cdr word)))
|
||
(setq formated (concat formated (format "[%s: %d], " name count)))))
|
||
(when (interactive-p)
|
||
(if (> (length formated) 2)
|
||
(message (substring formated 0 -2))
|
||
(message "No words.")))
|
||
words))
|
||
|
||
;; indent on paste
|
||
;; from Prelude: https://github.com/bbatsov/prelude
|
||
(defun spacemacs/yank-advised-indent-function (beg end)
|
||
"Do indentation, as long as the region isn't too large."
|
||
(if (<= (- end beg) spacemacs-yank-indent-threshold)
|
||
(indent-region beg end nil)))
|
||
|
||
(spacemacs|advise-commands
|
||
"indent" (yank yank-pop evil-paste-before evil-paste-after) around
|
||
"If current mode is not one of spacemacs-indent-sensitive-modes
|
||
indent yanked text (with universal arg don't indent)."
|
||
(evil-start-undo-step)
|
||
ad-do-it
|
||
(if (and (not (equal '(4) (ad-get-arg 0)))
|
||
(not (member major-mode spacemacs-indent-sensitive-modes))
|
||
(or (derived-mode-p 'prog-mode)
|
||
(member major-mode spacemacs-indent-sensitive-modes)))
|
||
(let ((transient-mark-mode nil)
|
||
(save-undo buffer-undo-list))
|
||
(spacemacs/yank-advised-indent-function (region-beginning)
|
||
(region-end))))
|
||
(evil-end-undo-step))
|
||
|
||
;; find file functions in split
|
||
(defun spacemacs//display-in-split (buffer alist)
|
||
"Split selected window and display BUFFER in the new window.
|
||
BUFFER and ALIST have the same form as in `display-buffer'. If ALIST contains
|
||
a split-side entry, its value must be usable as the SIDE argument for
|
||
`split-window'."
|
||
(let ((window (split-window nil nil (cdr (assq 'split-side alist)))))
|
||
(window--display-buffer buffer window 'window alist)
|
||
window))
|
||
|
||
(defun spacemacs/find-file-vsplit (file)
|
||
"find file in vertical split"
|
||
(interactive "FFind file (vsplit): ")
|
||
(let ((buffer (find-file-noselect file)))
|
||
(pop-to-buffer buffer '(spacemacs//display-in-split (split-side . right)))))
|
||
|
||
(defun spacemacs/find-file-split (file)
|
||
"find file in horizonatl split"
|
||
(interactive "FFind file (split): ")
|
||
(let ((buffer (find-file-noselect file)))
|
||
(pop-to-buffer buffer '(spacemacs//display-in-split (split-side . below)))))
|
||
|
||
(defun spacemacs//intersperse (seq separator)
|
||
"Returns a list with `SEPARATOR' added between each element
|
||
of the list `SEQ'."
|
||
(cond
|
||
((not seq) nil)
|
||
((not (cdr seq)) seq)
|
||
(t (append (list (car seq) separator)
|
||
(spacemacs//intersperse (cdr seq) separator)))))
|
||
|
||
(defun spacemacs//mode-line-nonempty (seg)
|
||
"Checks whether a modeline segment (classical Emacs style)
|
||
is nonempty."
|
||
(let ((val (format-mode-line seg)))
|
||
(cond ((listp val) val)
|
||
((stringp val) (< 0 (length val)))
|
||
(t))))
|
||
|
||
(defun spacemacs/switch-to-scratch-buffer ()
|
||
"Switch to the `*scratch*' buffer. Create it first if needed."
|
||
(interactive)
|
||
(let ((exists (get-buffer "*scratch*")))
|
||
(switch-to-buffer (get-buffer-create "*scratch*"))
|
||
(when (and (not exists)
|
||
(not (eq major-mode dotspacemacs-scratch-mode))
|
||
(fboundp dotspacemacs-scratch-mode))
|
||
(funcall dotspacemacs-scratch-mode))))
|
||
|
||
;; http://stackoverflow.com/questions/11847547/emacs-regexp-count-occurrences
|
||
(defun how-many-str (regexp str)
|
||
(loop with start = 0
|
||
for count from 0
|
||
while (string-match regexp str start)
|
||
do (setq start (match-end 0))
|
||
finally return count))
|
||
|
||
(defun spacemacs/close-compilation-window ()
|
||
"Close the window containing the '*compilation*' buffer."
|
||
(interactive)
|
||
(when compilation-last-buffer
|
||
(delete-windows-on compilation-last-buffer)))
|
||
|
||
(defun no-linum (&rest ignore)
|
||
"Disable linum if current buffer."
|
||
(when (or 'linum-mode global-linum-mode)
|
||
(linum-mode 0)))
|
||
|
||
|
||
;; Generalized next-error system ("gne")
|
||
|
||
(defun spacemacs//error-delegate ()
|
||
"Decide which error API to delegate to.
|
||
|
||
Delegates to flycheck if it is enabled and the next-error buffer
|
||
is not visible. Otherwise delegates to regular Emacs next-error."
|
||
(if (and (bound-and-true-p flycheck-mode)
|
||
(let ((buf (next-error-find-buffer)))
|
||
(not (and buf (get-buffer-window buf)))))
|
||
'flycheck
|
||
'emacs))
|
||
|
||
(defun spacemacs/next-error (&optional n reset)
|
||
"Dispatch to flycheck or standard emacs error."
|
||
(interactive "P")
|
||
(let ((sys (spacemacs//error-delegate)))
|
||
(cond
|
||
((eq 'flycheck sys) (call-interactively 'flycheck-next-error))
|
||
((eq 'emacs sys) (call-interactively 'next-error)))))
|
||
|
||
(defun spacemacs/previous-error (&optional n reset)
|
||
"Dispatch to flycheck or standard emacs error."
|
||
(interactive "P")
|
||
(let ((sys (spacemacs//error-delegate)))
|
||
(cond
|
||
((eq 'flycheck sys) (call-interactively 'flycheck-previous-error))
|
||
((eq 'emacs sys) (call-interactively 'previous-error)))))
|
||
|
||
(defvar-local spacemacs--gne-min-line nil
|
||
"The first line in the buffer that is a valid result.")
|
||
(defvar-local spacemacs--gne-max-line nil
|
||
"The last line in the buffer that is a valid result.")
|
||
(defvar-local spacemacs--gne-cur-line 0
|
||
"The current line in the buffer. (It is problematic to use
|
||
point for this.)")
|
||
(defvar-local spacemacs--gne-line-func nil
|
||
"The function to call to visit the result on a line.")
|
||
|
||
(defun spacemacs//gne-next (num reset)
|
||
"A generalized next-error function. This function can be used
|
||
as `next-error-function' in any buffer that conforms to the
|
||
Spacemacs generalized next-error API.
|
||
|
||
The variables `spacemacs--gne-min-line',
|
||
`spacemacs--gne-max-line', and `spacemacs--line-func' must be
|
||
set."
|
||
(when reset (setq spacemacs--gne-cur-line
|
||
spacemacs--gne-min-line))
|
||
(setq spacemacs--gne-cur-line
|
||
(min spacemacs--gne-max-line
|
||
(max spacemacs--gne-min-line
|
||
(+ num spacemacs--gne-cur-line))))
|
||
(goto-line spacemacs--gne-cur-line)
|
||
(funcall spacemacs--gne-line-func
|
||
(buffer-substring (point-at-bol) (point-at-eol))))
|