ChatGPT解决这个技术问题 Extra ChatGPT

邪恶模式最佳实践? [关闭]

关闭。这个问题是基于意见的。它目前不接受答案。想改进这个问题?更新问题,以便可以通过编辑这篇文章用事实和引用来回答它。 6年前关闭。改进这个问题

多年来,我一直使用 Vim 作为我的主要编辑器,并在那段时间多次尝试 Emacs。然后我发现了 Evil,并认为它可以很好地满足我对快速移动的需求,因此我最终可以继续使用 Emacs。

那么,对于所有 Evil 用户,您如何将它与正常的 Emacs 功能集成呢?你有没有遇到过这种模式和其他模式的冲突?你在这个话题上有什么值得分享的经验/技巧?


C
Christopher Bottoms

我使用了高度定制的 vim,现在使用了更加定制的 emacs。我想您会在我的键映射配置文件 https://github.com/mbriggs/.emacs.d-oldv2/blob/master/init/init-keymaps.el 中找到每个键映射实例

请记住,我正在重新绑定真正的 emacs 用户会认为是异端的东西,所以 YMMV 如果你想学习“真正的”emacs(我真的不想)。

我会向任何前任推荐人推荐的一件事是

;;; esc quits
(defun minibuffer-keyboard-quit ()
  "Abort recursive edit.
In Delete Selection mode, if the mark is active, just deactivate it;
then it takes a second \\[keyboard-quit] to abort the minibuffer."
  (interactive)
  (if (and delete-selection-mode transient-mark-mode mark-active)
      (setq deactivate-mark  t)
    (when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
    (abort-recursive-edit)))
(define-key evil-normal-state-map [escape] 'keyboard-quit)
(define-key evil-visual-state-map [escape] 'keyboard-quit)
(define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)

这样 esc 实际上会退出几乎所有内容(例如迷你缓冲区中的待处理提示)


minibuffer-keyboard-quit 的定义可以在这里找到:github.com/davvil/.emacs.d/blob/master/init.el
@Adam 对此感到抱歉>。> 我安装了很多东西,有时我使用我认为是内置的功能,但实际上来自其他地方
我发现这对我不起作用。我使用的是最新的 Emacs 24.4,有人有同样的经历吗?
链接已损坏。我相信这是新的:github.com/mbriggs/.emacs.d/blob/master/config/keybinds.el
@SeanLeather 更新了工作链接的答案。
R
RussellStewart

作为一个来自 emacs 的人,尝试过 vim,并意识到有很多东西可以得到,当我第一次开始使用 evil 时,我做了很多实验。虽然以下内容存在争议,但我想保留在终端、firefox、cocoa 等中更普遍使用的 emacs 键,但又不想失去 vim 编辑功能。我最终决定在我的 .emacs 中重新绑定以下键:

(define-key evil-normal-state-map "\C-e" 'evil-end-of-line)
(define-key evil-insert-state-map "\C-e" 'end-of-line)
(define-key evil-visual-state-map "\C-e" 'evil-end-of-line)
(define-key evil-motion-state-map "\C-e" 'evil-end-of-line)
(define-key evil-normal-state-map "\C-f" 'evil-forward-char)
(define-key evil-insert-state-map "\C-f" 'evil-forward-char)
(define-key evil-insert-state-map "\C-f" 'evil-forward-char)
(define-key evil-normal-state-map "\C-b" 'evil-backward-char)
(define-key evil-insert-state-map "\C-b" 'evil-backward-char)
(define-key evil-visual-state-map "\C-b" 'evil-backward-char)
(define-key evil-normal-state-map "\C-d" 'evil-delete-char)
(define-key evil-insert-state-map "\C-d" 'evil-delete-char)
(define-key evil-visual-state-map "\C-d" 'evil-delete-char)
(define-key evil-normal-state-map "\C-n" 'evil-next-line)
(define-key evil-insert-state-map "\C-n" 'evil-next-line)
(define-key evil-visual-state-map "\C-n" 'evil-next-line)
(define-key evil-normal-state-map "\C-p" 'evil-previous-line)
(define-key evil-insert-state-map "\C-p" 'evil-previous-line)
(define-key evil-visual-state-map "\C-p" 'evil-previous-line)
(define-key evil-normal-state-map "\C-w" 'evil-delete)
(define-key evil-insert-state-map "\C-w" 'evil-delete)
(define-key evil-visual-state-map "\C-w" 'evil-delete)
(define-key evil-normal-state-map "\C-y" 'yank)
(define-key evil-insert-state-map "\C-y" 'yank)
(define-key evil-visual-state-map "\C-y" 'yank)
(define-key evil-normal-state-map "\C-k" 'kill-line)
(define-key evil-insert-state-map "\C-k" 'kill-line)
(define-key evil-visual-state-map "\C-k" 'kill-line)
(define-key evil-normal-state-map "Q" 'call-last-kbd-macro)
(define-key evil-visual-state-map "Q" 'call-last-kbd-macro)
(define-key evil-normal-state-map (kbd "TAB") 'evil-undefine)

(defun evil-undefine ()
 (interactive)
 (let (evil-mode-map-alist)
   (call-interactively (key-binding (this-command-keys)))))

不幸的是,这些与 vim 的“向上或向下移动一屏”操作重叠。但是,我已经习惯使用以下内容:

(define-key evil-normal-state-map (kbd "DEL") (lambda ()
                    (interactive)
                    (previous-line 10)
                    (evil-scroll-line-up 10)
                    ))

(define-key evil-normal-state-map (kbd "=") (lambda ()
                      (interactive)
                      (next-line 10)
                      (evil-scroll-line-down 10)
                      ))

此外,如果您来自 vim 并希望使用“jk”(或任何其他 2 笔画组合)快速从插入模式到正常模式,最好的方法是从 http://www.emacswiki.org/emacs/download/key-chord.el 复制文本并将其粘贴到您的 ~/ .emacs.d/key-chord.el 。然后将以下内容添加到您的 .emacs 中:

;load a file named key-chord.el from some directory in the load-path (e.g. "~/.emacs.d")
(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "jk" 'evil-normal-state)

此外,如果您来自 vim,并且您认为 emacs 中的复制到剪贴板不好,那么您可能是对的。但是,在运行 sudo apt-get install xsel 后,您可能会发现以下内容很有用:

(defun copy-to-clipboard ()
  (interactive)
  (if (display-graphic-p)
      (progn
        (message "Yanked region to x-clipboard!")
        (call-interactively 'clipboard-kill-ring-save)
        )
    (if (region-active-p)
        (progn
          (shell-command-on-region (region-beginning) (region-end) "xsel -i -b")
          (message "Yanked region to clipboard!")
          (deactivate-mark))
      (message "No region active; can't yank to clipboard!")))
  )

(evil-define-command paste-from-clipboard()
  (if (display-graphic-p)
      (progn
        (clipboard-yank)
        (message "graphics active")
        )
    (insert (shell-command-to-string "xsel -o -b"))
    )
  )

(global-set-key [f8] 'copy-to-clipboard)
(global-set-key [f9] 'paste-from-clipboard)

显然,您必须自己决定这些有争议的更改是否值得,但也许这些基本更改会激发您的灵感。

对于其他一些非常酷的功能实现,例如删除和粘贴、删除而不复制到剪贴板、高效的 4x / 16x 移动、粘贴寄存器规范使用计数、实际适用于 c/c++ 的选项卡设置等等,您可以查看在 https://github.com/Russell91/emacs 的我的 git 上输出完整的 .emacs、init.el、my-keymaps.el 和 my-functions.el 版本


这一切都很棒,我在 wikemacs 中添加了一些:wikemacs.org/index.php/Evil#Configuration
我理解您重用 emacs 习惯的意愿。对于在 Firefox 中工作,我强烈建议尝试 Vimperator 插件,它为您的浏览带来了许多类似 vim 的功能。但是,它默认使用 vim 移动命令(例如 less 命令和其他命令)。
和你一样,我不喜欢 insert-state-mode 中的 evil 绑定,所以我只是将 normal-state-map 中的 "i" 重新绑定到 'evil-emacs-state.
我没有覆盖 evil 的键盘,而是将其删除,因此它回退到普通 emacs 的键盘设置,例如 (dolist (m (list evil-normal-state-map evil-motion-state-map evil-insert-state-map)) (define-key m "\C-e" 'nil))
K
Kenny Meyer

我也曾经是一个 Viper/Vimpulse 用户,有大量的配置。然后我找到了邪恶模式。

你在这个话题上有什么值得分享的经验/技巧?

这是我的整个邪恶模式配置,它对我很有用:

(require 'evil)
(evil-mode 1)

;; Remap org-mode meta keys for convenience
(mapcar (lambda (state)
    (evil-declare-key state org-mode-map
      (kbd "M-l") 'org-metaright
      (kbd "M-h") 'org-metaleft
      (kbd "M-k") 'org-metaup
      (kbd "M-j") 'org-metadown
      (kbd "M-L") 'org-shiftmetaright
      (kbd "M-H") 'org-shiftmetaleft
      (kbd "M-K") 'org-shiftmetaup
      (kbd "M-J") 'org-shiftmetadown))
  '(normal insert))

你有没有遇到过这种模式和其他模式的冲突?

不,与 Viper/Vimpulse 不同,Viper/Vimpulse 在几种模式下都会造成麻烦。


我收到此错误: progn: Symbol's value as variable is void: state 状态定义在哪里?
你可以试试evil-emacs-state
你能澄清你把它放在哪里吗?
这太棒了,我正是在寻找这个。点赞数不胜数!
d
dennis

一个月前我开始使用 Evil;在此之前,我尝试使用 viper/vimpulse,但没有取得多大成功。老实说,vimpulse 相当不错,但是在各种模式下使用它有点麻烦(例如,vimpulse 总是发疯的编译模式)让 emacs 在 vi-emacs-something 之间处于某种模式。

当我切换到 Evil 时,我终于开始探索 Emacs 的全部功能,相信我,我没有后悔。 Evil 在我使用的所有模式(主要是编辑、编译、scratch 和 eshell)下都能很好地工作,甚至阅读 info/man/help 也没有任何问题。

除此之外,我只发现缓冲区切换奇怪,就像我以前做的那样:b<0-9> 而不是 :b-TAB-then-complete-name 或 :bn。但是请注意,Evil 开发人员会尝试(在某些情况下)减少重复功能,因此 :! (执行 shell 命令),你应该使用原生 M-!。

如果您想添加/重新定义一些自定义 ex 命令,只需打开 evil-maps.el 并编辑它(在 vim 中尝试!)。

Evil 仍然是一个年轻但有前途的项目,我正在等待在官方 Emacs 发行版中取代 viper 的那一天。


这是否意味着无法在 vim 中添加/重新定义命令?
@JohnTyree 用户定义的命令在 Vim 中必须以大写字母开头,而所有内置命令都以小写字母开头。
E
Ehvince

我喜欢在退出 insert-mode 时保存缓冲区:(已编辑:当此缓冲区没有关联文件时不要求保存,例如在临时缓冲区或 magit 缓冲区中时)

(defun my-save ()
  (if (buffer-file-name)
    (evil-save))
)

   (add-hook 'evil-insert-state-exit-hook 'my-save)

更多可能性:参见http://wikemacs.org/index.php/Evil

欢迎评论改进!


谢谢。顺便说一句,您的链接已损坏。
也谢谢你。 Wikemacs 会回来的。该网站正在维护中,希望不会再维持太久。
C
Community

我使用 evil-leader 并使用 ",xm" 代替 "Mx",所以我很少按 Alt 键。还有支持多个领导密钥的general.el。 evil-matchit,按“%”在标签对之间跳转。 evil-nerd-commenter,按“9,ci”注释/取消注释 9 行避免使用 ESC 键,您可以按“kj”代替。对自由软件有信心! Evil 结合了 Vim 和 Emacs 的强大功能,没有什么是不可能的。例如,许多人认为 Evil 键绑定与现有插件 Emacs 冲突,而无需大量重新绑定。这实际上是错误的


u
unhammer

来自emacs方面,我非常喜欢M-。要定义,但在 M-. 上运行的函数因模式而异。我可以用 (define-key evil-normal-state-map (kbd "M-.") 'foo) 以常规方式覆盖它,其中 foo 检查当前的主要模式并运行适当的功能,但这听起来需要大量的硬编码。一个更通用的解决方案是:

(defun evil-emacs-key-binding (key)
  (evil-execute-in-emacs-state)
  (key-binding key))

(defmacro evil-revert-key-binding (state-map key)
  `(define-key ,state-map ,key (lambda ()
                                 (interactive)
                                 (call-interactively
                                  (evil-emacs-key-binding ,key)))))

(eval-after-load "evil-autoloads"
  '(add-hook 'evil-after-load-hook
        (lambda ()
          (evil-revert-key-binding evil-normal-state-map (kbd "M-."))
          ;; and so on
        )))

除此之外,我喜欢插件 evil-surround(虽然我觉得 smartparens 是一个更完整的解决方案)和 evil-leader

我曾经使用 key-chord 将 jk 映射到 ESC,就像我在 vim 中学到的那样,但它坚持将 kj 与 jk 相同,所以我使用以下内容:

(defun evil-escape-if-next-char (trigger)
  "Watches the next letter. If `trigger', then switch to normal mode,
otherwise keep the previously inserted key and forward unpressed
key to `unread-command-events'."
  (self-insert-command 1)
  (let ((next-key (read-event)))
    (if (eq trigger next-key)
        (progn
          (delete-char -1)
          (evil-normal-state))
      (setq unread-command-events (cons next-key unread-command-events)))))

(defun evil-escape-if-next-char-is-k (arg)
  (interactive "p")
  (if (= arg 1)
      (evil-escape-if-next-char ?k)
    (self-insert-command arg)))

(eval-after-load "evil-autoloads"
  '(add-hook 'evil-after-load-hook
             (lambda ()
               ;; … other stuff …
               (define-key evil-insert-state-map (kbd "j") 'evil-escape-if-next-char-is-k))))

我使用的 (setq evil-move-cursor-back nil) 不是很灵活(尽管显然你可以让你的 vimrc 也这样做),我只是不习惯退出插入后光标向后移动。

实用提示:将 evil-local-mode-hook 用于延迟加载 evil-surround-mode 之类的东西,将它放在简单的 evil-mode-hook 中无济于事。因此,如果您使用 package-install 安装 evil 和 evil-surround,您可以在执行 M-x evil-mode 时启动它

(eval-after-load "evil-surround-autoloads"
  '(add-hook 'evil-local-mode-hook #'evil-surround-mode))

(当然,如果你总是运行 evil-mode 并且总是安装 evil,则不需要那些自动加载的东西,但我更喜欢让我的 .emacs 足够通用,以便我可以在带有旧 emacsen 或没有任何 emacsen 的机器上使用它elpa 软件包已安装。)


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅