我也说说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发现,多了几个接口,前面已经讲过. ...
随机推荐
- 关于Java -cp引用jar是否支持通配符
其实是支持的: JDK6支持java -cp后面跟通配符'*',试了一下发现还是需要注意: 错误方式(Wrong way): java -cp /data/apps/lib/*.jar com.ch ...
- 爬虫之动态HTML处理(Selenium与PhantomJS )动态页面模拟点击
动态页面模拟点击 #!/usr/bin/env python # -*- coding:utf-8 -*- # python的测试模块 import unittest from selenium im ...
- QT 样式表基础知识
1. 何为Qt样式表2. 样式表语法基础3. 方箱模型4. 前景与背景5. 创建可缩放样式6. 控制大小7. 处理伪状态8. 使用子部件定义微观样式 8.1. 相对定位 8.2. 绝对定位 摘要 ...
- htop 比top更好用的top
安装 sudo apt-get install htop 使用 htop
- 【Python】“UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9”根因及解决方法
背景 自动化测试调用HTMLTestRunner生成测试报告的时候,出现了编码错误,错误如题 原因 搜索了很多资料,得出的结论是python的str默认是ascii编码,和unicode编码冲突,就会 ...
- [postgreSql]postgreSql数据库、模式、表、函数的删除与创建
1.删除/新增数据库 DROP DATABASE "testDB"; CREATE DATABASE "testDB" WITH OWNER = t ...
- jquery中的工具方法$.isFunction, $.isArray(), $.isWindow()
本文正式地址:http://www.xiabingbao.com/jquery/2015/07/25/jquery-judge-type 在javascript中对变量类型的判断中,我们讲解了了jqu ...
- 在windows操作系统中,查询端口占用和清除端口占用的程序
一.在windows操作系统中,查询端口占用和清除端口占用的程序 提升权限后用:netstat -b或用 1.查询端口占用的进程ID 点击"开始"-->"运行&qu ...
- 重新学习MySQL数据库10:MySQL里的那些日志们
重新学习MySQL数据库10:MySQL里的那些日志们 同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分.MySQL有几种不同的日志文件,通常包括错误日志文件,二进制日志,通用日志, ...
- 如何把数字字符'1'转换为整数(java 实现)
在一些表达式计算时,如 “3+2” 表达式自身是个字符串,通过切片得到的是数字字符和操作符,不能直接进行计算,在表达式计算中需要进行一步操作是,把数字字符'2','3'转化为整数. 如何操作? ...