Emacs中与Vim的dd、o、O相对应的命令

28
我目前正在尝试使用emacs,大多数概念都很满意。但是我真的很喜欢三个vim命令提供的便利:dd、o、O。希望您可以告诉我如何在emacs中模仿这些命令 :)
- dd - 删除整行,包括换行符,不管光标在哪里。 针对此操作,我找到了类似的技巧:C-a C-k C-k。其中C-a将光标移动到行首,第一个C-k删除了文本,第二个C-k删除了换行符。唯一的问题是,在空行上这种方法无法实现,我只能输入C-k,这很麻烦,因为我必须为同一个任务使用不同的命令:删除一行。
- o/O - 在光标下方/上方创建一个新的空行,并将光标移动到新行,正确缩进。 C-a C-o与O几乎相同,只有缩进不同。C-e C-o在当前行下方创建一个空白行,但不移动光标。
是否有更好的解决方案来解决我的问题,或者我必须学习Lisp并定义新命令以满足我的需求?

我认为最好的换行方法是使用http://superuser.com/a/331661(C-e C-j) - Petr Gladkikh
9个回答

29

对于 oO,以下是我多年前编写的一些函数:

(defun vi-open-line-above ()
  "Insert a newline above the current line and put point at beginning."
  (interactive)
  (unless (bolp)
    (beginning-of-line))
  (newline)
  (forward-line -1)
  (indent-according-to-mode))

(defun vi-open-line-below ()
  "Insert a newline below the current line and put point at beginning."
  (interactive)
  (unless (eolp)
    (end-of-line))
  (newline-and-indent))

(defun vi-open-line (&optional abovep)
  "Insert a newline below the current line and put point at beginning.
With a prefix argument, insert a newline above the current line."
  (interactive "P")
  (if abovep
      (vi-open-line-above)
    (vi-open-line-below)))

你可以将vi-open-line绑定到M-insert,方法如下:
(define-key global-map [(meta insert)] 'vi-open-line)

对于dd命令,如果你想要删除的行保留在kill ring中,可以使用下面这个函数来包装kill-line

(defun kill-current-line (&optional n)
  (interactive "p")
  (save-excursion
    (beginning-of-line)
    (let ((kill-whole-line t))
      (kill-line n))))

为了完整性,它接受前缀参数并将其应用于kill-line,这样它就可以杀死比“当前”行更多的内容。

您还可以查看viper-mode的源代码,以了解它如何实现等效的ddoO命令。


哇,太棒了,谢谢。运行得非常好 :) 只是 vi-open-line-above 不会缩进。有任何想法吗? - ericteubert
1
我在 vi-open-line-above 函数的 (forward-line -1) 下面添加了 (indent-according-to-mode)。这样就可以解决问题啦 :) - ericteubert
有趣的是,当你注意到找到了解决方案时,我正在编辑它。正如你所看到的,这是我很少使用的旧代码。我在刚开始学习Emacs Lisp时编写了它。这个问题给了我一个理由来更新它。 - seh

25

2
如果你正在输入一行代码,按下 c+j 将会把光标后面的内容移到新的一行。这就像是在一行中间按下了 return 键。我们想要在当前光标位置下方添加一个空白行。 - pjammer

24

对于dd命令,最近版本的Emacs默认将其绑定到“C-S-backspace”的“kill-whole-line”功能上。

我应该补充说明,我自己更经常使用whole-line-or-region.el,因为使用C-wC-S-backspace更容易输入。


2

2
经过一番搜索和实验,我得出了以下结论,这些是替代方案:
  • Vim中的dd命令:Emacs中的C-S-backspace
  • Vim中的o命令:Emacs中的C-e C-j
  • Vim中的O命令:Emacs中的C-a C-j C-p
是的,有时候Emacs会使用一些“表达式”命令组合来完成某些事情,但它们有时确实很有意义!
而且如果你想一次选择整个文件中的文本,Vim需要输入ggVG,而在Emacs中只需输入C-x h

2
我知道,这个回答不是直截了当的,但像vim用户一样,我发现Spacemacs是最功能强大的emacs入门套件,用于从vim转到emacs。您可以将其配置为类似于vim、类似于emacs或混合模式。

http://spacemacs.org/

试一试。


1

以下是我解决了Emacs缺少类似vi命令中的“O”的问题的方法:

(defadvice open-line (around vi-style-open-line activate)
  "Make open-line behave more like vi."
  (beginning-of-line)
  ad-do-it
  (indent-according-to-mode))

有了这个功能,我从来没有真正感到需要一个相应版本的vi的“o”命令。C-n C-o就可以了。

至于“dd”命令,一开始我有点不适应,但最终我还是接受了Emacs的做法。无论如何,当我想要一次删除多行时(通常情况下),我只需使用区域(C-a C-SPC,转到我想要删除的文本的另一端,C-w)。或者如果我能够估算出我想要删除的行数,我会执行例如M-9 C-k以一次删除九行。


0

5
这句话听起来让我感到别扭。如果我想要使用vim,那么我就会使用vim而不是emacs。 - ericteubert
1
Emacs的按键绑定可能不太符合人体工程学,但至少对我来说,vi的模态****让我感到烦躁。 - Jürgen A. Erhard
1
@eteubert 一点也不尴尬。把emacs看作第三(或第四)种模式,一旦你掌握了emacs并且所有内容都在emacs中,它实际上会感觉很自然。 - mt3

0
这些都很棒。这里还有几个。

https://stable.melpa.org/#/crux https://github.com/bbatsov/crux

Crux不会映射任何按键绑定,它让你自己决定按键绑定,但以下是相关的功能建议的按键绑定,你可以按照建议进行设置,或者根据自己的需求进行更改。
Function:                   Keymap:     Description:
---------------------------------------------------------
crux-kill-whole-line        Super-k     Kill whole line
crux-smart-open-line-above  Super-O     Insert an empty line above & indent
crux-smart-open-line        Super-o     Insert an empty line and indent 

你当然可以使用其他的按键绑定,比如C-c o / M-c o或者其他对你个人有意义的按键绑定。请参考crux github上的说明。
另一种选择是考虑使用Doom Emacs,它默认安装并启用了Evil Mode。这样,你熟悉的99.999%的ViM按键绑定基本上都能以相同的方式工作。你也可以在原始的Emacs上手动安装Evil-Mode,并根据需要通过按键绑定来开启和关闭,或者利用一些小的eLisp代码将Evil-Mode与特定的缓冲区/文件类型关联起来。
我长期以来一直是Vi/ViM/Neovim的用户,最开始使用的是Doom。然而,最近我强迫自己学习按照Emacs的原意来使用它,我学到了更多东西。那些按键组合和默认绑定并没有我想象中那么糟糕。我的肌肉记忆很快就适应了。我只需启动Emacs,除了选择一个不错的主题、字体,禁用滚动条、工具栏和菜单栏,再添加which-key-mode和spacious-padding-mode。除此之外,我几乎没有做太多改动,只是安装了一些其他的包。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接