diff --git a/README.md b/README.md index cce133e..be6ad14 100644 --- a/README.md +++ b/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 [![MELPA](http://stable.melpa.org/packages/boon-badge.svg)](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. + diff --git a/boon-arguments.el b/boon-arguments.el index 64c3c39..2087ae2 100644 --- a/boon-arguments.el +++ b/boon-arguments.el @@ -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) diff --git a/boon-colemak.el b/boon-colemak.el index 7afda65..f5ecfa7 100644 --- a/boon-colemak.el +++ b/boon-colemak.el @@ -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 "") '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 "") 'ivy-next-line) - (define-key ivy-minibuffer-map (kbd "") '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 "") '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 "") '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 "") 'ivy-next-line) + (define-key ivy-minibuffer-map (kbd "") '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 "") '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) diff --git a/boon-extras.el b/boon-extras.el index 81f7275..9bb7221 100644 --- a/boon-extras.el +++ b/boon-extras.el @@ -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) diff --git a/boon-keys.el b/boon-keys.el index 60d11b3..8d0d82d 100644 --- a/boon-keys.el +++ b/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 diff --git a/boon-main.el b/boon-main.el index 0936339..a65a316 100644 --- a/boon-main.el +++ b/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 diff --git a/boon-moves.el b/boon-moves.el new file mode 100644 index 0000000..510751e --- /dev/null +++ b/boon-moves.el @@ -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 + diff --git a/boon-qwerty.el b/boon-qwerty.el index 3319b15..2586dfe 100644 --- a/boon-qwerty.el +++ b/boon-qwerty.el @@ -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) diff --git a/boon-search.el b/boon-search.el index 8fcee39..6121439 100644 --- a/boon-search.el +++ b/boon-search.el @@ -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.") diff --git a/boon-utils.el b/boon-utils.el new file mode 100644 index 0000000..4649ad3 --- /dev/null +++ b/boon-utils.el @@ -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 diff --git a/boon-workman.el b/boon-workman.el index c2e4b7d..f760495 100644 --- a/boon-workman.el +++ b/boon-workman.el @@ -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) diff --git a/boon.el b/boon.el index bcf2a5c..a031b60 100644 --- a/boon.el +++ b/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 diff --git a/cheat-sheet.hs b/cheat-sheet.hs index 9c8d6fd..48e545a 100644 --- a/cheat-sheet.hs +++ b/cheat-sheet.hs @@ -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] ]