mirror of
https://github.com/vale981/boon
synced 2025-03-04 17:11:40 -05:00
structure in layers
This commit is contained in:
parent
d753df2dc1
commit
86c040b54f
13 changed files with 605 additions and 526 deletions
83
README.md
83
README.md
|
@ -1,20 +1,20 @@
|
|||
Boon: An Ergonomic Command Mode for Emacs
|
||||
==========================================
|
||||
|
||||
Boon is another package for modal editing.
|
||||
Boon is a complete package for modal editing, which is not Evil.
|
||||
|
||||
Selling points:
|
||||
- Ergonomic: common commands are easy to type. (See below)
|
||||
- Lightweight: ~300 loc for its core.
|
||||
- Good emacs integration: takes advantage of, and leverages existing
|
||||
emacs infrastructure instead of re-inventing the wheel.
|
||||
- Good Emacs integration: integrates with existing Emacs
|
||||
infrastructure and takes advantage of it.
|
||||
|
||||
|
||||
Design
|
||||
------
|
||||
Ergonomic Design
|
||||
----------------
|
||||
|
||||
It is largely accepted that modal edition is more ergonomic than using
|
||||
keychord. Boon attempts to make modal editing as comfortable as
|
||||
key-chords. Boon attempts to make modal editing as comfortable as
|
||||
possible, by adhering to the following design principles:
|
||||
|
||||
- Spacial allocation first, mnemonics second: the allocation of keys
|
||||
|
@ -49,20 +49,53 @@ manipulation) are bound to the home row. The top row is (mainly) for
|
|||
searching. The bottom row gives access to regular Emacs stuff (C-x
|
||||
...) (C-c ...) and registers.
|
||||
|
||||
|
||||
Emacs Integration: Reusable Modules
|
||||
-----------------------------------
|
||||
|
||||
Boon is designed as a layer of modules, which are reusable and
|
||||
customizable, in full agreement with the Emacs spirit. This means that
|
||||
even if you disagree with the frontend choices made above, you may
|
||||
still want to use parts of Boon, as these are re-usable.
|
||||
|
||||
1. boon-moves, boon-search: a set of move and search commands. These
|
||||
work the same way as standard Emacs commands; they are merely
|
||||
(maybe) more powerful. Frontends typically bind these commands (and
|
||||
more) in boon-moves-map, which is active in 'command mode'.
|
||||
2. boon-arguments: a set of combinators to define regions. Combinators
|
||||
include plain regions (words, lines, paragraphs, ...), but also
|
||||
region transformers (think: exclude borders, just borders,
|
||||
including spaces, foreach, etc.). Additionally every move command in
|
||||
boon-moves-map can be used to define a region. The system supports
|
||||
multiple cursors.
|
||||
3. boon-core: An infrastructure for modal editing, inspired from
|
||||
evil-core.
|
||||
4. boon-main: A set of commands similar to standard Emacs commands,
|
||||
but which uses the system of combinators. (Additionally some random
|
||||
extra commands are thrown in for good measure.) These commands may
|
||||
be used in combination with a modal system, or not. A few commands
|
||||
also switch to insert mode.
|
||||
5. boon-keys, boon-colemak, boon-qwerty, ...: frontends. Those
|
||||
'require all the above and provide a mapping of moves, combinators
|
||||
and commands onto keys. They may also bind keys for other 'modes',
|
||||
such as helm.
|
||||
|
||||
Installation/Configuration
|
||||
--------------------------
|
||||
|
||||
REQUIREMENTS
|
||||
- Emacs version >= 24.5
|
||||
- Colemak layout
|
||||
- Colemak layout (qwerty version exists but tutorial assumes colemak
|
||||
layout)
|
||||
|
||||
Install Boon (perhaps using
|
||||
[](http://stable.melpa.org/#/boon)),
|
||||
and add the following to your configuration:
|
||||
|
||||
(require 'boon-colemak) ;; qwerty mode not implemented (contributions welcome)
|
||||
(require 'boon-extras) ;; optional
|
||||
(boon-mode) ;; enable boon everywhere (use turn-on-boon-mode) to try locally
|
||||
(require 'boon-colemak)
|
||||
;; (require 'boon-qwerty) ;; for qwerty port (alpha quality)
|
||||
(boon-powerline-theme) ;; if you want use powerline with Boon
|
||||
(boon-mode) ;; to enable boon everywhere (use M-x turn-on-boon-mode) to try locally
|
||||
|
||||
You can jump-start by reading the
|
||||
[cheat sheet](https://pdf.yt/d/hSKUThNNSxrNFXkQ) directly, but reading
|
||||
|
@ -81,13 +114,26 @@ As far as I know, none of the other modal mode care about ergonomics
|
|||
|
||||
Evil is a (quite) complete vi emulation layer for Emacs.
|
||||
|
||||
In boon, quite a bit of Emacs structure and user experience is
|
||||
retained. Examples: the x key gives the C-x prefix map.
|
||||
Interactive arguments are used for text objects.
|
||||
In Boon, quite a bit of Emacs structure and user experience is
|
||||
retained. Examples: the x key gives the C-x prefix map. The usual
|
||||
Emacs (interactive) arguments are used for text objects. Thus most of
|
||||
Boon remains usable even if one does not wish to use modal editing.
|
||||
|
||||
Besides, Emacs is already customizable enough as it is: the core of
|
||||
Boon is just 200 lines or so. Figuring out all the ins and outs of
|
||||
Evil to do what I want would probably require more effort.
|
||||
Boon is just 300 lines or so. Figuring out all the ins and outs of
|
||||
Evil to do what I want would probably have required more effort than
|
||||
implementing Boon.
|
||||
|
||||
Finally, evil use vi bindings (by default at least), which do not
|
||||
feature the best ergonomics.
|
||||
|
||||
- Fingers https://github.com/fgeller/fingers.el
|
||||
|
||||
Fingers borrows a few ideas from Boon, including the division of work
|
||||
between left and right hand. fgeller gives a detailed account of the
|
||||
particular differences with Boon. My opinion is that fingers is
|
||||
compatible with Boon concepts and could be implemented as a Boon
|
||||
'frontend'.
|
||||
|
||||
- God-mode https://github.com/chrisdone/god-mode
|
||||
|
||||
|
@ -98,10 +144,11 @@ As far as I know, none of the other modal mode care about ergonomics
|
|||
|
||||
- Modal Mode http://retroj.net/modal-mode
|
||||
|
||||
Perhaps the work which is the closest to Boon in principle
|
||||
(lightweight and integration with Emacs). However, as far as I can
|
||||
see, there is no special attention to ergonomics.
|
||||
Another modal layer for Emacs, which is also lightweight and aims to
|
||||
integrate with Emacs. However, as far as I can see, there is no
|
||||
special attention to ergonomics.
|
||||
|
||||
- Modal Emacs https://github.com/joelmccracken/modal-emacs
|
||||
|
||||
Modal Emacs does not appear to be complete.
|
||||
|
||||
|
|
|
@ -2,11 +2,20 @@
|
|||
|
||||
;;; Commentary:
|
||||
|
||||
|
||||
;; This file defines functions which are intended to be used as
|
||||
;; 'interactive' specifications: boon-spec-region and
|
||||
;; boon-spec-enclosure. These are used by boon commands, but can be
|
||||
;; used by any commands.
|
||||
;;
|
||||
;; In this module can also be found functions which are bound in
|
||||
;; boon-select-map. Those functions return a no-argument lambda which
|
||||
;; returns a list of boon-regs.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'boon-core)
|
||||
(require 'boon-regs)
|
||||
(require 'boon-utils)
|
||||
(require 'multiple-cursors)
|
||||
(require 'dash)
|
||||
|
||||
|
@ -58,16 +67,6 @@ This item is either the symbol at point, or, if this fails, the sexp at point."
|
|||
(lambda () (boon-regs-from-bounds (or (bounds-of-thing-at-point 'symbol)
|
||||
(bounds-of-thing-at-point 'sexp)))))
|
||||
|
||||
(defun boon-jump-over-blanks-forward ()
|
||||
"Jump over blanks, forward."
|
||||
(interactive)
|
||||
(skip-chars-forward "\n\t "))
|
||||
|
||||
(defun boon-jump-over-blanks-backward ()
|
||||
"Jump over blanks, backward."
|
||||
(interactive)
|
||||
(skip-chars-backward "\n\t "))
|
||||
|
||||
(defun boon-select-org-table-cell ()
|
||||
"Return the region between pipes (|)."
|
||||
(interactive)
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
;;; Commentary:
|
||||
;;; Code:
|
||||
(require 'boon-core)
|
||||
(require 'boon-main)
|
||||
(require 'boon-search)
|
||||
(require 'boon-keys)
|
||||
(require 'boon)
|
||||
|
||||
(define-key boon-select-map "q" 'boon-select-outside-quotes)
|
||||
(define-key boon-select-map "w" 'boon-select-word)
|
||||
|
@ -54,46 +51,44 @@
|
|||
(define-key boon-moves-map "H" 'avy-goto-char)
|
||||
|
||||
|
||||
(eval-after-load 'ivy
|
||||
'(progn
|
||||
(define-key ivy-minibuffer-map (kbd "RET") 'ivy-done)
|
||||
(define-key ivy-minibuffer-map (kbd "<C-return>") 'ivy-call)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-j") 'ivy-alt-done)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-j") 'ivy-immediate-done)
|
||||
(define-key ivy-minibuffer-map (kbd "C-n") 'ivy-partial)
|
||||
(define-key ivy-minibuffer-map (kbd "C-y") 'ivy-next-line)
|
||||
(define-key ivy-minibuffer-map (kbd "C-u") 'ivy-previous-line)
|
||||
(define-key ivy-minibuffer-map (kbd "<down>") 'ivy-next-line)
|
||||
(define-key ivy-minibuffer-map (kbd "<up>") 'ivy-previous-line)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-s") 'ivy-next-line-or-history)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-r") 'ivy-reverse-i-search)
|
||||
(define-key ivy-minibuffer-map (kbd "SPC") 'boon-completer-space)
|
||||
(define-key ivy-minibuffer-map (kbd "DEL") 'ivy-backward-delete-char)
|
||||
(define-key ivy-minibuffer-map (kbd "C-w") 'ivy-backward-kill-word)
|
||||
(define-key ivy-minibuffer-map (kbd "C-d") 'ivy-delete-char)
|
||||
(define-key ivy-minibuffer-map (kbd "C-f") 'ivy-forward-char)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M-<") 'ivy-beginning-of-buffer)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M->") 'ivy-end-of-buffer)
|
||||
(define-key ivy-minibuffer-map (kbd "C-.") 'ivy-next-history-element)
|
||||
(define-key ivy-minibuffer-map (kbd "C-,") 'ivy-previous-history-element)
|
||||
(define-key ivy-minibuffer-map (kbd "<escape>") 'minibuffer-keyboard-quit)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-v") 'ivy-scroll-up-command)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M-v") 'ivy-scroll-down-command)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-n") 'ivy-next-line-and-call)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-p") 'ivy-previous-line-and-call)
|
||||
(define-key ivy-minibuffer-map (kbd "C-q") 'ivy-toggle-regexp-quote)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M-j") 'ivy-yank-word)
|
||||
(define-key ivy-minibuffer-map (kbd "C-v") 'ivy-insert-current)
|
||||
(define-key ivy-minibuffer-map (kbd "TAB") 'ivy-partial) ;; for counsel-find-file
|
||||
(define-key ivy-minibuffer-map (kbd "C-TAB") 'ivy-dispatching-call)
|
||||
(define-key ivy-minibuffer-map (kbd "C-k") 'ivy-kill-line)
|
||||
(define-key ivy-minibuffer-map (kbd "S-SPC") 'ivy-restrict-to-matches)
|
||||
(define-key ivy-minibuffer-map (kbd "C-t") 'ivy-kill-ring-save)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-h") 'ivy-avy)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-a") 'ivy-read-action)
|
||||
(define-key ivy-minibuffer-map (kbd "C-o") 'ivy-occur)
|
||||
)
|
||||
)
|
||||
(with-eval-after-load 'ivy
|
||||
(define-key ivy-minibuffer-map (kbd "RET") 'ivy-done)
|
||||
(define-key ivy-minibuffer-map (kbd "<C-return>") 'ivy-call)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-j") 'ivy-alt-done)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-j") 'ivy-immediate-done)
|
||||
(define-key ivy-minibuffer-map (kbd "C-n") 'ivy-partial)
|
||||
(define-key ivy-minibuffer-map (kbd "C-y") 'ivy-next-line)
|
||||
(define-key ivy-minibuffer-map (kbd "C-u") 'ivy-previous-line)
|
||||
(define-key ivy-minibuffer-map (kbd "<down>") 'ivy-next-line)
|
||||
(define-key ivy-minibuffer-map (kbd "<up>") 'ivy-previous-line)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-s") 'ivy-next-line-or-history)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-r") 'ivy-reverse-i-search)
|
||||
(define-key ivy-minibuffer-map (kbd "SPC") 'boon-completer-space)
|
||||
(define-key ivy-minibuffer-map (kbd "DEL") 'ivy-backward-delete-char)
|
||||
(define-key ivy-minibuffer-map (kbd "C-w") 'ivy-backward-kill-word)
|
||||
(define-key ivy-minibuffer-map (kbd "C-d") 'ivy-delete-char)
|
||||
(define-key ivy-minibuffer-map (kbd "C-f") 'ivy-forward-char)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M-<") 'ivy-beginning-of-buffer)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M->") 'ivy-end-of-buffer)
|
||||
(define-key ivy-minibuffer-map (kbd "C-.") 'ivy-next-history-element)
|
||||
(define-key ivy-minibuffer-map (kbd "C-,") 'ivy-previous-history-element)
|
||||
(define-key ivy-minibuffer-map (kbd "<escape>") 'minibuffer-keyboard-quit)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-v") 'ivy-scroll-up-command)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M-v") 'ivy-scroll-down-command)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-n") 'ivy-next-line-and-call)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-p") 'ivy-previous-line-and-call)
|
||||
(define-key ivy-minibuffer-map (kbd "C-q") 'ivy-toggle-regexp-quote)
|
||||
;; (define-key ivy-minibuffer-map (kbd "M-j") 'ivy-yank-word)
|
||||
(define-key ivy-minibuffer-map (kbd "C-v") 'ivy-insert-current)
|
||||
(define-key ivy-minibuffer-map (kbd "TAB") 'ivy-partial) ;; for counsel-find-file
|
||||
(define-key ivy-minibuffer-map (kbd "C-TAB") 'ivy-dispatching-call)
|
||||
(define-key ivy-minibuffer-map (kbd "C-k") 'ivy-kill-line)
|
||||
(define-key ivy-minibuffer-map (kbd "S-SPC") 'ivy-restrict-to-matches)
|
||||
(define-key ivy-minibuffer-map (kbd "C-t") 'ivy-kill-ring-save)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-h") 'ivy-avy)
|
||||
;; (define-key ivy-minibuffer-map (kbd "C-M-a") 'ivy-read-action)
|
||||
(define-key ivy-minibuffer-map (kbd "C-o") 'ivy-occur)
|
||||
)
|
||||
|
||||
(with-eval-after-load 'helm
|
||||
(define-helm-key (kbd "u") 'helm-previous-line)
|
||||
|
|
|
@ -8,39 +8,6 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'boon-core)
|
||||
(require 'boon-main)
|
||||
|
||||
(defun boon-adjust-indent ()
|
||||
"Adjust indentation of the region or current line."
|
||||
(interactive)
|
||||
(unless (use-region-p)
|
||||
(set-mark (line-beginning-position))
|
||||
(end-of-line))
|
||||
(call-interactively 'indent-rigidly))
|
||||
|
||||
(defun boon-query-replace ()
|
||||
"Query replace; but if the region is active, replace its contents"
|
||||
(interactive)
|
||||
(if (and (use-region-p) (eq (- (line-number-at-pos (region-end)) (line-number-at-pos (region-beginning))) 0))
|
||||
(let ((selection (buffer-substring-no-properties (region-beginning) (region-end))))
|
||||
(perform-replace
|
||||
selection
|
||||
(read-string "Replace region with:")
|
||||
t ; query
|
||||
nil ; not a regexp
|
||||
nil ; not delimited
|
||||
nil ; no specific repeat count
|
||||
nil ; default keymap
|
||||
(point-min-marker)
|
||||
(point-max-marker) ; replace in the whole buffer
|
||||
))
|
||||
(call-interactively 'query-replace)))
|
||||
|
||||
(defun boon-toggle-comment (regs)
|
||||
"Toggle comments in the regions REGS."
|
||||
(interactive (list (boon-spec-region "toggle comment")))
|
||||
(dolist (reg regs)
|
||||
(comment-or-uncomment-region (boon-reg-begin reg)(boon-reg-end reg))))
|
||||
|
||||
(define-key boon-x-map "rr" 'boon-query-replace) ; replace the region if it is selected
|
||||
(define-key boon-x-map "t" 'boon-toggle-comment) ; commenT
|
||||
|
@ -64,9 +31,8 @@
|
|||
(define-key boon-x-map "vv" 'magit-status)
|
||||
(define-key boon-x-map "x" 'helm-M-x)
|
||||
|
||||
(eval-after-load 'flycheck
|
||||
'(define-key boon-x-map "y" flycheck-command-map)
|
||||
)
|
||||
(with-eval-after-load 'flycheck
|
||||
(define-key boon-x-map "y" flycheck-command-map))
|
||||
|
||||
|
||||
(provide 'boon-extras)
|
||||
|
|
29
boon-keys.el
29
boon-keys.el
|
@ -106,5 +106,34 @@
|
|||
(define-key boon-goto-map "t" 'helm-etags-select)
|
||||
(define-key boon-goto-map "y" 'helm-flycheck)
|
||||
|
||||
(defun boon-god-control-swap (event)
|
||||
"Swap the control 'bit' in EVENT, if that is a good choice."
|
||||
(interactive (list (read-key)))
|
||||
(cond
|
||||
((memq event '(9 13)) event)
|
||||
((<= event 27) (+ 96 event))
|
||||
((not (eq 0 (logand (lsh 1 26) event))) (logxor (lsh 1 26) event))
|
||||
(t (list 'control event))))
|
||||
|
||||
(defun boon-c-god ()
|
||||
"Input a key sequence, prepend C- to each key, and run the command bound to that sequence."
|
||||
(interactive)
|
||||
(let ((keys '((control c)))
|
||||
(binding (key-binding (kbd "C-c")))
|
||||
(key-vector (kbd "C-c"))
|
||||
(prompt "C-c-"))
|
||||
(while (and binding (not (symbolp binding)))
|
||||
(let ((key (read-key (format "%s" prompt))))
|
||||
(if (eq key ?h) (describe-bindings key-vector)
|
||||
(push (boon-god-control-swap key) keys)
|
||||
(setq key-vector (vconcat (reverse keys)))
|
||||
(setq prompt (key-description key-vector))
|
||||
(setq binding (key-binding key-vector)))))
|
||||
(setq this-command-keys key-vector)
|
||||
(cond
|
||||
((not binding) (error "No command bound to %s" prompt))
|
||||
((commandp binding) (call-interactively binding))
|
||||
(t (error "Key not bound to a command: %s" binding)))))
|
||||
|
||||
(provide 'boon-keys)
|
||||
;;; boon-keys.el ends here
|
||||
|
|
447
boon-main.el
447
boon-main.el
|
@ -2,74 +2,19 @@
|
|||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file contains (most of) the boon commands. These commands are
|
||||
;; typically bound to a key in boon-keys or boon-colemak.
|
||||
;; This file contains boon actions (modification of text). These
|
||||
;; commands are typically bound to a key in boon-command-map. They
|
||||
;; can be bound to any desired key though (in global-map as well).
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'boon-core)
|
||||
(require 'boon-utils)
|
||||
(require 'boon-arguments)
|
||||
|
||||
(require 'er-basic-expansions)
|
||||
(require 'multiple-cursors)
|
||||
(require 'subr-x)
|
||||
(require 'dash)
|
||||
|
||||
;;; Jumping to definitions (at point):
|
||||
|
||||
(defun boon-find-elisp-thing-at-point ()
|
||||
"Find an elisp thing at point.
|
||||
Search preferentially for a function, then a variable."
|
||||
(interactive)
|
||||
(let ((symb (symbol-at-point)))
|
||||
(cond
|
||||
((fboundp symb) (find-function-do-it symb nil 'switch-to-buffer))
|
||||
((boundp symb) (find-function-do-it symb 'defvar 'switch-to-buffer))
|
||||
(t (call-interactively 'helm-apropos)))))
|
||||
|
||||
(defun boon-find-tag-at-point ()
|
||||
"Find the symbol at point in the current tags table."
|
||||
(interactive)
|
||||
(let ((symb (thing-at-point 'symbol)))
|
||||
(cond (symb
|
||||
(find-tag symb (when (and current-prefix-arg (bound-and-true-p last-tag))
|
||||
(if (< (prefix-numeric-value current-prefix-arg) 0)
|
||||
'-
|
||||
t))))
|
||||
(t (call-interactively 'find-tag)))))
|
||||
|
||||
(defcustom boon-find-definition-dispatch '()
|
||||
"An alist mapping major modes to finding the symbol at point."
|
||||
:group 'boon
|
||||
:type '(alist :key-type symbol :value-type function))
|
||||
(setq boon-find-definition-dispatch
|
||||
'((c-mode . boon-find-tag-at-point)
|
||||
(emacs-lisp-mode . boon-find-elisp-thing-at-point)
|
||||
(lisp-interaction-mode . boon-find-elisp-thing-at-point)
|
||||
(haskell-mode . (lambda () (interactive) (if intero-mode (intero-goto-definition) (haskell-mode-jump-to-def-or-tag))))))
|
||||
|
||||
(defun boon-find-definition ()
|
||||
"Find a definition, in a way which is adapted to the 'major-mode'.
|
||||
If possible, prompt the symbol at point."
|
||||
(interactive)
|
||||
;; TODO (ring-insert find-tag-marker-ring (point-marker))
|
||||
(let ((mode-fap (assoc major-mode boon-find-definition-dispatch)))
|
||||
(if mode-fap (call-interactively (cdr mode-fap))
|
||||
(error "Finding definitions is not defined for %s. Update the variable 'boon-find-definition-dispatch'."
|
||||
major-mode))))
|
||||
|
||||
(defcustom boon-hints-enabled 't "Display hints." :group 'boon)
|
||||
|
||||
(defun boon-hint (msg)
|
||||
"Provide MSG as a hint."
|
||||
(when boon-hints-enabled
|
||||
(message msg)))
|
||||
|
||||
(defmacro boon-with-ordered-region (body)
|
||||
"Run the BODY, ensuring that the point is before the mark."
|
||||
`(if (< (point) (mark))
|
||||
,body
|
||||
(progn (exchange-point-and-mark) ,body (exchange-point-and-mark))))
|
||||
|
||||
(defun boon-drop-or-extend-mark ()
|
||||
"Drop a mark; or extend the region to the next full line; or revert to original state."
|
||||
|
@ -79,12 +24,12 @@ If possible, prompt the symbol at point."
|
|||
(if (and (bolp)
|
||||
(save-excursion (goto-char (mark)) (bolp))
|
||||
(not (eq (point) (mark))))
|
||||
(progn ;; here we have a number of full lines selected, and that number is more than 0
|
||||
(progn ;; here we have a number of full lines selected, and that number is more than 0
|
||||
(pop-mark) ;; load the saved position into the mark
|
||||
(goto-char (mark));; jump there
|
||||
(deactivate-mark))
|
||||
(boon-with-ordered-region
|
||||
(progn ;; here we have at least one non-full line selected. Extend to the full lines.
|
||||
(progn ;; here we have at least one non-full line selected. Extend to the full lines.
|
||||
(beginning-of-line)
|
||||
(exchange-point-and-mark)
|
||||
(end-of-line)
|
||||
|
@ -106,12 +51,6 @@ If possible, prompt the symbol at point."
|
|||
(if mark-active (boon-deactivate-mark)
|
||||
(call-interactively 'boon-mark-region)))
|
||||
|
||||
(defun boon-current-line-indentation ()
|
||||
"Return the indentation of the curent line."
|
||||
(save-excursion
|
||||
(back-to-indentation)
|
||||
(current-column)))
|
||||
|
||||
(defun boon-enclose (enclosure regs)
|
||||
"Wrap with the given ENCLOSURE the regions given as REGS."
|
||||
(interactive (list (boon-spec-enclosure) (boon-spec-region "enclose")))
|
||||
|
@ -123,43 +62,6 @@ If possible, prompt the symbol at point."
|
|||
(goto-char (boon-reg-begin reg))
|
||||
(insert (car enclosure)))))
|
||||
|
||||
(defun boon-find-char-backward (char)
|
||||
"Move the cursor backwards, until finding an occurence of the character CHAR."
|
||||
(interactive "cType the character to find")
|
||||
(search-backward (make-string 1 char))
|
||||
(forward-char 1))
|
||||
|
||||
(defun boon-find-char-forward (char)
|
||||
"Find the given character (as CHAR), forwards."
|
||||
(interactive "cType the character to find")
|
||||
(search-forward (make-string 1 char))
|
||||
(backward-char 1))
|
||||
|
||||
(defun boon-edge-of-expression (forward)
|
||||
"Jump to the forward or backward (as FORWARD) limit of the current expression."
|
||||
(interactive "P")
|
||||
(let ((orig-point (point)))
|
||||
(goto-char
|
||||
(save-excursion
|
||||
(deactivate-mark)
|
||||
(if (boon-in-string-p)
|
||||
(er/mark-inside-quotes) (er/mark-inside-pairs))
|
||||
(when forward (exchange-point-and-mark))
|
||||
(point)))
|
||||
;; make sure we make some progress
|
||||
(when (eq (point) orig-point)
|
||||
(forward-char (if forward 1 -1)))))
|
||||
|
||||
(defun boon-end-of-expression ()
|
||||
"Jump to the end of the current expression."
|
||||
(interactive)
|
||||
(boon-edge-of-expression 't))
|
||||
|
||||
(defun boon-beginning-of-expression ()
|
||||
"Jump to the beginning of the current expression."
|
||||
(interactive)
|
||||
(boon-edge-of-expression nil))
|
||||
|
||||
(defun boon-delete-region ()
|
||||
"Delete the region if it is active."
|
||||
(when (use-region-p)
|
||||
|
@ -221,176 +123,6 @@ Return nil if no changes are made."
|
|||
;; done this way because 'or' is lazy
|
||||
(or fix-here fix-there)))
|
||||
|
||||
(defun boon-line-prefix ()
|
||||
"Return the text between beginning of line and point."
|
||||
(buffer-substring-no-properties
|
||||
(line-beginning-position)
|
||||
(point)))
|
||||
|
||||
(defun boon-line-suffix ()
|
||||
"Return the text between end of line and point."
|
||||
(buffer-substring-no-properties
|
||||
(line-end-position)
|
||||
(point)))
|
||||
|
||||
(defun boon-at-indent-or-more-p ()
|
||||
"Return non-nil if the point is at the current line indentation; or to the right."
|
||||
(or (eolp)
|
||||
(and (not (boon-at-indent-p))
|
||||
(string-blank-p (boon-line-prefix)))))
|
||||
|
||||
(defun boon-at-indent-p ()
|
||||
"Return non-nil if the point is at the current line indentation."
|
||||
(eq (save-excursion (back-to-indentation) (point)) (point)))
|
||||
|
||||
(defun boon-smarter-upward (count)
|
||||
"Move upward, to a line with the same level of indentation, or less, COUNT times."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(previous-logical-line)
|
||||
(while (boon-at-indent-or-more-p) (previous-logical-line)))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun boon-smarter-downward (count)
|
||||
"Move downward, to a line with the same level of indentation, or less COUNT times."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(next-logical-line)
|
||||
(while (boon-at-indent-or-more-p) (next-logical-line)))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun boon-smarter-backward (count)
|
||||
"Move backward, over COUNT whole syntactic units."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(boon-jump-over-blanks-backward)
|
||||
(cond
|
||||
((boon-looking-at-comment -1)
|
||||
(forward-comment -1))
|
||||
((looking-back "\\s\"")
|
||||
(backward-char)
|
||||
(er--move-point-backward-out-of-string))
|
||||
((looking-back "\\s)")
|
||||
(backward-list))
|
||||
((looking-back "\\s_") ;; symbol
|
||||
(skip-syntax-backward "_"))
|
||||
((looking-back "\\s(")
|
||||
(backward-char))
|
||||
((looking-back "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-backward "!"))
|
||||
((looking-back "\\sw")
|
||||
(if (not (looking-at "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-backward "w")
|
||||
(skip-syntax-backward "w_")))
|
||||
(t
|
||||
(backward-char)))))
|
||||
|
||||
(defun boon-smarter-forward (count)
|
||||
"Move forward, over COUNT whole syntactic unit."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(boon-jump-over-blanks-forward)
|
||||
(cond
|
||||
((boon-looking-at-line-comment-start-p)
|
||||
(end-of-line)
|
||||
(boon-jump-over-blanks-forward))
|
||||
((boon-looking-at-comment 1);;
|
||||
(forward-comment 1))
|
||||
((looking-at "\\s\"")
|
||||
(forward-char)
|
||||
(er--move-point-forward-out-of-string))
|
||||
((looking-at "\\s(")
|
||||
(forward-list))
|
||||
((looking-at "\\s_") ;; symbol
|
||||
(skip-syntax-forward "_"))
|
||||
((looking-at "\\s)")
|
||||
(forward-char))
|
||||
((looking-at "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-forward "!"))
|
||||
((looking-at "\\sw")
|
||||
(if (not (looking-back "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-forward "w")
|
||||
(skip-syntax-forward "w_")))
|
||||
(t
|
||||
(forward-char)))))
|
||||
|
||||
(defun boon-smarter-forward-spaces (count)
|
||||
"Move forward, over COUNT whole syntactic unit.
|
||||
Handle spaces cleverly."
|
||||
(interactive "p")
|
||||
(declare (obsolete "does not seem very useful" "20151120"))
|
||||
(dotimes (_number count)
|
||||
(let ((spaces-skipped (not (equal (boon-jump-over-blanks-forward) 0)))
|
||||
(in-middle nil)
|
||||
(at-bol (string-blank-p (boon-line-prefix))))
|
||||
(cond
|
||||
((boon-looking-at-line-comment-start-p)
|
||||
(end-of-line)
|
||||
(forward-char))
|
||||
((boon-looking-at-comment 1);;
|
||||
(forward-comment 1))
|
||||
((looking-at "\\s\"")
|
||||
(forward-char)
|
||||
(er--move-point-forward-out-of-string))
|
||||
((looking-at "\\s(")
|
||||
(forward-list))
|
||||
((looking-at "\\s_") ;; symbol
|
||||
(skip-syntax-forward "_"))
|
||||
((looking-at "\\s)")
|
||||
(forward-char)
|
||||
(setq in-middle 't))
|
||||
((looking-at "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-forward "!"))
|
||||
((looking-at "\\sw")
|
||||
(setq in-middle 't)
|
||||
(if (not (looking-back "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-forward "w")
|
||||
(skip-syntax-forward "w_")))
|
||||
(t
|
||||
(forward-char)
|
||||
(setq in-middle 't)))
|
||||
(unless (or spaces-skipped in-middle)
|
||||
(if at-bol
|
||||
(skip-chars-forward "\t\n ")
|
||||
(skip-chars-forward "\t "))))))
|
||||
|
||||
(defun boon-smarter-backward-spaces (count)
|
||||
"Move backward, over COUNT whole syntactic unit.
|
||||
Handles spaces smartly."
|
||||
(interactive "p")
|
||||
(declare (obsolete "does not seem very useful" "20151120"))
|
||||
(dotimes (_number count)
|
||||
(let ((spaces-skipped (not (equal (boon-jump-over-blanks-backward) 0)))
|
||||
(in-middle nil)
|
||||
(at-eol (string-blank-p (boon-line-suffix))))
|
||||
(cond
|
||||
((boon-looking-at-comment -1)
|
||||
(forward-comment -1))
|
||||
((looking-back "\\s\"")
|
||||
(backward-char)
|
||||
(er--move-point-backward-out-of-string))
|
||||
((looking-back "\\s)")
|
||||
(backward-list))
|
||||
((looking-back "\\s_") ;; symbol
|
||||
(skip-syntax-backward "_"))
|
||||
((looking-back "\\s(")
|
||||
(backward-char)
|
||||
(setq in-middle 't))
|
||||
((looking-back "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-backward "!"))
|
||||
((looking-back "\\sw")
|
||||
(setq in-middle 't)
|
||||
(if (not (looking-at "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-backward "w")
|
||||
(skip-syntax-backward "w_")))
|
||||
(t
|
||||
(backward-char)
|
||||
(setq in-middle 't)))
|
||||
(unless (or spaces-skipped in-middle)
|
||||
(if at-eol
|
||||
(skip-chars-backward "\t\n ")
|
||||
(skip-chars-backward "\t "))))))
|
||||
|
||||
(defun boon-toggle-character-case ()
|
||||
"Toggle the case of the character at point."
|
||||
(interactive)
|
||||
|
@ -440,68 +172,10 @@ NOTE: Do not run for every cursor."
|
|||
(message "mark placed at point"))
|
||||
(activate-mark)))
|
||||
|
||||
(defun boon-visible-beginning-of-line ()
|
||||
"Move point leftwards to the first visible beginning of line."
|
||||
(interactive)
|
||||
(beginning-of-line)
|
||||
(while (bound-and-true-p outline-invisible-p)
|
||||
(backward-char 1)
|
||||
(beginning-of-line 1)))
|
||||
|
||||
(defun boon-beginning-of-line ()
|
||||
"Move point to the first non-whitespace character on this line.
|
||||
If point was already at that position, move point to beginning of
|
||||
line."
|
||||
(interactive)
|
||||
(let ((oldpos (point)))
|
||||
(back-to-indentation)
|
||||
(when (or (and (fboundp 'outline-invisible-p)
|
||||
(outline-invisible-p))
|
||||
(= oldpos (point)))
|
||||
(boon-visible-beginning-of-line))))
|
||||
|
||||
(defun boon-looking-at-comment (how-many)
|
||||
"Is the current point looking at HOW-MANY comments? (negative for backwards)?"
|
||||
(save-excursion
|
||||
(forward-comment how-many)))
|
||||
|
||||
(defun boon-in-string-p ()
|
||||
"Determine if the point is inside a string."
|
||||
(nth 3 (syntax-ppss)))
|
||||
|
||||
(defun boon-looking-at-line-comment-start-p ()
|
||||
"Are we looking at a comment-start?"
|
||||
(interactive)
|
||||
(and (bound-and-true-p comment-start)
|
||||
(looking-at comment-start)
|
||||
(not (boon-in-string-p))))
|
||||
|
||||
(defun boon-end-of-line ()
|
||||
"Intelligently jump to the end of line.
|
||||
This function toggles between jumping to 1. the last character of code on the
|
||||
line 2. the last non-blank char on the line 3. the true end of
|
||||
line."
|
||||
(interactive)
|
||||
(let* ((orig (point))
|
||||
(orig-eol (eolp))
|
||||
(progress (lambda () (and (not (bolp)) (or orig-eol (> (point) orig))))))
|
||||
(beginning-of-line)
|
||||
(while (not (or (boon-looking-at-line-comment-start-p) (eolp)))
|
||||
(forward-char))
|
||||
;; we're now at the last non-comment character of the line
|
||||
(skip-chars-backward "\n\t " (line-beginning-position))
|
||||
;; we're now at the last non-blank, non-comment character of the line
|
||||
(unless (funcall progress)
|
||||
(end-of-line)
|
||||
(skip-chars-backward "\n\t " (line-beginning-position))
|
||||
;; we're now at the last non-blank character of the line
|
||||
(unless (funcall progress)
|
||||
(end-of-line)))))
|
||||
|
||||
(defun boon-open-line-and-insert ()
|
||||
"Open a new line, indented as much as the current one, and switch to insert mode."
|
||||
(interactive)
|
||||
(let ((indent-lvl (boon-current-line-indentation)))
|
||||
(let ((indent-lvl (boon-current-line-indentation)))
|
||||
(beginning-of-line)
|
||||
(open-line 1)
|
||||
(insert (make-string indent-lvl 32))
|
||||
|
@ -526,24 +200,6 @@ line."
|
|||
(forward-char 1)
|
||||
(insert line-prefix))))))
|
||||
|
||||
(defun boon-switch-mark ()
|
||||
"If mark active, switch point and mark, otherwise pop mark from mark ring."
|
||||
(interactive)
|
||||
(if mark-active
|
||||
(exchange-point-and-mark)
|
||||
(if (mark)
|
||||
(progn
|
||||
(goto-char (mark))
|
||||
(pop-mark)))))
|
||||
|
||||
(defun boon-switch-mark-quick ()
|
||||
"Pop the mark ring until we find ourselves on a different line."
|
||||
(interactive)
|
||||
(let ((orig-line (line-number-at-pos)))
|
||||
(while (> 1 (abs (- orig-line (line-number-at-pos))))
|
||||
(goto-char (mark))
|
||||
(pop-mark))))
|
||||
|
||||
(defun boon-split-line ()
|
||||
"Split the current line."
|
||||
(interactive)
|
||||
|
@ -585,19 +241,8 @@ If there is more than one, use mc/create-fake-cursor-at-point."
|
|||
(goto-char (boon-reg-point reg))) regs)
|
||||
(activate-mark))
|
||||
|
||||
(defun boon-end-of-region (regs)
|
||||
"Move the point the end region REGS."
|
||||
(interactive (list (boon-spec-region "go to end")))
|
||||
(dolist (reg regs)
|
||||
(goto-char (boon-reg-end reg))))
|
||||
|
||||
(defun boon-beginning-of-region (regs)
|
||||
"Move the point to the beginning region REGS."
|
||||
(interactive (list (boon-spec-region "go to beginning")))
|
||||
(dolist (reg regs)
|
||||
(goto-char (boon-reg-begin reg))))
|
||||
|
||||
(defun boon-execute-for-cursor (cursor fun)
|
||||
"In the context of the fake CURSOR, run FUN."
|
||||
(if cursor
|
||||
(mc/save-excursion
|
||||
(mc/save-window-scroll
|
||||
|
@ -616,7 +261,7 @@ If there is more than one, use mc/create-fake-cursor-at-point."
|
|||
;; We can't run 'kill-region' on markers. Indeed, using
|
||||
;; markers messes the logic used in kill-region to
|
||||
;; determine whether to prepend or append the thing
|
||||
;; just killed to the top of the kill ring.
|
||||
;; just killed to the top of the kill ring.
|
||||
(kill-region (boon-reg-mark reg) (boon-reg-point reg)))))))
|
||||
|
||||
(defun boon-treasure-region (regs)
|
||||
|
@ -683,44 +328,8 @@ NOTE: do not run for every cursor."
|
|||
(t
|
||||
(keyboard-quit))))
|
||||
|
||||
(defun boon-stuff-at-point ()
|
||||
"Return a meaningful piece of text around at point.
|
||||
If no such text exists, throw an error."
|
||||
(interactive)
|
||||
(if (use-region-p)
|
||||
(buffer-substring-no-properties (region-beginning) (region-end))
|
||||
(or (thing-at-point 'symbol)
|
||||
(error "Nothing relevant at point; move to a symbol or select a region"))))
|
||||
|
||||
;; TODO: remove
|
||||
(require 'skeleton)
|
||||
(setq skeleton-pair t)
|
||||
|
||||
(defun boon-empty-pair-p ()
|
||||
"Is the point at the middle of an empty pair of matched parens?"
|
||||
(interactive)
|
||||
(declare (obsolete "emacs 24.5 electric pair mode is good enough" "20150527"))
|
||||
(eq (caddr
|
||||
(assq (preceding-char)
|
||||
(or skeleton-pair-alist skeleton-pair-default-alist)))
|
||||
(following-char)))
|
||||
|
||||
(defun boon-empty-quotes-p ()
|
||||
"Is the point in the middle of an empty pair of quotes?"
|
||||
(interactive)
|
||||
(declare (obsolete "emacs 24.5 electric pair mode is good enough" "20150527"))
|
||||
(and (eq (preceding-char) (following-char))
|
||||
(member (following-char) '(?\" ?\'))))
|
||||
|
||||
(defun boon-smart-insert-backspace2 ()
|
||||
(interactive)
|
||||
(declare (obsolete "emacs 24.5 electric pair mode is good enough" "20150527"))
|
||||
(when (or (boon-empty-pair-p) (boon-empty-quotes-p))
|
||||
(delete-char 1))
|
||||
(backward-delete-char-untabify 1))
|
||||
|
||||
(defun boon-god-control-swap (event)
|
||||
"Swap the control 'bit' in an event, for event where it makes sense."
|
||||
"Swap the control 'bit' in EVENT, if that is a good choice."
|
||||
(interactive (list (read-key)))
|
||||
(cond
|
||||
((memq event '(9 13)) event)
|
||||
|
@ -729,7 +338,7 @@ If no such text exists, throw an error."
|
|||
(t (list 'control event))))
|
||||
|
||||
(defun boon-c-god ()
|
||||
"Handle C key"
|
||||
"Input a key sequence, prepend C- to each key, and run the command bound to that sequence."
|
||||
(interactive)
|
||||
(let ((keys '((control c)))
|
||||
(binding (key-binding (kbd "C-c")))
|
||||
|
@ -746,7 +355,39 @@ If no such text exists, throw an error."
|
|||
(cond
|
||||
((not binding) (error "No command bound to %s" prompt))
|
||||
((commandp binding) (call-interactively binding))
|
||||
(t (error "key not bound to a command: %s" binding)))))
|
||||
(t (error "Key not bound to a command: %s" binding)))))
|
||||
|
||||
(defun boon-adjust-indent ()
|
||||
"Adjust indentation of the region or current line."
|
||||
(interactive)
|
||||
(unless (use-region-p)
|
||||
(set-mark (line-beginning-position))
|
||||
(end-of-line))
|
||||
(call-interactively 'indent-rigidly))
|
||||
|
||||
(defun boon-query-replace ()
|
||||
"Query replace; but if the region is active, replace its contents."
|
||||
(interactive)
|
||||
(if (and (use-region-p) (eq (- (line-number-at-pos (region-end)) (line-number-at-pos (region-beginning))) 0))
|
||||
(let ((selection (buffer-substring-no-properties (region-beginning) (region-end))))
|
||||
(perform-replace
|
||||
selection
|
||||
(read-string "Replace region with:")
|
||||
t ; query
|
||||
nil ; not a regexp
|
||||
nil ; not delimited
|
||||
nil ; no specific repeat count
|
||||
nil ; default keymap
|
||||
(point-min-marker)
|
||||
(point-max-marker) ; replace in the whole buffer
|
||||
))
|
||||
(call-interactively 'query-replace)))
|
||||
|
||||
(defun boon-toggle-comment (regs)
|
||||
"Toggle comments in the regions REGS."
|
||||
(interactive (list (boon-spec-region "toggle comment")))
|
||||
(dolist (reg regs)
|
||||
(comment-or-uncomment-region (boon-reg-begin reg)(boon-reg-end reg))))
|
||||
|
||||
(provide 'boon-main)
|
||||
;;; boon-main.el ends here
|
||||
|
|
309
boon-moves.el
Normal file
309
boon-moves.el
Normal file
|
@ -0,0 +1,309 @@
|
|||
;;; boon-moves.el --- An Ergonomic Command Mode -*- lexical-binding: t -*-
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file contains boon moves (jumping around somewhere). These
|
||||
;; commands are typically bound to a key in boon-moves-map. They
|
||||
;; can be bound to any desired key though (in global-map as well).
|
||||
|
||||
;;; Code:
|
||||
(require 'boon-core)
|
||||
(require 'boon-utils)
|
||||
(require 'er-basic-expansions)
|
||||
(require 'find-func)
|
||||
(require 'boon-utils)
|
||||
|
||||
|
||||
;;; Jumping to definitions (at point):
|
||||
|
||||
(defun boon-find-elisp-thing-at-point ()
|
||||
"Find an elisp thing at point.
|
||||
Search preferentially for a function, then a variable."
|
||||
(interactive)
|
||||
(let ((symb (symbol-at-point)))
|
||||
(cond
|
||||
((fboundp symb) (find-function-do-it symb nil 'switch-to-buffer))
|
||||
((boundp symb) (find-function-do-it symb 'defvar 'switch-to-buffer))
|
||||
(t (call-interactively 'helm-apropos)))))
|
||||
|
||||
(defun boon-find-tag-at-point ()
|
||||
"Find the symbol at point in the current tags table."
|
||||
(interactive)
|
||||
(let ((symb (thing-at-point 'symbol)))
|
||||
(cond (symb
|
||||
(find-tag symb (when (and current-prefix-arg (bound-and-true-p last-tag))
|
||||
(if (< (prefix-numeric-value current-prefix-arg) 0)
|
||||
'-
|
||||
t))))
|
||||
(t (call-interactively 'find-tag)))))
|
||||
|
||||
(defcustom boon-find-definition-dispatch '()
|
||||
"An alist mapping major modes to finding the symbol at point."
|
||||
:group 'boon
|
||||
:type '(alist :key-type symbol :value-type function))
|
||||
(setq boon-find-definition-dispatch
|
||||
'((c-mode . boon-find-tag-at-point)
|
||||
(emacs-lisp-mode . boon-find-elisp-thing-at-point)
|
||||
(lisp-interaction-mode . boon-find-elisp-thing-at-point)
|
||||
(haskell-mode . (lambda () (interactive) (if intero-mode (intero-goto-definition) (haskell-mode-jump-to-def-or-tag))))))
|
||||
|
||||
(defun boon-find-definition ()
|
||||
"Find a definition, in a way which is adapted to the 'major-mode'.
|
||||
If possible, prompt the symbol at point."
|
||||
(interactive)
|
||||
;; TODO (ring-insert find-tag-marker-ring (point-marker))
|
||||
(let ((mode-fap (assoc major-mode boon-find-definition-dispatch)))
|
||||
(if mode-fap (call-interactively (cdr mode-fap))
|
||||
(error "Finding definitions is not defined for %s. Update the variable 'boon-find-definition-dispatch'"
|
||||
major-mode))))
|
||||
|
||||
(defun boon-find-char-backward (char)
|
||||
"Move the cursor backwards, until finding an occurence of the character CHAR."
|
||||
(interactive "cType the character to find")
|
||||
(search-backward (make-string 1 char))
|
||||
(forward-char 1))
|
||||
|
||||
(defun boon-find-char-forward (char)
|
||||
"Find the given character (as CHAR), forwards."
|
||||
(interactive "cType the character to find")
|
||||
(search-forward (make-string 1 char))
|
||||
(backward-char 1))
|
||||
|
||||
(defun boon-edge-of-expression (forward)
|
||||
"Jump to the forward or backward (as FORWARD) limit of the current expression."
|
||||
(interactive "P")
|
||||
(let ((orig-point (point)))
|
||||
(goto-char
|
||||
(save-excursion
|
||||
(deactivate-mark)
|
||||
(if (boon-in-string-p)
|
||||
(er/mark-inside-quotes) (er/mark-inside-pairs))
|
||||
(when forward (exchange-point-and-mark))
|
||||
(point)))
|
||||
;; make sure we make some progress
|
||||
(when (eq (point) orig-point)
|
||||
(forward-char (if forward 1 -1)))))
|
||||
|
||||
(defun boon-end-of-expression ()
|
||||
"Jump to the end of the current expression."
|
||||
(interactive)
|
||||
(boon-edge-of-expression 't))
|
||||
|
||||
(defun boon-beginning-of-expression ()
|
||||
"Jump to the beginning of the current expression."
|
||||
(interactive)
|
||||
(boon-edge-of-expression nil))
|
||||
|
||||
(defun boon-smarter-upward (count)
|
||||
"Move upward, to a line with the same level of indentation, or less, COUNT times."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(previous-logical-line)
|
||||
(while (boon-at-indent-or-more-p) (previous-logical-line)))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun boon-smarter-downward (count)
|
||||
"Move downward, to a line with the same level of indentation, or less COUNT times."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(next-logical-line)
|
||||
(while (boon-at-indent-or-more-p) (next-logical-line)))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun boon-smarter-backward (count)
|
||||
"Move backward, over COUNT whole syntactic units."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(boon-jump-over-blanks-backward)
|
||||
(cond
|
||||
((boon-looking-at-comment -1)
|
||||
(forward-comment -1))
|
||||
((looking-back "\\s\"")
|
||||
(backward-char)
|
||||
(er--move-point-backward-out-of-string))
|
||||
((looking-back "\\s)")
|
||||
(backward-list))
|
||||
((looking-back "\\s_") ;; symbol
|
||||
(skip-syntax-backward "_"))
|
||||
((looking-back "\\s(")
|
||||
(backward-char))
|
||||
((looking-back "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-backward "!"))
|
||||
((looking-back "\\sw")
|
||||
(if (not (looking-at "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-backward "w")
|
||||
(skip-syntax-backward "w_")))
|
||||
(t
|
||||
(backward-char)))))
|
||||
|
||||
(defun boon-smarter-forward (count)
|
||||
"Move forward, over COUNT whole syntactic unit."
|
||||
(interactive "p")
|
||||
(dotimes (_number count)
|
||||
(boon-jump-over-blanks-forward)
|
||||
(cond
|
||||
((boon-looking-at-line-comment-start-p)
|
||||
(end-of-line)
|
||||
(boon-jump-over-blanks-forward))
|
||||
((boon-looking-at-comment 1);;
|
||||
(forward-comment 1))
|
||||
((looking-at "\\s\"")
|
||||
(forward-char)
|
||||
(er--move-point-forward-out-of-string))
|
||||
((looking-at "\\s(")
|
||||
(forward-list))
|
||||
((looking-at "\\s_") ;; symbol
|
||||
(skip-syntax-forward "_"))
|
||||
((looking-at "\\s)")
|
||||
(forward-char))
|
||||
((looking-at "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-forward "!"))
|
||||
((looking-at "\\sw")
|
||||
(if (not (looking-back "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-forward "w")
|
||||
(skip-syntax-forward "w_")))
|
||||
(t
|
||||
(forward-char)))))
|
||||
|
||||
(defun boon-smarter-forward-spaces (count)
|
||||
"Move forward, over COUNT whole syntactic unit.
|
||||
Handle spaces cleverly."
|
||||
(interactive "p")
|
||||
(declare (obsolete "does not seem very useful" "20151120"))
|
||||
(dotimes (_number count)
|
||||
(let ((spaces-skipped (not (equal (boon-jump-over-blanks-forward) 0)))
|
||||
(in-middle nil)
|
||||
(at-bol (string-blank-p (boon-line-prefix))))
|
||||
(cond
|
||||
((boon-looking-at-line-comment-start-p)
|
||||
(end-of-line)
|
||||
(forward-char))
|
||||
((boon-looking-at-comment 1);;
|
||||
(forward-comment 1))
|
||||
((looking-at "\\s\"")
|
||||
(forward-char)
|
||||
(er--move-point-forward-out-of-string))
|
||||
((looking-at "\\s(")
|
||||
(forward-list))
|
||||
((looking-at "\\s_") ;; symbol
|
||||
(skip-syntax-forward "_"))
|
||||
((looking-at "\\s)")
|
||||
(forward-char)
|
||||
(setq in-middle 't))
|
||||
((looking-at "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-forward "!"))
|
||||
((looking-at "\\sw")
|
||||
(setq in-middle 't)
|
||||
(if (not (looking-back "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-forward "w")
|
||||
(skip-syntax-forward "w_")))
|
||||
(t
|
||||
(forward-char)
|
||||
(setq in-middle 't)))
|
||||
(unless (or spaces-skipped in-middle)
|
||||
(if at-bol
|
||||
(skip-chars-forward "\t\n ")
|
||||
(skip-chars-forward "\t "))))))
|
||||
|
||||
(defun boon-smarter-backward-spaces (count)
|
||||
"Move backward, over COUNT whole syntactic unit.
|
||||
Handles spaces smartly."
|
||||
(interactive "p")
|
||||
(declare (obsolete "does not seem very useful" "20151120"))
|
||||
(dotimes (_number count)
|
||||
(let ((spaces-skipped (not (equal (boon-jump-over-blanks-backward) 0)))
|
||||
(in-middle nil)
|
||||
(at-eol (string-blank-p (boon-line-suffix))))
|
||||
(cond
|
||||
((boon-looking-at-comment -1)
|
||||
(forward-comment -1))
|
||||
((looking-back "\\s\"")
|
||||
(backward-char)
|
||||
(er--move-point-backward-out-of-string))
|
||||
((looking-back "\\s)")
|
||||
(backward-list))
|
||||
((looking-back "\\s_") ;; symbol
|
||||
(skip-syntax-backward "_"))
|
||||
((looking-back "\\s(")
|
||||
(backward-char)
|
||||
(setq in-middle 't))
|
||||
((looking-back "\\s!") ;; generic comment delimiter
|
||||
(skip-syntax-backward "!"))
|
||||
((looking-back "\\sw")
|
||||
(setq in-middle 't)
|
||||
(if (not (looking-at "\\(\\s-\\|\\s(\\|\\s)\\)"))
|
||||
(skip-syntax-backward "w")
|
||||
(skip-syntax-backward "w_")))
|
||||
(t
|
||||
(backward-char)
|
||||
(setq in-middle 't)))
|
||||
(unless (or spaces-skipped in-middle)
|
||||
(if at-eol
|
||||
(skip-chars-backward "\t\n ")
|
||||
(skip-chars-backward "\t "))))))
|
||||
|
||||
(defun boon-visible-beginning-of-line ()
|
||||
"Move point leftwards to the first visible beginning of line."
|
||||
(interactive)
|
||||
(beginning-of-line)
|
||||
(while (bound-and-true-p outline-invisible-p)
|
||||
(backward-char 1)
|
||||
(beginning-of-line 1)))
|
||||
|
||||
(defun boon-beginning-of-line ()
|
||||
"Move point to the first non-whitespace character on this line.
|
||||
If point was already at that position, move point to beginning of
|
||||
line."
|
||||
(interactive)
|
||||
(let ((oldpos (point)))
|
||||
(back-to-indentation)
|
||||
(when (or (and (fboundp 'outline-invisible-p)
|
||||
(outline-invisible-p))
|
||||
(= oldpos (point)))
|
||||
(boon-visible-beginning-of-line))))
|
||||
|
||||
(defun boon-end-of-line ()
|
||||
"Intelligently jump to the end of line.
|
||||
This function toggles between jumping to 1. the last character of code on the
|
||||
line 2. the last non-blank char on the line 3. the true end of
|
||||
line."
|
||||
(interactive)
|
||||
(let* ((orig (point))
|
||||
(orig-eol (eolp))
|
||||
(progress (lambda () (and (not (bolp)) (or orig-eol (> (point) orig))))))
|
||||
(beginning-of-line)
|
||||
(while (not (or (boon-looking-at-line-comment-start-p) (eolp)))
|
||||
(forward-char))
|
||||
;; we're now at the last non-comment character of the line
|
||||
(skip-chars-backward "\n\t " (line-beginning-position))
|
||||
;; we're now at the last non-blank, non-comment character of the line
|
||||
(unless (funcall progress)
|
||||
(end-of-line)
|
||||
(skip-chars-backward "\n\t " (line-beginning-position))
|
||||
;; we're now at the last non-blank character of the line
|
||||
(unless (funcall progress)
|
||||
(end-of-line)))))
|
||||
|
||||
|
||||
(defun boon-switch-mark ()
|
||||
"If mark active, switch point and mark, otherwise pop mark from mark ring."
|
||||
(interactive)
|
||||
(if mark-active
|
||||
(exchange-point-and-mark)
|
||||
(if (mark)
|
||||
(progn
|
||||
(goto-char (mark))
|
||||
(pop-mark)))))
|
||||
|
||||
(defun boon-switch-mark-quick ()
|
||||
"Pop the mark ring until we find ourselves on a different line."
|
||||
(interactive)
|
||||
;; obsolete
|
||||
(let ((orig-line (line-number-at-pos)))
|
||||
(while (> 1 (abs (- orig-line (line-number-at-pos))))
|
||||
(goto-char (mark))
|
||||
(pop-mark))))
|
||||
|
||||
(provide 'boon-moves)
|
||||
;;; boon-moves.el ends here
|
||||
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
;;; Commentary:
|
||||
;;; Code:
|
||||
(require 'boon-core)
|
||||
(require 'boon-main)
|
||||
(require 'boon-search)
|
||||
(require 'boon-keys)
|
||||
(require 'boon)
|
||||
|
||||
(define-key boon-select-map "@" 'boon-select-occurences)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'boon-main)
|
||||
(require 'boon-utils)
|
||||
|
||||
(defvar-local boon-regexp nil "Current regexp search. Use boon-set-search-regexp to set this variable.")
|
||||
(defvar-local boon-search-success t "Last search was successful or non-existent.")
|
||||
|
|
94
boon-utils.el
Normal file
94
boon-utils.el
Normal file
|
@ -0,0 +1,94 @@
|
|||
;;; boon-utils.el --- An Ergonomic Command Mode -*- lexical-binding: t -*-
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file contains several utilities, which shoud probably be part
|
||||
;; of Emacs. (Maybe they are and I did not find them.)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'subr-x)
|
||||
|
||||
(defmacro boon-with-ordered-region (body)
|
||||
"Run the BODY, ensuring that the point is before the mark."
|
||||
`(if (< (point) (mark))
|
||||
,body
|
||||
(progn (exchange-point-and-mark) ,body (exchange-point-and-mark))))
|
||||
|
||||
(defcustom boon-hints-enabled 't "Display hints." :group 'boon)
|
||||
|
||||
(defun boon-hint (msg)
|
||||
"Provide MSG as a hint."
|
||||
(when boon-hints-enabled
|
||||
(message msg)))
|
||||
|
||||
(defun boon-current-line-indentation ()
|
||||
"Return the indentation of the curent line."
|
||||
(save-excursion
|
||||
(back-to-indentation)
|
||||
(current-column)))
|
||||
|
||||
|
||||
(defun boon-line-prefix ()
|
||||
"Return the text between beginning of line and point."
|
||||
(buffer-substring-no-properties
|
||||
(line-beginning-position)
|
||||
(point)))
|
||||
|
||||
(defun boon-line-suffix ()
|
||||
"Return the text between end of line and point."
|
||||
(buffer-substring-no-properties
|
||||
(line-end-position)
|
||||
(point)))
|
||||
|
||||
(defun boon-at-indent-or-more-p ()
|
||||
"Return non-nil if the point is at the current line indentation; or to the right."
|
||||
(or (eolp)
|
||||
(and (not (boon-at-indent-p))
|
||||
(string-blank-p (boon-line-prefix)))))
|
||||
|
||||
(defun boon-at-indent-p ()
|
||||
"Return non-nil if the point is at the current line indentation."
|
||||
(eq (save-excursion (back-to-indentation) (point)) (point)))
|
||||
|
||||
(defun boon-looking-at-comment (how-many)
|
||||
"Is the current point looking at HOW-MANY comments? (negative for backwards)?"
|
||||
;; (declare (obsolete "emacs 24.5 electric pair mode is good enough" "20150527"))
|
||||
;; (obsolete) 20160901
|
||||
(save-excursion
|
||||
(forward-comment how-many)))
|
||||
|
||||
(defun boon-in-string-p ()
|
||||
"Determine if the point is inside a string."
|
||||
(nth 3 (syntax-ppss)))
|
||||
|
||||
(defun boon-looking-at-line-comment-start-p ()
|
||||
"Are we looking at a comment-start?"
|
||||
(interactive)
|
||||
(and (bound-and-true-p comment-start)
|
||||
(looking-at comment-start)
|
||||
(not (boon-in-string-p))))
|
||||
|
||||
(defun boon-stuff-at-point ()
|
||||
"Return a meaningful piece of text around at point.
|
||||
If no such text exists, throw an error."
|
||||
(interactive)
|
||||
(if (use-region-p)
|
||||
(buffer-substring-no-properties (region-beginning) (region-end))
|
||||
(or (thing-at-point 'symbol)
|
||||
(error "Nothing relevant at point; move to a symbol or select a region"))))
|
||||
|
||||
|
||||
(defun boon-jump-over-blanks-forward ()
|
||||
"Jump over blanks, forward."
|
||||
(interactive)
|
||||
(skip-chars-forward "\n\t "))
|
||||
|
||||
(defun boon-jump-over-blanks-backward ()
|
||||
"Jump over blanks, backward."
|
||||
(interactive)
|
||||
(skip-chars-backward "\n\t "))
|
||||
|
||||
(provide 'boon-utils)
|
||||
|
||||
;;; boon-utils.el ends here
|
|
@ -3,10 +3,7 @@
|
|||
;;; Commentary:
|
||||
;; fgeller's workman port (WIP, contributions welcome)
|
||||
;;; Code:
|
||||
(require 'boon-core)
|
||||
(require 'boon-main)
|
||||
(require 'boon-search)
|
||||
(require 'boon-keys)
|
||||
(require 'boon)
|
||||
|
||||
(define-key boon-select-map (kbd "g") 'boon-select-document)
|
||||
(define-key boon-select-map (kbd "w") 'boon-select-paragraph)
|
||||
|
@ -40,8 +37,8 @@
|
|||
(define-key boon-moves-map (kbd ".") 'boon-end-of-expression)
|
||||
(define-key boon-moves-map (kbd "e") 'backward-char)
|
||||
(define-key boon-moves-map (kbd "o") 'forward-char)
|
||||
(define-key boon-moves-map (kbd "<") 'boon-beginning-of-region)
|
||||
(define-key boon-moves-map (kbd ">") 'boon-end-of-region)
|
||||
(define-key boon-moves-map (kbd "<") 'beginning-of-buffer)
|
||||
(define-key boon-moves-map (kbd ">") 'end-of-buffer)
|
||||
(define-key boon-moves-map (kbd "C-,") 'beginning-of-buffer)
|
||||
(define-key boon-moves-map (kbd "C-.") 'end-of-buffer)
|
||||
|
||||
|
|
6
boon.el
6
boon.el
|
@ -10,8 +10,12 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'boon-colemak)
|
||||
(require 'boon-main)
|
||||
(require 'boon-keys)
|
||||
(require 'boon-search)
|
||||
(require 'boon-extras)
|
||||
(require 'boon-core)
|
||||
(require 'boon-moves)
|
||||
|
||||
(provide 'boon)
|
||||
;;; boon.el ends here
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{-# OPTIONS_GHC -XTypeSynonymInstances -XOverloadedStrings -XRecursiveDo -pgmF marxup -F #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
module CC where
|
||||
|
||||
import Data.Char (toUpper)
|
||||
import Prelude hiding (mapM,sequence,Num(..),(/))
|
||||
import MarXup
|
||||
|
@ -57,7 +59,6 @@ argColor a = case a of
|
|||
Bin _ _ -> "purple"
|
||||
_ -> "white"
|
||||
|
||||
|
||||
reserved :: (TeX,Argument)
|
||||
reserved = (italic "reserved",Reserved)
|
||||
|
||||
|
@ -72,7 +73,7 @@ leftHandL = [[("escape",Char), ("search backward",SearchObject), ("search forwar
|
|||
]
|
||||
|
||||
leftHandR = [[("quotes (string)",None), ("word",None), ("word",None), ("paragraph",None), reserved]
|
||||
,[("enclosure",TextRegion), ("whole-line",None), ("symbol",None), reserved, ("document",None), ("previous-region",None)]
|
||||
,[("enclosure",TextRegion), ("whole-line",None), ("symbol",None), ("whitespace+",TextRegion), ("document",None), ("previous-region",None)]
|
||||
,[("inclosure",TextRegion), ("s-expr",None), ("s-expr contents",None), reserved, reserved]
|
||||
]
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue