boon/boon-core.el

244 lines
7.8 KiB
EmacsLisp
Raw Normal View History

;;; boon-core.el --- An Ergonomic Command Mode -*- lexical-binding: t -*-
2014-10-19 13:59:12 +02:00
;;; Commentary:
2014-10-23 13:05:17 +02:00
;; This module sets up the emulation keymaps for each boon state.
;; Functions to switch to each state is also provided.
2014-10-19 13:59:12 +02:00
;;; Code:
2014-10-20 14:06:34 +02:00
(require 'cl-macs)
2014-10-19 13:59:12 +02:00
2016-07-25 19:59:08 +02:00
;; Maps
2016-11-17 23:00:24 +01:00
(defgroup boon nil "Boon" :group 'Editing)
(defvar boon-x-map)
2016-11-16 19:59:36 +01:00
(define-prefix-command 'boon-x-map)
2014-10-19 14:17:46 +02:00
(set-keymap-parent boon-x-map ctl-x-map)
2016-09-04 21:42:27 +02:00
(defvar boon-command-map (make-sparse-keymap)
"Keymap used in Boon command mode.
2016-09-06 21:03:44 +02:00
\\{boon-command-map}")
2014-10-19 22:29:29 +02:00
(suppress-keymap boon-command-map 't) ; so that typing is disabled altogether in command mode
2016-09-04 21:42:27 +02:00
(defvar boon-moves-map (make-sparse-keymap)
"Keymap for moves (subset of command mode).
2016-09-06 21:03:44 +02:00
\\{boon-moves-map}")
2016-07-25 19:59:08 +02:00
(set-keymap-parent boon-command-map boon-moves-map)
(defvar boon-select-map (make-sparse-keymap)
2016-09-04 21:42:27 +02:00
"Keymap for text regions selectors.
\\{boon-select-map}
Any move is also a valid region selector.
2016-09-06 21:03:44 +02:00
\\{boon-moves-map}")
2014-10-19 13:59:12 +02:00
(defvar boon-off-map (make-sparse-keymap))
2016-08-29 20:09:33 +02:00
(make-obsolete-variable 'boon-off-map nil "20160713")
2014-10-19 13:59:12 +02:00
(defvar boon-insert-map (make-sparse-keymap))
2015-12-07 08:36:41 +01:00
(defvar boon-special-map (make-sparse-keymap))
2014-10-19 13:59:12 +02:00
2014-10-19 13:59:12 +02:00
(defvar boon-mode-map-alist (list (cons 'boon-command-state boon-command-map)
(cons 'boon-off-state boon-off-map)
2015-12-07 08:36:41 +01:00
(cons 'boon-special-state boon-special-map)
(cons 'boon-insert-state boon-insert-map)))
2014-10-19 13:59:12 +02:00
(push 'boon-mode-map-alist emulation-mode-map-alists)
;; States
2016-07-25 19:59:08 +02:00
(defvar-local boon-command-state nil "Non-nil when boon command mode is activated. (Boon commands can be entered in this mode.)")
(defvar-local boon-insert-state nil "Non-nil when boon insert mode is activated.")
(defvar-local boon-off-state nil "Non-nil when off state is
activated. Off state is similar to insert mode, but
insertion-specific commands are disabled then.")
(defvar-local boon-special-state nil "Non-nil when off state is
activated. Special is active when special-mode buffers are
activated. This buffers have their own set of commands, so we use
those. See 'boon-special-map' for exceptinons.")
2016-08-29 20:09:33 +02:00
(make-obsolete-variable 'boon-off-state nil "20160713")
2016-07-25 19:59:08 +02:00
;; indeed: the special mode is good enough that it's not necessary to
;; switch to 'off' mode any longer.
2014-10-19 13:59:12 +02:00
(defun boon-set-state (state)
2014-10-19 23:01:11 +02:00
"Set the boon state (as STATE) for this buffer."
2014-10-19 13:59:12 +02:00
(setq boon-command-state nil)
(setq boon-insert-state nil)
(setq boon-off-state nil)
2015-12-07 08:36:41 +01:00
(setq boon-special-state nil)
2014-10-19 13:59:12 +02:00
(set state t)
2015-12-07 08:36:41 +01:00
(unless (or boon-command-state boon-special-state)
2014-10-19 13:59:12 +02:00
(deactivate-mark)
(save-excursion
(when (not (bolp))
(let ((orig (point)))
(skip-chars-forward " " (line-end-position))
(when (eolp) (delete-region orig (point))))))
2014-10-19 13:59:12 +02:00
(setq cursor-type 'bar))
(cond (boon-command-state
;; (do-auto-save)
2015-12-07 08:36:41 +01:00
(setq cursor-type 'box))
(boon-special-state (setq cursor-type 'box))
2014-10-19 13:59:12 +02:00
(boon-off-state)
2014-10-28 12:30:38 +01:00
(boon-insert-state
;; remember where the last edition was by pushing a mark
(push-mark))
2014-10-19 13:59:12 +02:00
(t (message "Unknown state!")))
(force-mode-line-update))
(defun boon-set-insert-like-state ()
2016-09-04 21:42:27 +02:00
"Switch to special or insert state, depending on mode."
2014-10-19 13:59:12 +02:00
(interactive)
2016-07-25 19:59:08 +02:00
(if (boon-special-mode-p)
2016-08-30 20:43:19 +02:00
(boon-set-special-state)
2016-07-25 19:59:08 +02:00
(boon-set-state 'boon-insert-state)))
2014-10-19 13:59:12 +02:00
2014-10-20 22:44:11 +02:00
(defun boon-set-insert-state ()
"Switch to insert state."
(interactive)
(boon-set-state 'boon-insert-state))
2014-10-19 13:59:12 +02:00
(defun boon-set-command-state ()
2016-07-25 19:59:08 +02:00
"Switch to command state."
2014-10-19 13:59:12 +02:00
(interactive) (boon-set-state 'boon-command-state))
(defun boon-set-off-state ()
2014-10-20 14:06:34 +02:00
"Switch to off state."
2014-10-19 13:59:12 +02:00
(interactive) (boon-set-state 'boon-off-state))
2015-12-07 08:36:41 +01:00
(defun boon-set-special-state ()
2016-07-25 19:59:08 +02:00
"Switch to special state."
2015-12-07 08:36:41 +01:00
(interactive) (boon-set-state 'boon-special-state))
2015-05-25 23:22:57 +02:00
(defcustom boon-special-mode-list
'(
2014-10-23 13:05:17 +02:00
Buffer-menu-mode
2014-10-20 14:06:34 +02:00
debugger-mode
ediff-mode
git-rebase-mode
2014-11-24 13:39:01 +01:00
mu4e-headers-mode
mu4e-view-mode
2016-11-16 19:58:27 +01:00
org-agenda-mode
2017-03-18 21:12:41 +01:00
cfw:calendar-mode
)
2016-09-04 21:42:27 +02:00
"A List of modes which should use `boon-special-state'."
2016-11-08 20:35:02 +01:00
:group 'boon
:type '(repeat symbol))
2014-10-20 14:06:34 +02:00
(defun boon-special-mode-p ()
2016-09-04 21:42:27 +02:00
"Should the mode use `boon-special-state'?"
2015-12-03 19:46:29 +01:00
(or
2015-12-13 20:18:09 +01:00
(and (eq (get major-mode 'mode-class) 'special)
(not (derived-mode-p 'comint-mode 'eshell-mode)))
2015-12-03 19:46:29 +01:00
(memq major-mode boon-special-mode-list)))
2014-10-19 13:59:12 +02:00
;;; Initialisation and activation
(define-minor-mode boon-local-mode
"Minor mode for setting up command mode in a single buffer."
:init-value nil
:lighter (:eval (boon-modeline-string))
:keymap nil
(cond
(boon-local-mode
;; The initial state is usually setup by `boon-initialize' when
;; the major-mode in a buffer changes. This preliminary
;; initialization is only for the case when `boon-local-mode' is
;; called directly for the first time in a buffer.
(cond
2014-10-20 14:06:34 +02:00
((boon-special-mode-p)
2015-12-07 08:36:41 +01:00
(boon-set-state 'boon-special-state))
2014-10-19 13:59:12 +02:00
(t (boon-set-command-state))))
(t
(boon-set-off-state)
(message "Boon disabled")
)))
(add-hook 'minibuffer-setup-hook 'boon-minibuf-hook)
(defun boon-minibuf-hook ()
"Set the cursor type to 'bar'.
This is because no command mode is activated in the minibuffer."
(setq cursor-type 'bar))
2014-10-20 14:06:34 +02:00
;; The function `boon-initialize' should only be used to initialize
;; `boon-local-mode' from the globalized minor-mode `boon-mode'. It is
;; called whenever boon is enabled in a buffer for the first time or
;; when boon is active and the major-mode of the buffer changes.
2014-10-19 13:59:12 +02:00
(defun boon-initialize ()
2014-10-20 10:28:56 +02:00
"Enable Boon in the current buffer, if appropriate. To enable Boon globally, do (boon-mode 1)."
(unless (minibufferp)
2014-10-19 13:59:12 +02:00
(boon-local-mode 1)))
2014-10-20 14:06:34 +02:00
;;;###autoload (autoload 'boon-mode "boon" "Toggle boon in all buffers" t)
(define-globalized-minor-mode boon-mode boon-local-mode boon-initialize)
2014-10-19 13:59:12 +02:00
2014-10-20 14:06:34 +02:00
;;;###autoload
(defun turn-on-boon-mode ()
2014-10-19 13:59:12 +02:00
"Turn on Boon in the current buffer."
(interactive)
2014-10-20 14:06:34 +02:00
(boon-local-mode 1))
2014-10-19 13:59:12 +02:00
2014-10-20 14:06:34 +02:00
;;;###autoload
(defun turn-off-boon-mode ()
2014-10-19 13:59:12 +02:00
"Turn off Boon in the current buffer."
(interactive)
2014-10-20 14:06:34 +02:00
(boon-local-mode -1))
2014-10-19 13:59:12 +02:00
(defun boon-modeline-string ()
"Return the modeline string appropriate for the current state."
(concat " Boon:" (boon-state-string)))
(defun boon-state-string ()
2014-10-19 13:59:12 +02:00
"Return a string describing the current state."
(cond
2014-10-19 13:59:12 +02:00
(boon-command-state "CMD")
(boon-insert-state "INS")
(boon-off-state "OFF")
2015-12-07 08:36:41 +01:00
(boon-special-state "SPC")
(t "???")))
2016-08-29 22:06:38 +02:00
(with-eval-after-load 'multiple-cursors
2016-11-06 16:00:15 +01:00
(defvar mc--default-cmds-to-run-for-all)
(defvar mc--default-cmds-to-run-once)
2016-08-29 22:06:38 +02:00
(setq mc--default-cmds-to-run-for-all
(append '(boon-beginning-of-expression
boon-beginning-of-line
boon-end-of-expression
boon-end-of-line
boon-end-of-region
boon-find-char-backward
boon-find-char-forward
boon-quote-character
boon-replace-by-character
boon-set-insert-like-state
boon-smarter-backward
boon-smarter-forward
boon-splice
boon-split-line
boon-switch-mark
boon-toggle-character-case
boon-toggle-mark)))
(setq mc--default-cmds-to-run-once
(append mc--default-cmds-to-run-once
'(boon-adjust-indent
boon-drop-mark
boon-enclose
boon-qsearch-next
boon-qsearch-next-at-point
boon-qsearch-previous
boon-qsearch-previous-at-point
boon-query-replace
boon-quit
boon-set-command-state
boon-substitute-region
boon-take-region
2016-09-01 21:08:30 +02:00
boon-toggle-character-case
2016-08-29 22:06:38 +02:00
boon-toggle-case))))
2014-10-19 13:59:12 +02:00
(provide 'boon-core)
;;; boon-core ends here