【shell】vim专家指南

基础

c{motion} c会将{motion}指定的片段删除,然后进入插入模式。
. 会记住c插入的词语,然后进行重放

比d{motion}i更加快一点

as, is a sentence/inner sentnce

(
) -> 移动到句子的开始或结束

{} 段落移动
]] section 移动

几个移动命令的具体区别

^ 第一个非空字符
0 第一个字符
g_ 最后一个非空字符
g0 屏幕的第一个字符
g^ 屏幕的第一个非空字符

f<char> char的第一个,right方向
F<char> char的第一个,left方向
t,T 类似,但是字符会放在char的前面(相对左右方向前面) , 注意fFtT不会跨行

; 重复fFtT命令
, 重复fFtT命令,相反方向

:[count]% 进入文件的百分比

wW
bB backward, word

eE forward,end of work
gE backword,go to end of word(next)

从命令行使用vim

Plugin

:profile file <file>
:profile func <pattern>
--startuptime <file> Write startup timing messages to <file>

插件规则:主要代码写在autoload中,必须的启动代码写在plugin.vinm中

:packadd 添加插件

vim和neovim都支持feedkeys,但是只有vim支持term_sendkeys

subsitute

统计: s/…//gn
n: nop,显示匹配的数量

marks

大写的Marks是跨文件,跨Session的。

autocmd

在调试autocmd时,可通过:set verbose=9来进行调试

buffer-local

:help autocmd-local 查看<buffer>修饰的autocmd

所谓的buffer-local就是指仅仅针对当前buffer生效,一旦buffer被移除,相应的命令就会失效。

通过:set verbose=6来进行调试,这对于测试autocmd命令是非常有效的

autocmd BufEnter <buffer> echo "hi"这条命令在进入buffer时显示hi.

定义能够接受范围的命令

像c,d,y,~这样能够在normal模式中改变文本的键叫做操作符,通过:help operator查看帮助。

像这样的操作符可以和motion移动命令结合在一起使用。

= 将文本传递给eqaulprg执行(filter)

> < shift

g@ 调用operatorfunc

通过:omap 查看operator对应的map。

在operator后面可以使用:命令来定位光标的位置
d:call search("f")<CR>
在这种模式下,操作是exclusive的(也就是光标的末尾不包含在操作内),也是按字符的(而不是按行)

仅能用于operator的选择命令

aw 一个word,无论在词的哪里,都可以选中这个词 "*yaw将一个词语复制到系统粘贴板.
iw 和aw相同,但是指定count时,iw会将空格也计算在内

space between words
3yiw-> space between
3yaw-> space between words

aW
iW 类似

as
is sentence
通过vis查看选中的句子

ap
ip 段落

a[
a] 两个都是一样的,最终广告都停留在末尾]处

i[
i] 在[]内部
a) a( ab 在()内部

i) i( ib

a>
a<
i>
i<

a} a{ aB
i} i{ iB
a" a’ a`
i" i’ i`

组合

dl 等价于x,删除一个单词
diB 删除{}之间的内容

Marks和jumplist

m’ m` 标记上一次的位置,非常有用

g’a 跳转,但是不改变jumplist

jumplist 可以使用C-I, C-O进行跳转

当你使用split开启新的窗口时,jumplist会被复制

通过jumps命令可以看到跳转栈,你可以通过C-O 向上移动

变量名和映射

@@ 对应unamed_register

g@ 定义模式

	nmap <silent> <F4> :set opfunc=CountSpaces<CR>g@
	vmap <silent> <F4> :<C-U>call CountSpaces(visualmode(), 1)<CR>
		function! CountSpaces(type, ...)
	  let sel_save = &selection
	  let &selection = "inclusive"
	  let reg_save = @@

	  if a:0  " Invoked from Visual mode, use gv command.
	    silent exe "normal! gvy"
	  elseif a:type == 'line'
	    silent exe "normal! '[V']y"
	  else
	    silent exe "normal! `[v`]y"
	  endif

	  echomsg strlen(substitute(@@, '[^ ]', '', 'g'))

	  let &selection = sel_save
	  let @@ = reg_save
	endfunction

上面的命令都是将<F4>映射到统计函数,但是支持不同的模式,当在正常模式中使用g@时,实际上type这些参数就是自动设置的,会根据上下文进行设置

注意上面的函数中,a:0表示第一个可变参数

type是line时表示按行执行, char表示字符. 一般而言,类型会根据移动的motion来进行判断

在正常模式下,[和]的mark表示的上一次yank或者changed的文本段的开始或结尾,但当使用g@{motion}时,[和]则是{motion}指示的范围

编写DoComment

我们希望根据文件类型来实现IDEA的 <C-/>注释和去掉注释的快捷键.

我们通过operator来做有很大的灵活性。因此,需要能够通过mark拿到lnum(VIM术语)以及对应的行

line(expr) 获取行号
getline(lnum,end) 获取行内容,如果不存在就返回0. 注意:end也会包含在结果中
setline(lnum,text) 来设置

" set comment prefix
augroup comment-maker
	autocmd!
	autocmd BufEnter *.go,*.c,*.c++,*.java let b:commentPrefix="//"
	autocmd BufEnter *.sh,*.zsh,*.csh,*.ruby let b:commentPrefix="#"
	autocmd BufEnter *.vim let b:commentPrefix='"'
augroup END

" NOTE do not use \<SID>, <SID> is replaced by command,not by string
" Usage:  <Leader>/4j   = comment following 5 lines
"         <Leader>/l    = comment current line
nnoremap <silent> <Leader>/ :set operatorfunc=<SID>ToggleCommentOperator<CR>g@
vnoremap <silent> <Leader>/ :<C-U>call <SID>ToggleCommentOperator(visualmode())<CR>
function! s:ToggleCommentOperator(type)
	" do not do this when there is no comment prefix
	if !exists("b:commentPrefix") || len(b:commentPrefix)==0
		return
	endif
	let start = 0
	let end = 0
	if a:type ==# 'v'
		" todo visual mode
		let start = line("'<")
		let end= line("'>")
	else
		" line or char
		"use '[ and '] to get motion range
		let start = line("'[")
		let end = line("']")
	endif
	let lines = getline(start,end)
	if len(lines)==0
		return
	endif

	" judge should we comment or uncomment based on first line's
	" start
	let commentLen = len(b:commentPrefix)
	let firstline = lines[0]
	let commented = 0
	" startswithA commentPrefix
	if len(firstline) >= commentLen && firstline[0:commentLen-1] ==# b:commentPrefix
		let 	commented = 1
	endif
	if commented
		" must all line be commented to be safely uncommented
		let i = 0
		let size = end - start + 1
		while i < size
			let cur = lines[i]
			if len(cur) < commentLen || cur[0:commentLen-1] !=# b:commentPrefix
				echoerr "line ".(i+start)."  does not start with ".b:commentPrefix.", aka not commented"
				return
			endif
			let i=i+1
		endwhile
		let i=0
		while i < size
			let cur = lines[i][commentLen:]
			if len(cur) > 0 && cur[0] ==# " "
				let cur = cur[1:]
			endif
			call setline(start+i,cur)
			let i=i+1
		endwhile
	else
		" all line can be commented
		let i = 0
		let size = end - start + 1
		while i < size
			call setline(start+i,b:commentPrefix . " " .lines[i])
			let i=i+1
		endwhile
	endif
endfunction

quickfix

关键词: getqflist setqflist getloclist setloclist
vim中关于 edit-compile-edit的编程循环有两个支持:quickfix和locationlist

每个窗口都有一个附属的quickfix,当你使用:clist时就会展示所有相关的错误
使用 :vimgrep /patter/ file 即可打开一个:clist

echo getqflist({'lines':["F1:20:Line10"]})
--> {'items': [{'lnum': 20, 'bufnr': 22, 'col': 0, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': 'Line10'}]}

errorformat选项:这个选项指定了一个列表,定义编译器产生的错误该如何解析。例子:

%*[^"]"%f"%*\D%l: %m,"%f"%*\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\,,%-GIn file included from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\,,%-G%*[ ]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,"%f"\, line %l%*\D%c%*[^ ] %m,%D%*\a[%*\d]: Entering directory %*[`']%f',%X%*\a[%*\d]: Leaving directory %*[`']%f',%D%*\a: Entering directory %*[`']%f',%X%*\a: Leaving directory %*[`']%f',%DMaking %*\a in %f,%f|%l| %m

其中,逗号用于分隔多个format,逗号之后的空格忽略。

注意: errorformat也可以简写为efm.

如果某一行不能被匹配,则:cn, :cp时会被跳过,也会被标记为not valid.

%f 文件名
%\ \符号
%. .符号

管理quickfix list

使用:cexpr system(‘grep -n xyz’) 可以创建一个quickfix list, 并且跳转到第一个错误

:lexpr … 则可以创建一个跳转的list

跳转: :cc[!] [nr] 展示nr或当前错误,如果错误在另外的buffer,则指定了!时进行跳转

与quickfix list相关的命令有哪些呢?
autocmd的event: QuickFixCmdPre QuickFixCmdPost 用于在执行QuickFix类命令前后执行
相关命令:help QuickFixCmdPre -> [l]make,[l]grep,[l]vimgrep,cbuffer,cfile,cexpr

cgetexpr和cexpr一样,但是不跳转到第一个错误
caddfile file 将错误从文件添加过来

与系统交互

关键词:system systemlist shellescape expand

shellescape 基本上就是将字符串使用单引号引起,然后将字符串中的单引号换成’

但是注意,与grep等系统命令交互时,需要将|进行转义,避免被当成管道。

Command-Editing 模式

在normal模式下输入:即可进入command-editing模式,相应的按键使用cmap, cnoremap。
此外, /和?也可以进入command模式

<C-\> e可以计算表达式的值

类readline的交互

	:cnoremap <C-A> <Home>
	:cnoremap <C-F> <Right>
	:cnoremap <C-B> <Left>
	:cnoremap <Esc>b <S-Left>
	:cnoremap <Esc>f <S-Right>

窗口

z{nr}<CR> 设置窗口的大小

<C-W> t top的window
<C-W> z 关于preview窗口

关于window title

选项title, titlestring ,t_ts 用于决定一个vim与terminal的交互。

首先:set title会将title打开
然后 set titlestring=… 会设置terminal的窗口名称(其实就是整个应用的标题,在MacOS上桌面预览时会展示这个作为标题)

但是,仅在t_ts选项非空的情况下才会用作用。例子:
在这里插入图片描述

    :auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p")
    :set title titlestring=%<%F%=%l/%L-%P titlelen=70

[]命令

Square Brackets又称为方括号命令,主要用于与语言相关的移动。

Tab

<C-W> gt 同gt下一个tab
<C-W> gT 同gT,上一个Tab

help

:help subject

<C-D>可用于列出所有可帮助的主体补全。

help ^V CTRL-V的帮助
help i^V insert模式下 CTRL-V的帮助,等价于help i_CTRL-V

:helpgrep pattern 用于在所有的帮助文件中搜索正则表达式, 搜索内容在quickfix window中打开,你可以通过:cnext等命令进行移动

最有用的几个主题:
:help howto
:help quickref

命令重复(Power of g)

g& 重复 对所有的行重复": s"命令

在shell脚本中使用vim

vim -e -s “$file” < commands.vim

-e: 在ex模式下启动vim, 在这种模式下,只能对command-line进行编辑,不能对文件进行直接的编辑。通过输入visual可进入normal模式。
其实ex模式就是normal模式输入:之后不再退出的状态。
在这个模式下默认有一个buf和file可以直接写入

-s: 告诉vim使用silent,不输出

 vim -e -s
normal! iheel
file x.txt
wq

上面就是-s模式启动的例子,这种模式下vim不会启动一个新的窗口,而是如同repl一样接收输入,但不展示命令结果。
在这种模式下执行 echo “msg” 不会有任何展示。

echo hello|vim - -作为文件参数时,表示从stdin读取内容。vim中作为脚本时需要从stdin读取
这种情况下该怎么设置脚本内容呢?通过-S scriptname指定。

vim -s source file当-s不与-e出现时,-s表示source的脚本。

vim -w scriptrecord file -w用于指定记录输入的命令。

gv + s组合

为了完成多次替换,可以使用gv来重复选择之前的文本,然后执行s替换指令。

CTRL_A 对数字进行递增

如果你有一个列表

1
2
3
5
6
7

你想对1,2,3都增加1,办法就是选择1,2,3,然后执行<C-A>就会递增1.还可以结合visual + /搜索模式框定要改变的文本。

<C-X> 减少1.

do系列命令

:argdo %s… 在每个文件上执行命令
:windo cmd 执行完命令后,光标将会处于最后一个window。
:bufdo cmd
:tabdo cmd

preview窗口

每个tab只能有一个preview窗口,&previewindow属性用于识别一个preview窗口。这就意味着使用split和vsplit时,新的窗口previewwindow属性未设置.
previewheight用于设置preview窗口的高度。

:ptag tag 在preview窗口中打开tag

C-W z
:pclose 关闭任何已经打开的preview窗口

:ppop 类似:pop, 跳转到tagstack中前面的位置

C-W } 在当前word上执行ptag
C-W g} 当前word执行ptjump

:psearch pattern 搜索tag,在preview中打开

:pedit 在preview window中编辑
:wincmd P 跳转到preview window

CursorHold + ptag 自动在preview window中展示tag

 :au! CursorHold *.[ch] ++nested exe "silent! ptag " . expand("<cword>")

++nested表示在preview窗口中其他autocmd也能执行,比如语法高亮。
CursorHold受updatetime选项的影响。

:tags 用于展示
:jumps 用于展示jump list, 当你使用C-O C-I进行移动时 jumpstack会保留,但是使用C-] 时,jump的头部会被替换。

Tag
map进阶

通过使用<Cmd> : noremap x <Cmd>echo mode(1)<cr>可以避免切换到command-lin 状态,这比:C-U(visual 模式)和C-O:(insert 模式)具有更好的通用性。

relativenumber

由于d6j是如此常用,我们需要知道目标和现在的位置,使用
set relativenumber即可获取当前行的相对位置

如何改变光标的形状?

如果你的光标不幸被改变了默认值,执行下面这条命令恢复它!

:set guicursor=n-v-c:block,i-ci-ve:ver25,r-cr:hor20,o:hor50,a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor,sm:block-blinkwait175-blinkoff150-blinkon175
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值