我也说说Emacs吧(5) - 基本编辑操作
基本编辑操作
进入编辑模式
标准的emacs用户是遇不到这一节的,因为默认就可以编辑。但是spacemacs用户需要先学习一下强大的vi的模式切换功能了。
vi的一个重要特点就是命令特别多,所以一旦学会了效率就非常高。
我们以进入编辑模式为说明一下,大家就清楚了。
有同学说了,切换到编辑模式,只用一条命令,比如i命令,切过去就是了么。从功能上说,是这样的。但是,这样的效率还不够高。
vi中是这样的定义的:
* i:在当前光标之前插入文本
* a: 在当前光标之后插入文本
* A: 在当前行的结尾处插入文本
* I: 在当前行的开始处插入文本
* o: 在光标位置的下一行加一个新行插入文本
* O: 在光标位置的上一行加一个新行插入文本
* s: 删除光标所在位置的字符,再进行插入
* S: 删除光标所在行,再进行插入
* R: 用新的字符替换现有的字符
在evil的实现中,i对应的是evil-insert函数:
(defun evil-insert (count &optional vcount skip-empty-lines)
(interactive
(list (prefix-numeric-value current-prefix-arg)
(and (evil-visual-state-p)
(memq (evil-visual-type) '(line block))
(save-excursion
(let ((m (mark)))
;; go to upper-left corner temporarily so
;; `count-lines' yields accurate results
(evil-visual-rotate 'upper-left)
(prog1 (count-lines evil-visual-beginning evil-visual-end)
(set-mark m)))))
(evil-visual-state-p)))
(if (and (called-interactively-p 'any)
(evil-visual-state-p))
(cond
((eq (evil-visual-type) 'line)
(evil-visual-rotate 'upper-left)
(evil-insert-line count vcount))
((eq (evil-visual-type) 'block)
(let ((column (min (evil-column evil-visual-beginning)
(evil-column evil-visual-end))))
(evil-visual-rotate 'upper-left)
(move-to-column column t)
(evil-insert count vcount skip-empty-lines)))
(t
(evil-visual-rotate 'upper-left)
(evil-insert count vcount skip-empty-lines)))
(setq evil-insert-count count
evil-insert-lines nil
evil-insert-vcount (and vcount
(> vcount 1)
(list (line-number-at-pos)
(current-column)
vcount))
evil-insert-skip-empty-lines skip-empty-lines)
(evil-insert-state 1)))
a绑定的是evil-append
A绑定evil-append-line
I绑定evil-insert-line
o绑定evil-open-below
O绑定evil-open-above
s绑定evil-substitute
S绑定evil-change-whole-line
R绑定的是evil-replace-state
从编辑模式退回普通模式的命令的Esc.
标准emacs下的编辑命令
删除一个字符
Del 删除上一个字符,对应delete-forward-char函数。
C-d (delete-char) 删除光标位置字符,不过这个绑定在spacemacs中不支持。
在spacemacs中的正常模式下,可以使用vi的x命令来删除当前字符,函数是evil-delete-char.
(evil-define-operator evil-delete-char (beg end type register)
:motion evil-forward-char
(interactive "<R><x>")
(evil-delete beg end type register))
删除一行
下面我们学习emacs中非常有趣的一个功能。
在vi中,删除一行非常容易,一条命令dd就可以了。
但是emacs不会这样的,要想删除一行,需要三个命令C-a C-k C-k,哈哈
C-k绑定的命令是kill-line,它的作用是,删除光标至行尾的所有内容,但是不包括换行符。删除掉这个空行需要再执行一次kill-line.
如果要删除从光标开始到行首的命令的话,我们可以使用kill-line的负命令,就是把负号做为参数传给kill-line. 方法是调用negative-argument函数,它绑定的键特别多,有C–, A–, C-A–,反正跟减号的组合都是它就是了。
(defun negative-argument (arg)
"Begin a negative numeric argument for the next command.
\\[universal-argument] following digits or minus sign ends the argument."
(interactive "P")
(prefix-command-preserve-state)
(setq prefix-arg (cond ((integerp arg) (- arg))
((eq arg '-) nil)
(t '-)))
(universal-argument--mode))
剪切,复制和粘贴
文本区域的选择
要想做剪切和复制,第一步要先做文本区域的选择。
在想要选择的文本区域的头部,使用set-mark-command函数来设置标记:
(defun set-mark-command (arg)
(interactive "P")
(cond ((eq transient-mark-mode 'lambda)
(kill-local-variable 'transient-mark-mode))
((eq (car-safe transient-mark-mode) 'only)
(deactivate-mark)))
(cond
((and (consp arg) (> (prefix-numeric-value arg) 4))
(push-mark-command nil))
((not (eq this-command 'set-mark-command))
(if arg
(pop-to-mark-command)
(push-mark-command t)))
((and set-mark-command-repeat-pop
(eq last-command 'pop-global-mark)
(not arg))
(setq this-command 'pop-global-mark)
(pop-global-mark))
((or (and set-mark-command-repeat-pop
(eq last-command 'pop-to-mark-command))
arg)
(setq this-command 'pop-to-mark-command)
(pop-to-mark-command))
((eq last-command 'set-mark-command)
(if (region-active-p)
(progn
(deactivate-mark)
(message "Mark deactivated"))
(activate-mark)
(message "Mark activated")))
(t
(push-mark-command nil))))
set-mark-command绑定在Ctrl-@和Ctrl-空格上。不管是Windows还是MacOS,Ctrl-空格都已被操作系统征用了,可以用C-@,不过这个键确实是不好用,需要按Ctrl-Shift-2。
设置了标记之后,将光标移至要选择的结尾就可以了。
如果想确认下标记的位置,可以用exchange-point-and-mark函数,快捷键C-x C-x.
剪切
选中文本块之后,就可以将其删除kill-region,然后再到新的位置通过yank命令粘贴出来就好。删除之后,删除的结果会存到删除环中。
在标准emacs下,kill-region绑定在C-w上,但是spacemacs下不支持。可以使用Shift-Delete组合。yank在标准emacs上绑定在C-y上,spacemacs下也不支持,但是可以使用Shift-Insert.
spacemacs是个土洋结合的系统,使用emacs的方式选中文本区域之后,可以使用vi的d命令达到同样的剪切效果,函数是evil-delete。
不选中文本块,只删除一行的话,命令是dd。
(evil-define-operator evil-delete (beg end type register yank-handler)
(interactive "<R><x><y>")
(unless register
(let ((text (filter-buffer-substring beg end)))
(unless (string-match-p "\n" text)
;; set the small delete register
(evil-set-register ?- text))))
(let ((evil-was-yanked-without-register nil))
(evil-yank beg end type register yank-handler))
(cond
((eq type 'block)
(evil-apply-on-block #'delete-region beg end nil))
((and (eq type 'line)
(= end (point-max))
(or (= beg end)
(/= (char-before end) ?\n))
(/= beg (point-min))
(= (char-before beg) ?\n))
(delete-region (1- beg) end))
(t
(delete-region beg end)))
;; place cursor on beginning of line
(when (and (called-interactively-p 'any)
(eq type 'line))
(evil-first-non-blank)))
复制
复制也是先选中文本区域,然后使用kill-ring-save函数将其复制到删除环中,最后还是通过yank命令粘贴。它绑定的键是A-w,在spacemacs中仍然有效。
也可以使用vi中的y命令,达到同样的效果,函数是evil-yank. 有没有觉得用y键比A-w键要舒服一些?
(evil-define-operator evil-yank (beg end type register yank-handler)
"Saves the characters in motion into the kill-ring."
:move-point nil
:repeat nil
(interactive "<R><x><y>")
(let ((evil-was-yanked-without-register
(and evil-was-yanked-without-register (not register))))
(cond
((and (fboundp 'cua--global-mark-active)
(fboundp 'cua-copy-region-to-global-mark)
(cua--global-mark-active))
(cua-copy-region-to-global-mark beg end))
((eq type 'block)
(evil-yank-rectangle beg end register yank-handler))
((eq type 'line)
(evil-yank-lines beg end register yank-handler))
(t
(evil-yank-characters beg end register yank-handler)))))
如果要复制一行的话,命令是yy.
vi中的粘贴命令是p,函数是evil-paste-after
(evil-define-command evil-paste-after
(count &optional register yank-handler)
"Pastes the latest yanked text behind point.
The return value is the yanked text."
:suppress-operator t
(interactive "P<x>")
(if (evil-visual-state-p)
(evil-visual-paste count register)
(evil-with-undo
(let* ((text (if register
(evil-get-register register)
(current-kill 0)))
(yank-handler (or yank-handler
(when (stringp text)
(car-safe (get-text-property
0 'yank-handler text)))))
(opoint (point)))
(when text
(if (functionp yank-handler)
(let ((evil-paste-count count)
;; for non-interactive use
(this-command #'evil-paste-after))
(insert-for-yank text))
;; no yank-handler, default
(when (vectorp text)
(setq text (evil-vector-to-string text)))
(set-text-properties 0 (length text) nil text)
(unless (eolp) (forward-char))
(push-mark (point) t)
;; TODO: Perhaps it is better to collect a list of all
;; (point . mark) pairs to undo the yanking for COUNT > 1.
;; The reason is that this yanking could very well use
;; `yank-handler'.
(let ((beg (point)))
(dotimes (i (or count 1))
(insert-for-yank text))
(setq evil-last-paste
(list #'evil-paste-after
count
opoint
beg ; beg
(point))) ; end
(evil-set-marker ?\[ beg)
(evil-set-marker ?\] (1- (point)))
(when (evil-normal-state-p)
(evil-move-cursor-back)))))
(when register
(setq evil-last-paste nil))
(and (> (length text) 0) text)))))
p是粘贴到当前光标后,如果要粘贴到当前光标前的话,命令是P,函数是evil-paste-before.
从删除环中获取更早的结果
删除环不只会保存上一次的结果,如果想要更早的结果,可以通过yank-pop函数来获取。
vi移动光标方式的补充
上一讲讲过,可以在正常模式下通过使用0来移动到行首。但是,有时候我们希望跳过行首第一个不是空白符的位置,这时候,就要用”^”命令,函数是evil-first-non-blank.
(evil-define-motion evil-first-non-blank ()
"Move the cursor to the first non-blank character of the current line."
:type exclusive
(evil-narrow-to-line (back-to-indentation)))
vi括号匹配
vi中的%命令,可以匹配跟当前括号配对的另一半括号,函数是evil-jump-item.
vi重复做上一条命令
“.”可以执行上一条命令,函数是evil-repeat.
(evil-define-command evil-repeat (count &optional save-point)
"Repeat the last editing command with count replaced by COUNT.
If SAVE-POINT is non-nil, do not move point."
:repeat ignore
:suppress-operator t
(interactive (list current-prefix-arg
(not evil-repeat-move-cursor)))
(cond
((null evil-repeat-ring)
(error "Already executing repeat"))
(save-point
(save-excursion
(evil-repeat count)))
(t
(unwind-protect
(let ((confirm-kill-emacs t)
(kill-buffer-hook
(cons #'(lambda ()
(user-error "Cannot delete buffer in repeat command"))
kill-buffer-hook))
(undo-pointer buffer-undo-list))
(evil-with-single-undo
(setq evil-last-repeat (list (point) count undo-pointer))
(evil-execute-repeat-info-with-count
count (ring-ref evil-repeat-ring 0))))
(evil-normal-state)))))
小结
功能 | 函数 | 键绑定 | leader key |
---|---|---|---|
删除光标处字符 | delete-char | 无 | 无 |
evil-delete-char | x | 无 | |
删除光标至行尾 | kill-line | C-k | 无 |
传递负参数 | negative-argument | C–, A–, C-A– | 无 |
设置文本块开始标记 | set-mark-command | C-@ | 无 |
交换光标与文本标记 | exchange-point-and-mark | C-x C-x | 无 |
剪切文本块到删除环 | kill-region | Shift-Delete | 无 |
evil-delete | d | 无 | |
复制文本块到删除环 | kill-ring-save | A-w | 无 |
evil-yank | y | 无 | |
从删除环中弹出,即粘贴 | yank | Shift-Insert | 无 |
evil-paste-after | p | 无 | |
evil-paste-before | P | 无 | |
从删除环中弹出更早的结果 | yank-pop | 无 | 无 |
移至行首第一个非空白符 | evil-first-non-blank | ^ | 无 |
匹配下一个可配对的括号 | evil-jump-item | % | 无 |
再次执行上一次执行的命令 | evil-repeat | . | 无 |
我也说说Emacs吧(5) - 基本编辑操作的更多相关文章
- Emacs学习心得之 基础操作
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Emacs学习心得之 基础操作 1.前言与学习计划2.Emacs基础操作 一. 前言与学习计 ...
- Html简单demo_html列表中进行编辑操作
html列表中进行编辑操作 <div class="_sort_box" style="float: left;"><?php echo $v ...
- linux --> VIM的列编辑操作
VIM的列编辑操作 一.删除列 1.光标定位到要操作的地方. 2.CTRL+v 进入“可视 块”模式,选取这一列操作多少行. 3.d 删除. 二.插入列 插入操作的话知识稍有区别.例如在每一行 ...
- Asp.Net MVC +EntityFramework主从表新增编辑操作的实现(删除操作怎么实现?)
Asp.Net MVC +EntityFramework主从表新增编辑操作的实现 对于MVC中同时对主从表的表单操作在网上现有的解决很少,而这样的操作在做业务系统中是经常为遇到的.我在网上搜索了很久都 ...
- 【vim】插入模式与常用编辑操作
vim不像很多编辑器那样一启动便可以直接编辑文本,需要在普通模式按下i, a等键才会进入插入模式进行文本编辑. 如何进入插入模式 以下的命令都会让vim从普通模式切换到插入模式,但命令执行后的字符插入 ...
- 【Linux学习】Vi / Vim编辑器—编辑器工作模式、vi编辑操作
Vi / Vim编辑器-编辑器工作模式.vi编辑操作 推荐一个很好的学习指南:http://www.oschina.net/translate/learn-vim-progressively 一.编辑 ...
- Web UI开发神器—Kendo UI for jQuery数据管理网格编辑操作
Kendo UI for jQuery最新试用版下载 Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support f ...
- jQqery EasyUI dategrid行中多列数据的可编辑操作
最近的项目中需要在前台dategrid列表中直接修改某些列的数据,并且修改后的数据需要不通过后台而自动更新在列表中. 带着这一问题开始寻找实现的思路,首先想到的就是去jQqery EasyUI官网找例 ...
- ao的编辑操作
自从10.0以后,ArcMap的编辑界面发生了变化,原本的“目标图层”和“编辑任务”不见了,取而代之的是“要素构造”窗口,里面融合了目标图层和编辑任务功能.查看sdk发现,多了几个接口,前面已经讲过. ...
随机推荐
- 20145328 《Java程序设计》第10周学习总结
20145328 <Java程序设计>第10周学习总结 资料学习内容总结 网络编程 13.1 网络概述 网络编程技术是当前一种主流的编程技术,随着联网趋势的逐步增强以及网络应用程序的大量出 ...
- 20145329《Java程序设计》第六周学习总结
教材学习内容总结 第十章 InputSream与OutputStream Java中,输入串流代表对象为java.io.InputStream实例,输出串流代表对象为java.io.OutputStr ...
- hadoop随手笔记
1.Hadoop Streaming 是为了方便不太熟悉java用户编写MR程序的工具.用户可以将任何可执行文件(C++)或者脚本(python,ruby)作为Mapper/Reducer, 提高了效 ...
- COGS 723. [SDOI2007] 超级数组
★★☆ 输入文件:arr.in 输出文件:arr.out 简单对比 时间限制:1 s 内存限制:3 MB Source: SDOI2007 Day2[问题描述] 一般的数组大家都经常 ...
- db2 xml 转 table
版本:DB2 Version 9.1 1.创建测试表,初始化数据 create table emp (doc XML); INSERT INTO EMP VALUES ('<dept bldg= ...
- Codeforces Round #365 (Div. 2) E - Mishka and Divisors(转化成01-背包)
http://codeforces.com/contest/703/problem/E 题意: 给出n个数和一个k,计算出至少要多少个数相乘才是k的倍数. 思路:这道题目参考了杭电大神的代码http: ...
- 一款简单易用的.Net 断言测试框架 : Shouldly
GitHub地址:https://github.com/shouldly/shouldly Shouldly的官方文档:http://docs.shouldly-lib.net/ Nuget安装: 在 ...
- shell基本认识
shell基本认识 bash # echo $BASH /bin/bash 第一个shell脚本first_shell.sh #!/bin/bash echo "Hello world!&q ...
- 从git获取项目代码
1.先复制项目的SSH链接备用 2.在你要放置项目的地方git bash here 3.按照以下步骤走: $ git clone YourSSHAddress // clone项目 $ ls // 查 ...
- 关于java.lang.Exception:No tests found matching的一系列解决方法
问题描述: java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=yahaa], {ExactMatcher ...