Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## Master

### Breaking Changes

* replace motion remapping with transparent keypad leader.

The `meow-motion-overwrite-define-key` has been changed to `meow-motion-define-key`. and now it
works just like other key binding helpers. Users don't have to bind a key to remapped the
keybinding. Now the keypad leader is transparent when a key is not bound in motion state. So that
users can still access the original command with `SPC <original-key>`.

## 1.5.0 (2024-10-20)

### Features
Expand Down
38 changes: 22 additions & 16 deletions CUSTOMIZATIONS.org
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Define key bindings in a state.

Similar to ~meow-define-keys~. Define key in NORMAL state.

** meow-motion-define-key

Similar to ~meow-define-keys~. Define key in MOTION state.

** meow-leader-define-key

Similar to ~meow-define-keys~. Define key in leader keymap.
Expand All @@ -33,14 +37,6 @@ The keymap used is the one listed in ~meow-keymap-alist~.

By default, it is ~mode-specific-map~.

** meow-motion-overwrite-define-key

Similar to ~meow-define-keys~. Define key in MOTION state.

Meow will remap overwritten commands to a keybinding with *HYPER* modifier.

For example, if you define ~j~ as ~C-N~ , the original command on ~j~ will be bound to ~H-j~.

** meow-setup-indicator

A helper function that puts an indicator at the beginning of mode-line. If you want customize mode-line by hand, see `meow-indicator`.
Expand Down Expand Up @@ -313,17 +309,27 @@ Default: ~select~

The type of selection activated by ~meow-expand-*~ commands.

** meow-motion-remap-prefix
** meow-keypad-leader-dispatch

Default: ~nil~

The fallback dispatching in KEYPAD when there's no translation.

The value can be either a string or a keymap:

A keymap stands for a base keymap used for further translation. A string stands for finding the
keymap at a specified key binding. Nil stands for taking leader keymap from ~meow-keymap-alist~.

** meow-keypad-leader-transparent

Default: "H-"
Default: ~motion~

The prefix string used when remapping an occupied key in MOTION state.
Use transparent behaivor when a bound command is not found in leader dispatch.

For examples:
#+begin_example
"C-x C-v" will remap the occupied j to C-x C-v j.
"C-M-" will remap the occupied j to C-M-j.
#+end_example
- Value ~t~ stands for always be transparent.
- Value ~motion~ stands for only be transparent in MOTION state.
- Value ~normal~ stands for only be transparent in NORMAL state.
- Value ~nil~ stands for never be transparent."

** meow-state-mode-alist
Association list of symbols of meow states to their corresponding mode functions.
Expand Down
19 changes: 2 additions & 17 deletions TUTORIAL.org
Original file line number Diff line number Diff line change
Expand Up @@ -66,30 +66,15 @@ MOTION state is the default state for special modes, like ~dired~, ~proced~, etc
By default, MOTION state has no keybindings, except ~SPC~ is used as the leader key. The original command on ~SPC~ can be access via ~SPC SPC~.

Users may want a consistent keybindings for movement globally, for example: k/j to move up/down. Usually, you can bind k/j in MOTION state,
however the original command on k/j is not accessible. To solve the problem, Meow introduce a simple solution.

For any keybinding you defined with ~meow-motion-overwrite-define-key~, the overwritten command will be bound to the key with ~hyper~ modifier.
however then the original command on k/j is not accessible. To access the original command on k/j, use ~SPC k/j~.

Here's an example: you want use ~j~ as ~next-line~ globally.

#+begin_src emacs-lisp
(meow-motion-overwrite-define-key '("j" . next-line))
(meow-leader-define-key '("j" . "H-j"))
#+end_src

Now ~j~ will act as ~next-line~, the original command on ~j~ (e.g. ~dired-goto-file~ in ~dired~) will be bound to ~H-j~.
Since we use ~j~ in the leader for ~H-j~, now we can call it via ~SPC j~.

It is also possible to route the original command(e.g. ~j~) to original motion key(e.g. ~n~).

#+begin_src emacs-lisp
(meow-motion-overwrite-define-key '("j" . next-line))
(meow-motion-overwrite-define-key '("n" . "H-j"))
#+end_src

Now you have swapped ~j~ and ~n~.

The settings we made has nothing to do with the name of a command. Thus, it works in all special modes.
The settings we made works in all special modes.

** KEYPAD

Expand Down
20 changes: 3 additions & 17 deletions meow-core.el
Original file line number Diff line number Diff line change
Expand Up @@ -129,27 +129,13 @@ 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)))))
(let ((state (meow--mode-get-state)))
(meow--disable-current-state)
(meow--switch-state state t)))

(defun meow--disable ()
"Disable Meow."
Expand Down
8 changes: 4 additions & 4 deletions meow-helpers.el
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ with this helper, it will result in recursive calls.
Check `meow-normal-define-key' for usages."
(apply #'meow-define-keys 'leader keybinds))

;; Remap Leader SPC
(meow-leader-define-key (cons "SPC" (concat meow-motion-remap-prefix "SPC")))

(defun meow-motion-overwrite-define-key (&rest keybinds)
(defun meow-motion-define-key (&rest keybinds)
"Define key for MOTION state.

Check `meow-normal-define-key' for usages."
(apply #'meow-define-keys 'motion keybinds))

(defalias 'meow-motion-overwrite-define-key 'meow-motion-define-key)
(make-obsolete 'meow-motion-overwrite-define-key 'meow-motion-define-key "1.6.0")

(defun meow-setup-line-number ()
(add-hook 'display-line-numbers-mode-hook #'meow--toggle-relative-line-number)
(add-hook 'meow-insert-mode-hook #'meow--toggle-relative-line-number))
Expand Down
38 changes: 23 additions & 15 deletions meow-keypad.el
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
;;
;;; Code:

(require 'cl-lib)
(require 'subr-x)
(require 'meow-var)
(require 'meow-util)
Expand Down Expand Up @@ -66,9 +67,7 @@
(let* ((keybind (if meow--keypad-base-keymap
(lookup-key meow--keypad-base-keymap keys)
(key-binding keys))))
(unless (and (meow--is-self-insertp keybind)
(not meow-keypad-self-insert-undefined))
keybind)))
keybind))

(defun meow--keypad-has-sub-meta-keymap-p ()
"Check if there's a keymap belongs to Meta prefix.
Expand Down Expand Up @@ -408,8 +407,8 @@ If there are beacons, execute it at every beacon."
(defun meow--keypad-try-execute ()
"Try execute command, return t when the translation progress can be ended.

If there is a command available on the current key binding,
try replacing the last modifier and try again."
This function supports a fallback behavior, where it allows to use `SPC
x f' to execute `C-x C-f' or `C-x f' when `C-x C-f' is not bound."
(unless (or meow--use-literal
meow--use-meta
meow--use-both)
Expand Down Expand Up @@ -439,23 +438,32 @@ try replacing the last modifier and try again."
(meow--keypad-try-execute))
(t
(setq meow--prefix-arg nil)
(message "%s is undefined" (meow--keypad-format-keys nil))
(meow--keypad-quit)
(if (or (eq t meow-keypad-leader-transparent)
(eq meow--keypad-previous-state meow-keypad-leader-transparent))
(let* ((key (meow--parse-input-event last-input-event))
(origin-cmd (cl-some (lambda (m)
(lookup-key m key))
(current-active-maps)))
(remapped-cmd (command-remapping origin-cmd))
(cmd-to-call (if (member remapped-cmd '(undefined nil))
(or origin-cmd 'undefined)
remapped-cmd)))
(meow--keypad-execute cmd-to-call))
(message "%s is undefined" key-str))
t)))))

(defun meow--keypad-handle-input-with-keymap (input-event)
"Handle INPUT-EVENT with `meow-keypad-state-keymap'.

Return t if handling is completed."
(if (numberp input-event)
(let* ((k (if (= 27 input-event)
[escape]
(kbd (single-key-description input-event))))
(cmd (lookup-key meow-keypad-state-keymap k)))
(if cmd
(call-interactively cmd)
(meow--keypad-handle-input-event input-event)))
(meow--keypad-quit)))
(if (equal 'escape last-input-event)
(meow--keypad-quit)
(setq last-command-event last-input-event)
(let ((kbd (single-key-description input-event)))
(if-let* ((cmd (lookup-key meow-keypad-state-keymap (read-kbd-macro kbd))))
(call-interactively cmd)
(meow--keypad-handle-input-event input-event)))))

(defun meow--keypad-handle-input-event (input-event)
"Handle the INPUT-EVENT.
Expand Down
2 changes: 1 addition & 1 deletion meow-tutor.el
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@
added to your search if the selection is created with \\[meow-visit], \\[meow-mark-word] and \\[meow-mark-symbol].

=================================================================
= KEYPAD AND MOTION MODE =
= KEYPAD =
=================================================================

One of the most notable features of Meow is the Keypad. It
Expand Down
35 changes: 0 additions & 35 deletions meow-util.el
Original file line number Diff line number Diff line change
Expand Up @@ -470,41 +470,6 @@ Looks up the state in meow-replace-state-name-list"
(format "<%s>" e))
(t nil)))

(defun meow--save-origin-commands ()
"Save the commands overridden by the Motion map to modified bindings.

The new key binding, modified by the prefix in
`meow-motion-remap-prefix', is bound to a command that calls the
command locally bound to the original key binding, or, if that is
nil, the original command.

For example, under the default and suggested settings, in a
Magit status buffer, `k' could be bound to `meow-previous'
and `H-k' would be bound to a command that would try
to use the status buffer's original `k' binding at point."
(cl-loop for key-code being the key-codes of meow-motion-state-keymap do
(ignore-errors
(let* ((key (meow--parse-input-event key-code))
(cmd (key-binding (kbd key))))
(when (and (commandp cmd)
(not (equal cmd 'undefined)))
(let ((rebind-key (concat meow-motion-remap-prefix key)))
(local-set-key (kbd rebind-key)
(lambda ()
(interactive)
;; Local maps are those local to the buffer
;; or a region of the buffer.
(let* ((local (lookup-key (current-local-map) key))
(remapped (command-remapping local)))
(call-interactively
(cond
((commandp remapped)
remapped)
((commandp local)
local)
(t
cmd))))))))))))

(defun meow--prepare-region-for-kill ()
(when (and (equal 'line (cdr (meow--selection-type)))
(meow--direction-forward-p)
Expand Down
27 changes: 13 additions & 14 deletions meow-var.el
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,6 @@ Each item is a (THING FORWARD_SYNTAX_TO_INCLUDE BACKWARD-SYNTAX_TO_INCLUDE)."
:group 'meow
:type 'boolean)

(defcustom meow-keypad-self-insert-undefined t
"Whether to self-insert a key in keypad mode if it is undefined"
:group 'meow
:type 'boolean)

(defcustom meow-char-thing-table
'((?r . round)
(?s . square)
Expand Down Expand Up @@ -282,6 +277,19 @@ Set to `t' to always update.
:type '(choice (const select)
(const expand)))

(defcustom meow-keypad-leader-transparent 'motion
"Use transparent behaivor when a bound command is not found in leader dispatch.

Value `t' stands for always be transparent.
Value `motion' stands for only be transparent in MOTION state.
Value `normal' stands for only be transparent in NORMAL state.
Value `nil' stands for never be transparent."
:group 'meow
:type '(choice (const t :tag "Always be transparent")
(const motion :tag "Transparent only in MOTION state")
(const normal :tag "Transparent only in NORMAL state")
(const nil :tag "Never be transparent")))

(defcustom meow-keypad-leader-dispatch nil
"The fallback dispatching in KEYPAD when there's no translation.

Expand Down Expand Up @@ -320,15 +328,6 @@ prompted to finish the command."
:type '(alist :key-type (character :tag "From")
:value-type (character :tag "To")))

(defcustom meow-motion-remap-prefix "H-"
"The prefix string used when remapping an occupied key in MOTION state.

For examples:
\"C-x C-v\" will remap the occupied j to C-x C-v j.
\"C-M-\" will remap the occupied j to C-M-j."
:group 'meow
:type 'string)

(defcustom meow-goto-line-function nil
"Function to use in `meow-goto-line'.

Expand Down
Loading