猫态编辑:Meow

就是类似 make-sparse-key,选择模式只会把几个不需要 mark 的命令覆盖成移动命令,其他的保留。

另外狗哥可以录几个小视频来展示下自己的 meow,最好额外开个 frame,用来记录你的按键和命令(忘了那个包叫啥名了),有时即使是用一个人设计的 keybinding 很久,也不一定能想到作者的全部设计思路。然后之后出教程的时候,那个 frame 也可以顺便开着,也正好能宣传宣传(

如果有默认绑键中由C-g, 比如我将C-p C-g C-s绑定到magit-status, 我发现C-g不知道怎么输入, 因为和Alt冲突了…

C-g 是 Emacs 中的 keyboard-quit,也是唯一救命的键。。。 基本上不管你用什么都是非常不建议覆盖这个按键的,说这个键救命的原因是所有的 package 都不会在组合键中加入 C-g,所以 C-g 所绑定的这个 keyboard-quit 一定有机会执行。如果你覆盖了这个按键,如果真发生死循环的是就直接卡死了。也许不常见,但是如果自己写插件或 elisp 的话,还是非常重要的。

在设计 Meow 的时候就考虑不可能有这样的情况发生。 同样的,C-m 会被转义成 RET,所以也不会被使用。


对于在 magit(和其它所有特殊的 mode 集成的情况),Meow 比较推荐的做法就是什么绑定都不要做,Meow 自己会激活 MOTION 模式,而 MOTION 就是除了 SPC 绑定到了 Leader, 其余什么都不干。最多最多就是绑定给 MOTION 一个新的上/下键。

我目前的Dvp键盘的绑定方案, 部分函数功能做了点小改动,仅供参考。

(meow-normal-define-key
   '("*" . meow-expand-0)
   '("=" . meow-expand-9)
   '("!" . meow-expand-8)
   '("[" . meow-expand-7)
   '("]" . meow-expand-6)
   '("{" . meow-expand-5)
   '("+" . meow-expand-4)
   '("}" . meow-expand-3)
   '(")" . meow-expand-2)
   '("(" . meow-expand-1)
   '("1" . digit-argument)
   '("2" . digit-argument)
   '("3" . digit-argument)
   '("4" . digit-argument)
   '("5" . digit-argument)
   '("6" . digit-argument)
   '("7" . digit-argument)
   '("8" . digit-argument)
   '("9" . digit-argument)
   '("0" . digit-argument)
   '("-" . negative-argument)
   '(";" . meow-comment)
   ;; '("," . meow-inner-of-thing) ; chord keys
   '("." . meow-bounds-of-thing)
   '("<" . meow-beginning-of-thing)
   '(">" . meow-end-of-thing)
   '("a" . meow-append)
   ;; '("A" . meow-clipboard-yank)
   '("b" . meow-back-word)
   '("B" . meow-back-symbol)
   '("c" . meow-change)
   '("C" . meow-change-save)
   '("d" . meow-delete)
   '("D" . meow-replace)
   '("e" . meow-line)
   '("f" . meow-find)
   '("F" . meow-find-expand)
   '("g" . meow-keyboard-quit)
   '("G" . goto-line)
   '("h" . meow-head)
   '("H" . meow-head-expand)
   '("i" . meow-insert)
   ;; '("I" . winner-undo)
   '("j" . meow-join)
   '("J" . delete-indentation)
   '("k" . meow-kill)
   '("l" . meow-till)
   '("L" . meow-till-expand)
   '("m" . meow-mark-word)
   '("M" . meow-mark-symbol)
   '("n" . meow-next)
   '("N" . meow-next-expand)
   '("o" . meow-block)
   '("O" . meow-block-expand)
   '("p" . meow-prev)
   '("P" . meow-prev-expand)
   '("q" . meow-quit)
   '("r" . meow-reverse)
   '("R" . meow-open-above)
   '("s" . meow-M-x)
   '("t" . meow-tail)
   '("T" . meow-tail-expand)
   '("u" . meow-undo)
   '("U" . winner-undo)
   '("v" . meow-search)
   '("w" . meow-next-word)
   '("W" . meow-next-symbol)
   '("x" . meow-save)
   '("X" . meow-clipboard-save)
   '("y" . meow-yank)
   '("Y" . meow-clipboard-yank)
   '("z" . meow-pop-selection)
   '("Z" . meow-pop-all-selection)
   '("'" . meow-pop-to-mark)
   '("/" . meow-visit)
   '("&" . meow-query-replace)
   '("%" . meow-query-replace-regexp)
   '("@" . recenter)
   ;; '("^" . meow-pop-to-mark)
   '("<escape>" . meow-last-buffer)
   '("$" . apply-macro-to-region-lines))

可以提供这些函数的改动思路或是源码,讨论之后进行一些整合?


话说咱们的选择好接近。。

我发现的新的解决方式是这样:

(meow-leader-define-key
'("ss" . swiper)
'(",gs" . magit-status)
'(",kk" . find-file-in-project-by-selected)
'("p" . meow-keypad-start)
)

这样相比evil, 只会多按一个spc, 影响不是太大.

我觉得对于每个插件来说,大部分都可以不设快捷键,少部分的话就按照自己不用模式编辑的方式来设置。

最后所有模式编辑的配置都在一个文件里面,以我自己的配置为例,我去掉这个文件对其它插件的使用没有任何影响,可以说 Meow 的配置对于你 emacs 配置的其它部分是 没有侵入性 的。这是我很在意的一点。

我自己的 meow 的配置,仅一个文件,且与其它文件没有交集

1赞

哈哈哈,我也是用 Dvp, 所以直接在你配置的基础上,做了点小变动。

主要改动是活用 fallback。 像 x c g都回落到 keypad mode了,r 回落个 (meow-open-below)。

如果你用的是 general.el 可以直接给对应的keymap邦个键。然后,这个keymap下的所有按键 都有了。

我自己是没有再用 fallback,因为在 MOTION 里面的话,就必须要 SPC 了。感觉两边不一样的话,就有点适应不能。

我前端时间研究了 Vim 和 Kakoune 的那些快捷键设计,感觉像 xah-fly-key 的话就更喜欢那种 dwim 行为,每个键都要好多职责,Meow 最开始也是这样的。但是后来觉得可能保持一个按键序列一个行为更好,Vim 之类的都是这样的设计方式,所以有时看起来是不怎么科学,如果说从按键数量上看。不过心智负担比较低。

我现在希望的是 Meow 在保持心智负担低的情况下,尽量的精简。

2赞

赞同。如果过度滥用,的确心智负担重,特别是对于新的使用者和新的按键方案。可以根据每个人的按键设计方案,适度使用fallback,因为能fallback的场景和按键并不是很多。Meow可以提供这个fallback的功能,看个人怎么用了。对我来说,熟悉了,感觉都是指头的肌肉记忆。心智负担还好。

加了一个小小的 feature,允许在退出选择的时候自动选择插入的内容,默认关闭。也许可以解决替代 vim 中 repeat 的一部分场景(对我来说是绝大部分,我以前经常 n.n.n.n.)。在 issue 中回复了细节

nice. 不过功能是不是和 query-replace 有点重叠了?

是重叠的,但是 query-replace 的话需要输入,或复制粘贴要被替换的内容。这个功能也可以让 query-replace 的过程变简单。

1赞

回头尝尝鲜。 :crazy_face:

狗哥,你是都推到master分支了吗? develop分支放弃了?

1赞

推到 master 了,develop 分支打算删掉,主要是为了大重构才开的。剩下的都是小优化了。后续再看情况

在文档中加入了 QWERTY 布局的示例,发现自己真的是好长时间没有用了,就想是以前很熟的 Vim HJKL, 现在也完全按不来了。

这个示例中,在 special mode 里面依然是 j / k 上下移动。 在 Leader 中则是预留了 j/k 给原 special-mode 中被覆盖的命令。

(defun meow-setup ()
  (meow-motion-overwrite-define-key
   '("j" . meow-next)
   '("k" . meow-prev))
  (meow-leader-define-key
   ;; SPC j/k will run the original command in MOTION state.
   '("j" . meow-motion-origin-command)
   '("k" . meow-motion-origin-command)
   ;; Use SPC (0-9) for digit arguments.
   '("1" . meow-digit-argument)
   '("2" . meow-digit-argument)
   '("3" . meow-digit-argument)
   '("4" . meow-digit-argument)
   '("5" . meow-digit-argument)
   '("6" . meow-digit-argument)
   '("7" . meow-digit-argument)
   '("8" . meow-digit-argument)
   '("9" . meow-digit-argument)
   '("0" . meow-digit-argument))
  (meow-normal-define-key
   '("0" . meow-expand-0)
   '("9" . meow-expand-9)
   '("8" . meow-expand-8)
   '("7" . meow-expand-7)
   '("6" . meow-expand-6)
   '("5" . meow-expand-5)
   '("4" . meow-expand-4)
   '("3" . meow-expand-3)
   '("2" . meow-expand-2)
   '("1" . meow-expand-1)
   '("-" . negative-argument)
   '(";" . meow-reverse)
   '("," . meow-inner-of-thing)
   '("." . meow-bounds-of-thing)
   '("[" . meow-beginning-of-thing)
   '("]" . meow-end-of-thing)
   '("a" . meow-append)
   '("A" . meow-open-below)
   '("b" . meow-back-word)
   '("B" . meow-back-symbol)
   '("c" . meow-change)
   '("C" . meow-change-save)
   '("d" . meow-delete)
   '("x" . meow-line)
   '("f" . meow-find)
   '("F" . meow-find-expand)
   '("g" . meow-keyboard-quit)
   '("G" . goto-line)
   '("h" . meow-head)
   '("H" . meow-head-expand)
   '("i" . meow-insert)
   '("I" . meow-open-above)
   '("m" . meow-join)
   '("M" . delete-indentation)
   '("s" . meow-kill)
   '("t" . meow-till)
   '("T" . meow-till-expand)
   '("w" . meow-mark-word)
   '("W" . meow-mark-symbol)
   '("j" . meow-next)
   '("J" . meow-next-expand)
   '("o" . meow-block)
   '("O" . meow-block-expand)
   '("k" . meow-prev)
   '("K" . meow-prev-expand)
   '("q" . meow-quit)
   '("r" . meow-replace)
   '("R" . meow-replace-save)
   '("n" . meow-search)
   '("N" . meow-pop-search)
   '("l" . meow-tail)
   '("L" . meow-tail-expand)
   '("u" . undo)
   '("v" . meow-visit)
   '("e" . meow-next-word)
   '("e" . meow-next-symbol)
   '("y" . meow-save)
   '("p" . meow-yank)
   '("z" . meow-pop-selection)
   '("Z" . meow-pop-all-selection)
   '("&" . meow-query-replace)
   '("%" . meow-query-replace-regexp)
   '("<escape>" . meow-last-buffer)))
1赞

meow-leader-define-key能不能绑定prefix-map

请问下,按如下最小配置,在启动后的scratch中,按i等都显示i is undefined,是使用方式不对么?

modeline显示已处于normal状态。

;; Set ELPA packages
(setq package-archives '(("gnu" . "https://elpa.emacs-china.org/gnu/")
                         ("melpa" . "https://elpa.emacs-china.org/melpa/")))

;; Initialize packages
(unless (bound-and-true-p package--initialized) ; To avoid warnings in 27
  (setq package-enable-at-startup nil)          ; To prevent initializing twice
  (package-initialize))

;; Setup `use-package'
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

;; Should set before loading `use-package'
(eval-and-compile
  (setq use-package-always-ensure t)
  (setq use-package-always-defer t)
  (setq use-package-expand-minimally t)
  (setq use-package-enable-imenu-support t))

(eval-when-compile
  (require 'use-package))

(use-package meow
  :init
  (meow-global-mode 1)
  :config
  (meow-setup-line-number)
  (defun meow-setup ()
    (meow-motion-overwrite-define-key
     '("j" . meow-next)
     '("k" . meow-prev))
    (meow-leader-define-key
     ;; SPC j/k will run the original command in MOTION state.
     '("j" . meow-motion-origin-command)
     '("k" . meow-motion-origin-command)
     ;; Use SPC (0-9) for digit arguments.
     '("1" . meow-digit-argument)
     '("2" . meow-digit-argument)
     '("3" . meow-digit-argument)
     '("4" . meow-digit-argument)
     '("5" . meow-digit-argument)
     '("6" . meow-digit-argument)
     '("7" . meow-digit-argument)
     '("8" . meow-digit-argument)
     '("9" . meow-digit-argument)
     '("0" . meow-digit-argument))
    (meow-normal-define-key
     '("0" . meow-expand-0)
     '("9" . meow-expand-9)
     '("8" . meow-expand-8)
     '("7" . meow-expand-7)
     '("6" . meow-expand-6)
     '("5" . meow-expand-5)
     '("4" . meow-expand-4)
     '("3" . meow-expand-3)
     '("2" . meow-expand-2)
     '("1" . meow-expand-1)
     '("-" . negative-argument)
     '(";" . meow-reverse)
     '("," . meow-inner-of-thing)
     '("." . meow-bounds-of-thing)
     '("[" . meow-beginning-of-thing)
     '("]" . meow-end-of-thing)
     '("a" . meow-append)
     '("A" . meow-open-below)
     '("b" . meow-back-word)
     '("B" . meow-back-symbol)
     '("c" . meow-change)
     '("C" . meow-change-save)
     '("d" . meow-delete)
     '("x" . meow-line)
     '("f" . meow-find)
     '("F" . meow-find-expand)
     '("g" . meow-keyboard-quit)
     '("G" . goto-line)
     '("h" . meow-head)
     '("H" . meow-head-expand)
     '("i" . meow-insert)
     '("I" . meow-open-above)
     '("m" . meow-join)
     '("M" . delete-indentation)
     '("s" . meow-kill)
     '("t" . meow-till)
     '("T" . meow-till-expand)
     '("w" . meow-mark-word)
     '("W" . meow-mark-symbol)
     '("j" . meow-next)
     '("J" . meow-next-expand)
     '("o" . meow-block)
     '("O" . meow-block-expand)
     '("k" . meow-prev)
     '("K" . meow-prev-expand)
     '("q" . meow-quit)
     '("r" . meow-replace)
     '("R" . meow-replace-save)
     '("n" . meow-search)
     '("N" . meow-pop-search)
     '("l" . meow-tail)
     '("L" . meow-tail-expand)
     '("u" . undo)
     '("v" . meow-visit)
     '("e" . meow-next-word)
     '("e" . meow-next-symbol)
     '("y" . meow-save)
     '("p" . meow-yank)
     '("z" . meow-pop-selection)
     '("Z" . meow-pop-all-selection)
     '("&" . meow-query-replace)
     '("%" . meow-query-replace-regexp)
     '("<escape>" . meow-last-buffer)))
  (meow-setup))