猫态编辑:Meow

Gitee从Github/Gitlab (https)导入的仓库有这功能,但是我一般还是用melpa的镜像,搬过来只是看文档方便,同步功能没有深入折腾过,不知道打开的姿势对不对;

我现在用的老王全家桶都是一个叫kuxia的道友同步过来的,他还建了一个叫emacs-hub的gitee组织,不知道平时在不在坛子里活动……

[wsw@t440p ~]$ emacs --version
GNU Emacs 27.1
Copyright (C) 2020 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
[wsw@t440p ~]$ 
[wsw@t440p ~]$ emacs --batch --eval "(print (string-replace \"a\" \"b\" \"abababa\"))"
Symbol’s function definition is void: string-replace

奇怪

那可能是28才有的函数,我可能要换到 s 里面的 函数。

感觉 s-replace 干的就是一样的事。你可以先简单的定义 string-replace 就是 s-replace?

我试试看定义别名

最新的版本里面依赖了 s.el 现在应该没有这个问题了。

1 个赞

谢谢。动作好快。

不过string-truncate-left也是28里才有的。

(use-package s
  :commands (s-replace s-truncate)
  :config
  (defalias 'string-replace #'s-replace)
  (defun string-truncate-left (string length)
    (s-truncate length string "...")
  ))

这么粗暴的定义也可以~

@DogLooksGood 我大概明白meow的逻辑了,在编辑的时候确实很舒服,赞! 另外有一个问题,你在可见范围内跳转的时候是怎么操作的?有用类似easymotion的方案吗?

有几种方式,看情况

  1. 如果有 block 结构的话,用 block 或是 beginning-of-thing 或 end-of-thing 是比较方便的。
  2. 最通用的就是用 findtill 后面追加数字,比如到一个 n 的后面可以 fn,然后假如你看到要去的 n 是最浅色的 2,那就是说明是第 22 个 n,这时就 200(对应函数是 meow-expand-* ,200 相当于 2 + 10 + 10),这就算是类似 avy 的对应随机位置随机字符的情况。
  3. next/back-wordnext/back-symbol 之类的,然后同上的方式追数字过去,这就算是类似 avy 的按词跳的情况。
  4. 如果要跳相似的词或符号的话,用 mark-wordmark-symbol ,然后用 search 就可以过去了。

今天有几个提交为了加 meow-search 显示计数的功能,影响到 meow-expand-* 函数了,刚才修复了。以后我还是要拉个 branch 出来稳一些。

1 个赞

@DogLooksGood string-truncate-left也是28特有的,也需要用s.el里的替换掉

好的,看来 28 对字符串的函数优化了很多。


改好了,还有个问题就是 s-replace 是 case-insensitive 的,需要指定 case-fold-search 才行。

我是evil用户,由于大量配置,一时没法切换到meow,不过我有个想法,为了解放双手,我自定义了这个函数(我使用的是Colemak,本人小白,勿喷):

(defun spring/arg-with-middle-keyboard (&optional msg)
  "A function which make you can use the middle of the keyboard instead of the num keyboard."
  (interactive)
  (let ((number "")
        (arg ""))
    (while (not (string= number "over"))
      (setq number
            (pcase (read-char)
              (97 "1") (114 "2") (115 "3") (116 "4") (100 "5")
              (104 "6") (110 "7") (101 "8") (105 "9") (111 "0")
              (39 "-") (13 "over") (127 "delete")))
      (unless (string= number "over")
        (if (string= number "delete")
            (setq arg (substring arg 0 -1))
          (setq arg (concat arg number))))
      (message "%s%s" (if msg
                          msg
                        "C-")
               arg))
    (string-to-number arg)))

这里使用键盘最中间来代替数字按键,个人用着感觉不错,目前用来多行移动和使用digit-argument

1 个赞

是的,evil 用户一定会有非常大量的关于插件整合方面的配置,我之前用 evil 的时候因为没有用 spacemacs,那会也不知道有没有 doom,感觉配置中的一半都是在配 evil 和 evil-leader。

你这个函数不错,可以在一个不是数字的按键上指定一个 digit-argument,我要回头参照着在 Meow 里面也加一个。

这点很真实,之前给我用Vim的朋友介绍Evil的时候,他看到了我的配置后也是这么吐槽的。

这个函数我原先是看到了B站一个Vim用户的配置后恍然大悟然后实现的,目前我使用了一段时间,体验很好,这个拿来做多行移动也很不错。

不过这样的话,不就少了很多键来放其它的命令了吗?我感觉 vim 当中是有几个相对闲置的 key,不过应该凑不出 9 个吧?

「移动即选择」如何调整选区范围?

以 kakoune (刚好以前有安装)为例。

当我按 5W 之后发现需要做些修正,按 W 扩展选区至下一个单词。假如我估算失误比较严重,就需要连续按多个 W 来修正,感觉比 vim 的 v5wwww... 更吃力一些。

假如我只需再多选几个字符,按 LLL...,也比 vim 的 v5wlll... 需要按更多的键。

是我操作不对吗?

这里 kakoune 和 meow 选择的是完全不同的思路。

kakoune 中的选择是没有类型的,也就是只要选了之后,如果不对的话,总是可以继续选的。

meow 是一开始你就奔着目标位置的特点按键,比如说你要去的位置

  • 是个词的末尾,你会按 w (假定是 meow-next-word)
  • 是随机的一个中间位字符,你可能就需要 f (假定是 meow-find)

之后靠追加数字(meow-expand-*)总是可以到你要到的位置,如果错了可以继续补或是用 meow-pop-selection undo 一次选择。

之所以 5w 容易出问题是因为什么提示都没有的情况下,数几个词是很难的,Vim 里面除了相对行号的情况,w, f, t, e, b 这些都很难数的出来。我以前用 vim 的时候经常 f, 之后发现要去的位置原来前面还有逗号,就很蠢。

在 meow 里面你可以直接移动到第 比如说 23 词后,没有难度。可以理解为 meow 的移动更像是 avy 的方式。当然 meow 里面前缀 digit-argument 的方式也可以用。一般来说 digit-argument 绑在 SPC 1 这样的按键上,只有第一下用按 SPC。而直接的数字就对应 meow-expand-{0-9} 这一组命令。

1 个赞

我的方案如下:

(defun spring/evil-digit-argument (arg)
  "The digit argument function."
  (interactive (list (spring/arg-with-middle-keyboard)))
  (prefix-command-preserve-state)
  (setq prefix-arg arg)
  (universal-argument--mode))

(set-movement-evil-states-keys (kbd "SPC") 'spring/evil-digit-argument)
;; (set-movement-evil-states-keys) 是我定义的函数

这样只需要按一下空格,然后输入中间的字母,最后回车即可。

1 个赞

录了一个演示的视频,可能后面需要整个更完善的版本。

2 个赞

这里面的 after! 是不是 doom-emacs 特有的宏?


我加了个函数 (meow-setup-indicator) 直接在 mode-line 前面插入 meow 的状态指示器,不过在 doom-mode-line 下面好像不是很好用,所以把你的那段代码加到了 README 里面,写是针对 doom-emacs 的。

(defmacro after! (package &rest body)
  "Evaluate BODY after PACKAGE have loaded.

PACKAGE is a symbol or list of them. These are package names, not modes,
functions or variables. It can be:

- An unquoted package symbol (the name of a package)
    (after! helm BODY...)
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
  and git-gutter have loaded)
    (after! (magit git-gutter) BODY...)
- An unquoted, nested list of compound package lists, using any combination of
  :or/:any and :and/:all
    (after! (:or package-a package-b ...)  BODY...)
    (after! (:and package-a package-b ...) BODY...)
    (after! (:and package-a (:or package-b package-c) ...) BODY...)
  Without :or/:any/:and/:all, :and/:all are implied.

This is a wrapper around `eval-after-load' that:

1. Suppresses warnings for disabled packages at compile-time
2. Supports compound package statements (see below)
3. Prevents eager expansion pulling in autoloaded macros all at once"
  (declare (indent defun) (debug t))
  (if (symbolp package)
        (list (if (or (not (bound-and-true-p byte-compile-current-file))
                      (require package nil 'noerror))
                  #'progn
                #'with-no-warnings)
              (let ((body (macroexp-progn body)))
                `(if (featurep ',package)
                     ,body
                   ;; We intentionally avoid `with-eval-after-load' to prevent
                   ;; eager macro expansion from pulling (or failing to pull) in
                   ;; autoloaded macros/packages.
                   (eval-after-load ',package ',body))))
    (let ((p (car package)))
      (cond ((not (keywordp p))
             `(after! (:and ,@package) ,@body))
            ((memq p '(:or :any))
             (macroexp-progn
              (cl-loop for next in (cdr package)
                       collect `(after! ,next ,@body))))
            ((memq p '(:and :all))
             (dolist (next (cdr package))
               (setq body `((after! ,next ,@body))))
             (car body))))))