boon/boon-core.el
Jean-Philippe Bernardy c37750547e remove attempt to enable boon in all buffers
Boon is enabled in fundamental buffers anyway. The removed code does not
manage to enable boon in temporary buffers, so it seems useless.
2016-11-25 13:48:21 +01:00

242 lines
7.7 KiB
EmacsLisp

;;; boon-core.el --- An Ergonomic Command Mode -*- lexical-binding: t -*-
;;; Commentary:
;; This module sets up the emulation keymaps for each boon state.
;; Functions to switch to each state is also provided.
;;; Code:
(require 'cl-macs)
;; Maps
(defgroup boon nil "Boon" :group 'Editing)
(defvar boon-x-map)
(define-prefix-command 'boon-x-map)
(set-keymap-parent boon-x-map ctl-x-map)
(defvar boon-command-map (make-sparse-keymap)
"Keymap used in Boon command mode.
\\{boon-command-map}")
(suppress-keymap boon-command-map 't) ; so that typing is disabled altogether in command mode
(defvar boon-moves-map (make-sparse-keymap)
"Keymap for moves (subset of command mode).
\\{boon-moves-map}")
(set-keymap-parent boon-command-map boon-moves-map)
(defvar boon-select-map (make-sparse-keymap)
"Keymap for text regions selectors.
\\{boon-select-map}
Any move is also a valid region selector.
\\{boon-moves-map}")
(defvar boon-off-map (make-sparse-keymap))
(make-obsolete-variable 'boon-off-map nil "20160713")
(defvar boon-insert-map (make-sparse-keymap))
(defvar boon-special-map (make-sparse-keymap))
(defvar boon-mode-map-alist (list (cons 'boon-command-state boon-command-map)
(cons 'boon-off-state boon-off-map)
(cons 'boon-special-state boon-special-map)
(cons 'boon-insert-state boon-insert-map)))
(push 'boon-mode-map-alist emulation-mode-map-alists)
;; States
(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.")
(make-obsolete-variable 'boon-off-state nil "20160713")
;; indeed: the special mode is good enough that it's not necessary to
;; switch to 'off' mode any longer.
(defun boon-set-state (state)
"Set the boon state (as STATE) for this buffer."
(setq boon-command-state nil)
(setq boon-insert-state nil)
(setq boon-off-state nil)
(setq boon-special-state nil)
(set state t)
(unless (or boon-command-state boon-special-state)
(deactivate-mark)
(save-excursion
(when (not (bolp))
(let ((orig (point)))
(skip-chars-forward " " (line-end-position))
(when (eolp) (delete-region orig (point))))))
(setq cursor-type 'bar))
(cond (boon-command-state
;; (do-auto-save)
(setq cursor-type 'box))
(boon-special-state (setq cursor-type 'box))
(boon-off-state)
(boon-insert-state
;; remember where the last edition was by pushing a mark
(push-mark))
(t (message "Unknown state!")))
(force-mode-line-update))
(defun boon-set-insert-like-state ()
"Switch to special or insert state, depending on mode."
(interactive)
(if (boon-special-mode-p)
(boon-set-special-state)
(boon-set-state 'boon-insert-state)))
(defun boon-set-insert-state ()
"Switch to insert state."
(interactive)
(boon-set-state 'boon-insert-state))
(defun boon-set-command-state ()
"Switch to command state."
(interactive) (boon-set-state 'boon-command-state))
(defun boon-set-off-state ()
"Switch to off state."
(interactive) (boon-set-state 'boon-off-state))
(defun boon-set-special-state ()
"Switch to special state."
(interactive) (boon-set-state 'boon-special-state))
(defcustom boon-special-mode-list
'(
Buffer-menu-mode
debugger-mode
ediff-mode
git-rebase-mode
mu4e-headers-mode
mu4e-view-mode
org-agenda-mode
)
"A List of modes which should use `boon-special-state'."
:group 'boon
:type '(repeat symbol))
(defun boon-special-mode-p ()
"Should the mode use `boon-special-state'?"
(or
(and (eq (get major-mode 'mode-class) 'special)
(not (derived-mode-p 'comint-mode 'eshell-mode)))
(memq major-mode boon-special-mode-list)))
;;; 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
((boon-special-mode-p)
(boon-set-state 'boon-special-state))
(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))
;; 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.
(defun boon-initialize ()
"Enable Boon in the current buffer, if appropriate. To enable Boon globally, do (boon-mode 1)."
(unless (minibufferp)
(boon-local-mode 1)))
;;;###autoload (autoload 'boon-mode "boon" "Toggle boon in all buffers" t)
(define-globalized-minor-mode boon-mode boon-local-mode boon-initialize)
;;;###autoload
(defun turn-on-boon-mode ()
"Turn on Boon in the current buffer."
(interactive)
(boon-local-mode 1))
;;;###autoload
(defun turn-off-boon-mode ()
"Turn off Boon in the current buffer."
(interactive)
(boon-local-mode -1))
(defun boon-modeline-string ()
"Return the modeline string appropriate for the current state."
(concat " Boon:" (boon-state-string)))
(defun boon-state-string ()
"Return a string describing the current state."
(cond
(boon-command-state "CMD")
(boon-insert-state "INS")
(boon-off-state "OFF")
(boon-special-state "SPC")
(t "???")))
(with-eval-after-load 'multiple-cursors
(defvar mc--default-cmds-to-run-for-all)
(defvar mc--default-cmds-to-run-once)
(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
boon-toggle-character-case
boon-toggle-case))))
(provide 'boon-core)
;;; boon-core ends here