;;; meow-core.el --- Mode definitions for Meow -*- lexical-binding: t; -*-
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 3
;; of the License, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;; Modes definition in Meow.
;;; Code:
(require 'cl-lib)
(require 'subr-x)
(require 'meow-util)
(require 'meow-command)
(require 'meow-keypad)
(require 'meow-var)
(require 'meow-esc)
(require 'meow-shims)
(require 'meow-beacon)
(require 'meow-helpers)
(meow-define-state insert
"Meow INSERT state minor mode."
:lighter " [I]"
:keymap meow-insert-state-keymap
:face meow-insert-cursor
(if meow-insert-mode
(run-hooks 'meow-insert-enter-hook)
(when (and meow--insert-pos
meow-select-on-change
(not (= (point) meow--insert-pos)))
(thread-first
(meow--make-selection '(select . transient) meow--insert-pos (point))
(meow--select)))
(run-hooks 'meow-insert-exit-hook)
(setq-local meow--insert-pos nil)))
(meow-define-state normal
"Meow NORMAL state minor mode."
:lighter " [N]"
:keymap meow-normal-state-keymap
:face meow-normal-cursor)
(meow-define-state motion
"Meow MOTION state minor mode."
:lighter " [M]"
:keymap meow-motion-state-keymap
:face meow-motion-cursor)
(meow-define-state keypad
"Meow KEYPAD state minor mode."
:lighter " [K]"
:keymap meow-keypad-state-keymap
:face meow-keypad-cursor
(when meow-keypad-mode
(setq meow--prefix-arg current-prefix-arg
meow--keypad-keymap-description-activated nil
meow--keypad-allow-quick-dispatch t
meow--keypad-base-keymap nil
meow--keypad-keys nil
meow--use-literal nil
meow--use-meta nil
meow--use-both nil)))
(meow-define-state beacon
"Meow BEACON state minor mode."
:lighter " [B]"
:keymap meow-beacon-state-keymap
:face meow-beacon-cursor
(if meow-beacon-mode
(progn
(setq meow--beacon-backup-hl-line (bound-and-true-p hl-line-mode)
meow--beacon-defining-kbd-macro nil)
(meow--cancel-selection)
(hl-line-mode -1))
(when meow--beacon-backup-hl-line
(hl-line-mode 1))))
;;;###autoload
(define-minor-mode meow-mode
"Meow minor mode.
This minor mode is used by meow-global-mode, should not be enabled directly."
:init-value nil
:interactive nil
:global nil
:keymap meow-keymap
(if meow-mode
(meow--enable)
(meow--disable)))
;;;###autoload
(defun meow-indicator ()
"Indicator showing current mode."
(or meow--indicator (meow--update-indicator)))
;;;###autoload
(define-global-minor-mode meow-global-mode meow-mode
(lambda ()
(unless (minibufferp)
(meow-mode 1)))
:group 'meow
(if meow-mode
(meow--global-enable)
(meow--global-disable)))
(defun meow--enable ()
"Enable Meow.
This function will switch to the proper state for current major
mode. Firstly, the variable `meow-mode-state-list' will be used.
If current major mode derived from any mode from the list,
specified state will be used. When no result is found, give a
test on the commands bound to the keys a-z. If any of the command
names contains \"self-insert\", then NORMAL state will be used.
Otherwise, MOTION state will be used.
Before turning on MOTION state, the original commands will be
remapped. The new keybinding is generated by prepending
`meow-motion-remap-prefix' to the original keybinding.
Note: When this function is called, NORMAL state is already
enabled. NORMAL state is enabled globally when
`meow-global-mode' is used, because in `fundamental-mode',
there's no chance for meow to call an init function."
(let ((state (meow--mode-get-state))
(motion (lambda ()
(meow--disable-current-state)
(meow--save-origin-commands)
(meow-motion-mode 1))))
(cond
;; if MOTION is specified
((eq state 'motion)
(funcall motion))
(state
(meow--disable-current-state)
(meow--switch-state state t)))))
(defun meow--disable ()
"Disable Meow."
(mapc (lambda (state-mode) (funcall (cdr state-mode) -1)) meow-state-mode-alist)
(meow--beacon-remove-overlays)
(when (secondary-selection-exist-p)
(meow--cancel-second-selection)))
(defun meow--global-enable ()
"Enable meow globally."
(setq-default meow-normal-mode t)
(meow--init-buffers)
(add-hook 'window-state-change-functions #'meow--on-window-state-change)
(add-hook 'minibuffer-setup-hook #'meow--minibuffer-setup)
(add-hook 'pre-command-hook 'meow--highlight-pre-command)
(add-hook 'post-command-hook 'meow--maybe-toggle-beacon-state)
(add-hook 'suspend-hook 'meow--on-exit)
(add-hook 'suspend-resume-hook 'meow--update-cursor)
(add-hook 'kill-emacs-hook 'meow--on-exit)
(add-hook 'desktop-after-read-hook 'meow--init-buffers)
(meow--enable-shims)
;; meow-esc-mode fix ESC in TUI
(unless window-system
(meow-esc-mode 1))
;; raise Meow keymap priority
(add-to-ordered-list 'emulation-mode-map-alists
`((meow-motion-mode . ,meow-motion-state-keymap)))
(add-to-ordered-list 'emulation-mode-map-alists
`((meow-normal-mode . ,meow-normal-state-keymap)))
(add-to-ordered-list 'emulation-mode-map-alists
`((meow-keypad-mode . ,meow-keypad-state-keymap)))
(add-to-ordered-list 'emulation-mode-map-alists
`((meow-beacon-mode . ,meow-beacon-state-keymap)))
(when meow-use-cursor-position-hack
(setq redisplay-highlight-region-function #'meow--redisplay-highlight-region-function)
(setq redisplay-unhighlight-region-function #'meow--redisplay-unhighlight-region-function))
(meow--prepare-face)
(advice-add 'load-theme :after 'meow--prepare-face))
(defun meow--global-disable ()
"Disable Meow globally."
(setq-default meow-normal-mode nil)
(remove-hook 'window-state-change-functions #'meow--on-window-state-change)
(remove-hook 'minibuffer-setup-hook #'meow--minibuffer-setup)
(remove-hook 'pre-command-hook 'meow--highlight-pre-command)
(remove-hook 'post-command-hook 'meow--maybe-toggle-beacon-state)
(remove-hook 'suspend-hook 'meow--on-exit)
(remove-hook 'suspend-resume-hook 'meow--update-cursor)
(remove-hook 'kill-emacs-hook 'meow--on-exit)
(remove-hook 'desktop-after-read-hook 'meow--init-buffers)
(meow--disable-shims)
(meow--remove-modeline-indicator)
(when meow-use-cursor-position-hack
(setq redisplay-highlight-region-function meow--backup-redisplay-highlight-region-function)
(setq redisplay-unhighlight-region-function meow--backup-redisplay-unhighlight-region-function))
(unless window-system
(meow-esc-mode -1))
(advice-remove 'load-theme 'meow--prepare-face))
(provide 'meow-core)
;;; meow-core.el ends here