aboutsummaryrefslogtreecommitdiff
path: root/.config/emacs/lisp/evil-collection/modes/unimpaired
diff options
context:
space:
mode:
Diffstat (limited to '.config/emacs/lisp/evil-collection/modes/unimpaired')
-rw-r--r--.config/emacs/lisp/evil-collection/modes/unimpaired/evil-collection-unimpaired.el313
1 files changed, 313 insertions, 0 deletions
diff --git a/.config/emacs/lisp/evil-collection/modes/unimpaired/evil-collection-unimpaired.el b/.config/emacs/lisp/evil-collection/modes/unimpaired/evil-collection-unimpaired.el
new file mode 100644
index 0000000..4d9710f
--- /dev/null
+++ b/.config/emacs/lisp/evil-collection/modes/unimpaired/evil-collection-unimpaired.el
@@ -0,0 +1,313 @@
+;;; evil-collection-unimpaired.el --- Evil Collection port of Unimpaired -*- lexical-binding: t -*-
+
+;; Copyright (C) 2019 James Nguyen
+
+;; Author: James Nguyen <james@jojojames.com>
+;; Maintainer: James Nguyen <james@jojojames.com>
+;; Pierre Neidhardt <mail@ambrevar.xyz>
+;; URL: https://github.com/emacs-evil/evil-collection
+;; Version: 0.0.1
+;; Package-Requires: ((emacs "26.3"))
+;; Keywords: evil, unimpaired, tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;; `evil' port of unimpaired for `evil-collection'.
+;; https://github.com/tpope/vim-unimpaired
+
+;;; Code:
+(require 'evil-collection)
+
+;; Externals
+(defvar flycheck-current-errors)
+
+(defgroup evil-collection-unimpaired nil
+ "Evil port of unimpaired for `evil-collection'."
+ :group 'evil-collection)
+
+(defcustom evil-collection-unimpaired-want-repeat-mode-integration nil
+ "Whether or not to enable `repeat-mode' integration."
+ :type 'boolean
+ :group 'evil-collection)
+
+(defconst evil-collection-unimpaired-maps '(evil-collection-unimpaired-mode-map))
+
+(defvar evil-collection-unimpaired-mode-map (make-sparse-keymap)
+ "Keymap for `evil-collection-unimpaired-mode'.")
+
+(define-minor-mode evil-collection-unimpaired-mode
+ "Evil port of unimpaired."
+ :lighter " unimpaired"
+ :group 'evil-collection-unimpaired)
+
+;;;###autoload
+(define-globalized-minor-mode global-evil-collection-unimpaired-mode
+ evil-collection-unimpaired-mode evil-collection-unimpaired-mode-on
+ :group 'evil-collection-unimpaired)
+
+(defun evil-collection-unimpaired-mode-on ()
+ "Turn on `evil-collection-unimpaired-mode'."
+ (evil-collection-unimpaired-mode 1))
+
+(evil-define-motion evil-collection-unimpaired-next-error (count)
+ "Go to next error."
+ :jump t
+ (setq count (or count 1))
+ (cond
+ ((and (bound-and-true-p flycheck-mode)
+ (fboundp 'flycheck-next-error))
+ (flycheck-next-error count))
+ ((and (bound-and-true-p flymake-mode)
+ (fboundp 'flymake-goto-next-error))
+ (flymake-goto-next-error count))
+ (:default
+ (message "No linting modes are on."))))
+
+(evil-define-motion evil-collection-unimpaired-previous-error (count)
+ "Go to previous error."
+ :jump t
+ (evil-collection-unimpaired-next-error (- (or count 1))))
+
+(defun evil-collection-unimpaired--flycheck-count-errors ()
+ "Count the number of flycheck errors."
+ (length (delete-dups (mapcar 'flycheck-error-line flycheck-current-errors))))
+
+(evil-define-motion evil-collection-unimpaired-first-error ()
+ "Go to the first error."
+ :jump t
+ (cond
+ ((and (bound-and-true-p flycheck-mode)
+ (fboundp 'flycheck-first-error))
+ (flycheck-first-error))
+ ((bound-and-true-p flymake-mode)
+ (message "flymake unsupported."))
+ (:default
+ (message "No linting modes are on."))))
+
+(evil-define-motion evil-collection-unimpaired-last-error ()
+ "Go to the last error."
+ :jump t
+ (cond
+ ((and (bound-and-true-p flycheck-mode)
+ (fboundp 'flycheck-first-error))
+ (flycheck-first-error (evil-collection-unimpaired--flycheck-count-errors)))
+ ((bound-and-true-p flymake-mode)
+ (message "flymake unsupported."))
+ (:default
+ (message "No linting modes are on."))))
+
+(defconst evil-collection-unimpaired--SCM-conflict-marker "^\\(@@@ .* @@@\\|[<=>]\\{7\\}\\)"
+ "A regexp to match SCM conflict marker.")
+
+(evil-define-motion evil-collection-unimpaired-previous-SCM-conflict-marker (count)
+ "Go to the previous SCM conflict marker or diff/patch hunk."
+ :jump t
+ (evil-collection-unimpaired-next-SCM-conflict-marker (- (or count 1))))
+
+(evil-define-motion evil-collection-unimpaired-next-SCM-conflict-marker (count)
+ "Go to the next SCM conflict marker or diff/patch hunk."
+ :jump t
+ (evil-motion-loop (dir (or count 1))
+ (cond
+ ((> dir 0)
+ (forward-line 1)
+ (when (not (search-forward-regexp evil-collection-unimpaired--SCM-conflict-marker nil t))
+ (forward-line -1))
+ (move-beginning-of-line nil))
+ (t
+ (search-backward-regexp evil-collection-unimpaired--SCM-conflict-marker nil t)
+ (move-beginning-of-line nil)))))
+
+(defun evil-collection-unimpaired-paste-above ()
+ "Paste above current line with preserving indentation."
+ (interactive)
+ (let ((indent (current-indentation))
+ (column (current-column)))
+ (evil-insert-newline-above)
+ (indent-to indent)
+ (evil-paste-after 1)
+ (move-to-column column)))
+
+(defun evil-collection-unimpaired-paste-below ()
+ "Paste below current line with preserving indentation."
+ (interactive)
+ (let ((indent (current-indentation))
+ (column (current-column)))
+ (evil-insert-newline-below)
+ (indent-to indent)
+ (evil-paste-after 1)
+ (move-to-column column)))
+
+(defun evil-collection-unimpaired-insert-newline-above (count)
+ "Insert COUNT blank line(s) above current line."
+ (interactive "p")
+ (save-excursion (dotimes (_ count) (evil-insert-newline-above)))
+ (when (bolp) (forward-char count)))
+
+(defun evil-collection-unimpaired-insert-newline-below (count)
+ "Insert COUNT blank line(s) below current line."
+ (interactive "p")
+ (save-excursion (dotimes (_ count) (evil-insert-newline-below))))
+
+(defun evil-collection-unimpaired--encode (beg end fn)
+ "Apply FN from BEG to END."
+ (save-excursion
+ (goto-char beg)
+ (let* ((end (if (eq evil-this-type 'line) (1- end) end))
+ (text (buffer-substring-no-properties beg end)))
+ (delete-region beg end)
+ (insert (funcall fn text)))))
+
+(evil-define-operator evil-collection-unimpaired-url-encode (count &optional beg end)
+ "Encode a URL string."
+ (interactive "<c><r>")
+ (ignore count)
+ (evil-collection-unimpaired--encode beg end #'url-encode-url))
+
+(evil-define-operator evil-collection-unimpaired-url-decode (count &optional beg end)
+ "Decode a URL string."
+ (interactive "<c><r>")
+ (ignore count)
+ (evil-collection-unimpaired--encode beg end #'url-unhex-string))
+
+(evil-define-operator evil-collection-unimpaired-b64-encode (count &optional beg end)
+ "Encode a base64 string."
+ (interactive "<c><r>")
+ (ignore count)
+ (evil-collection-unimpaired--encode beg end #'base64-encode-string))
+
+(evil-define-operator evil-collection-unimpaired-b64-decode (count &optional beg end)
+ "Decode a base64 string."
+ (interactive "<c><r>")
+ (ignore count)
+ (evil-collection-unimpaired--encode beg end #'base64-decode-string))
+
+;; https://stackoverflow.com/questions/2423834/move-line-region-up-and-down-in-emacs
+(defun evil-collection-unimpaired--move-text (arg)
+ "Move text down if ARG is positive, otherwise move text up."
+ (cond
+ ((and mark-active transient-mark-mode)
+ (when (> (point) (mark))
+ (exchange-point-and-mark))
+ (let ((column (current-column))
+ (text (delete-and-extract-region (point) (mark))))
+ (forward-line arg)
+ (move-to-column column :force)
+ (set-mark (point))
+ (insert text)
+ (exchange-point-and-mark)
+ (setq deactivate-mark nil)))
+ (t
+ (let ((column (current-column)))
+ (beginning-of-line)
+ (when (or (> arg 0) (not (bobp)))
+ (forward-line)
+ (when (or (< arg 0) (not (eobp)))
+ (transpose-lines arg))
+ (forward-line -1))
+ (move-to-column column)))))
+
+(defun evil-collection-unimpaired-move-text-down (arg)
+ "Move region (transient-mark-mode active) or current line ARG lines down."
+ (interactive "*p")
+ (evil-collection-unimpaired--move-text arg))
+
+(defun evil-collection-unimpaired-move-text-up (arg)
+ "Move region (transient-mark-mode active) or current line ARG lines up."
+ (interactive "*p")
+ (evil-collection-unimpaired--move-text (- arg)))
+
+;;; 'repeat-mode' integration. Emacs 28+
+(defmacro evil-collection-unimpaired-defvar-keymap (name &rest bindings)
+ "Define NAME a keymap with BINDINGS."
+ (declare (indent 1))
+ (cl-assert (cl-evenp (length bindings)))
+ `(progn
+ (defvar ,name
+ (let ((map (make-sparse-keymap)))
+ map))
+ (evil-collection-define-key nil ',name ,@bindings)))
+
+;; "[b" and "]b"
+(evil-collection-unimpaired-defvar-keymap evil-prev-buffer-repeat-map
+ "b" #'evil-prev-buffer
+ "B" #'evil-next-buffer)
+(evil-collection-unimpaired-defvar-keymap evil-next-buffer-repeat-map
+ "b" #'evil-next-buffer
+ "B" #'evil-prev-buffer)
+
+;; "[e" and "]e"
+(evil-collection-unimpaired-defvar-keymap evil-collection-unimpaired-move-text-up-repeat-map
+ "e" #'evil-collection-unimpaired-move-text-up
+ "E" #'evil-collection-unimpaired-move-text-down)
+(evil-collection-unimpaired-defvar-keymap evil-collection-unimpaired-move-text-down-repeat-map
+ "e" #'evil-collection-unimpaired-move-text-down
+ "E" #'evil-collection-unimpaired-move-text-up)
+
+;; "[q" and "]q"
+(evil-collection-unimpaired-defvar-keymap evil-collection-unimpaired-previous-error-repeat-map
+ "q" #'evil-collection-unimpaired-previous-error
+ "Q" #'evil-collection-unimpaired-next-error)
+(evil-collection-unimpaired-defvar-keymap evil-collection-unimpaired-next-error-repeat-map
+ "q" #'evil-collection-unimpaired-next-error
+ "Q" #'evil-collection-unimpaired-previous-error)
+
+;;;###autoload
+(defun evil-collection-unimpaired-setup ()
+ "Set up unimpaired-like bindings."
+ (global-evil-collection-unimpaired-mode 1)
+ (evil-collection-define-key 'normal 'evil-collection-unimpaired-mode-map
+ "[b" 'evil-prev-buffer
+ "]b" 'evil-next-buffer
+ "[e" 'evil-collection-unimpaired-move-text-up
+ "]e" 'evil-collection-unimpaired-move-text-down
+ "[l" 'evil-collection-unimpaired-previous-error
+ "]l" 'evil-collection-unimpaired-next-error
+ "[L" 'evil-collection-unimpaired-first-error
+ "]L" 'evil-collection-unimpaired-last-error
+ "[q" 'evil-collection-unimpaired-previous-error
+ "]q" 'evil-collection-unimpaired-next-error
+ "[Q" 'evil-collection-unimpaired-first-error
+ "]Q" 'evil-collection-unimpaired-last-error
+ "[n" 'evil-collection-unimpaired-previous-SCM-conflict-marker
+ "]n" 'evil-collection-unimpaired-next-SCM-conflict-marker
+ "[p" 'evil-collection-unimpaired-paste-above
+ "]p" 'evil-collection-unimpaired-paste-below
+ "[P" 'evil-collection-unimpaired-paste-above
+ "]P" 'evil-collection-unimpaired-paste-below
+ (kbd "[ SPC") 'evil-collection-unimpaired-insert-newline-above
+ (kbd "] SPC") 'evil-collection-unimpaired-insert-newline-below)
+ (evil-collection-define-key 'visual 'evil-collection-unimpaired-mode-map
+ "[e" 'evil-collection-unimpaired-move-text-up
+ "]e" 'evil-collection-unimpaired-move-text-down
+ "[n" 'evil-collection-unimpaired-previous-SCM-conflict-marker
+ "]n" 'evil-collection-unimpaired-next-SCM-conflict-marker)
+ (evil-collection-define-key 'motion 'evil-collection-unimpaired-mode-map
+ "[u" 'evil-collection-unimpaired-url-encode
+ "]u" 'evil-collection-unimpaired-url-decode
+ "[6" 'evil-collection-unimpaired-b64-encode
+ "]6" 'evil-collection-unimpaired-b64-decode)
+
+ (when evil-collection-unimpaired-want-repeat-mode-integration
+ (dolist (cmd '(evil-prev-buffer
+ evil-next-buffer
+ evil-collection-unimpaired-move-text-up
+ evil-collection-unimpaired-move-text-down
+ evil-collection-unimpaired-previous-error
+ evil-collection-unimpaired-next-error))
+ (put cmd 'repeat-map (intern (format "%s-repeat-map" cmd))))))
+
+(provide 'evil-collection-unimpaired)
+;;; evil-collection-unimpaired.el ends here