Vim Tips

最後更新: 2022-12-16

介紹

在 Debian 5 內的 vim 是 vim-tiny 來, 它比原本的 vim 輕巧, 不過少了許多功能 ...

最少沒有了"語法高亮"及"用上下左右鍵移位"

我們可以用以下指令安裝回原全版的 vim

apt-get install vim

目錄

 


設定檔

 

vim 共有兩個設定檔, 分別是 global 檔 及 personal 檔

它們是 /etc/vim/vimrc 及 ~/.vimrc

vimrc 的 config file 係相當有趣的, 它可以 include 東西入去, 如

source /path/to/external/file

以下是我的 .vimrc 設定

set nocompatible
" 可以用返上下左右鍵

set nu
" 顯示行數

set incsearch
" Live Search

set autoindent
set tabstop=4
" 自動縮排, 且 tab 會看成 4 個 space 寬

syntax enable
set syntax=automatic
" 啟用自動 highlight (syntax=???)

source ~/.my-vim-key
" 載入另一檔案

~/.my-vim-key

" view next buffer
map <Esc>OC <C-right>
map <C-right> <Esc>:bn<CR>
" view before buffer
map <Esc>OD <C-left>
map <C-left> <Esc>:bn<CR>
“Hot key to switch between Big5 and UTF-8
set <C-u>=^U
set <C-b>=^B
map <C-u> :set fileencoding=utf-8<CR>
map <C-b> :set fileencoding=big5<CR>

從以上檔案好易看出, " 是代表 comments

map 是綁 keyboard 鍵的功能

在 .my-vim-key上, 我用了雙重 keyboard 綁定 @@"

這是因為經 putty 後, vi-tiny 的方向鍵會失效 .....

詳細請看 Escape character

首先我把 putty 輸出的 "Ctrl+右" map 成 terminal 的 "Ctrl+右" 先

之後再綁定 vi 的 "Ctrl+右" 的功能

 


'modeline' option

 

將 vim 的設定寫在被修改的檔案首尾N行, 打開它時自動套用.

Help

:help 'modeline'

Enabling modeline

~/.vimrc

set modeline

Remark

1. Debian-based distros disables modeline by default

/usr/share/vim/vim*/debian.vim

2. modeline 預設 detect 頭尾 5 行

set modelines=5

 

Checking

:set modeline? modelines?

modeline
modelines=3

:verbose set modeline?

modeline

Last set from ~/.vimrc

Usage

# vim: sts=4:ts=4:sw=4:paste:et

"et" 要放在最尾, 否則會唔 work

 


Space & Tab

 

Tab 與 Space 的 ASCII

hexdump -C test.txt

20 = 空格, 0a = 新行, 09 = tab

00000000  20 20 20 20 0a 09 0a                              |    ...|

 

Setting

  • et (expandtab)
  • ts (tabstop)
  • sw (shiftwidth)
  • sts (softtabstop)
  • sta (smarttab)

show current setting

 * default setting 係不會 display 出來的

:set

:set ts sw sts

expandtab (et)

# 按 "tab" 時, 會用 "ts" 數量的空格取代 tab

# real tab character use Ctrl-V<Tab>

# 建議 et 前 settings

# set 'shiftwidth' and 'softtabstop' to the same value, while leaving 'tabstop' at its default value

:set et

tabstop (ts) # default 8

在 et 情況

設定每次按 TAB 相當多小個空格

在 noet 情況

設定一個 tab 顯示成多少個空格 (沒有 et 情況下)

shiftwidth (sw) # default 8

1. Number of spaces to use for each step of autoindent.

2. shiftwidth governs indentation via ">>" (:help shift-left-right)
    set shiftwidth=8 makes it so that each >> you do will
    indent a line 8 character blocks more to the right.

 * 建議 shiftwidth=0 => 令它與 tabstop 保持一致

:set sw=0

softtabstop (sts) # Default 0 => tabs are always 'tabstop' positions

Number of spaces that a <Tab> counts for while performing editing operations

* It affects what happens when you press the <TAB> or <BS> keys.

> 空格轉換成TAB

> makes spaces feel like tabs ( i.e. Deleting 時, 將 N 個 space 當做 1 個 tab 去 Delete )

* "x"(DEL) still work on the actual characters.

noet

If softtabstop is less than tabstop

=> vim will use a combination of tabs and spaces to make up the desired spacing.

If softtabstop equals tabstop

=> vim will always use tabs.

et

vim will always use the appropriate number of spaces.

Example

:set ts=8 sts=4 noet

第一次按 Tab 鍵時, vim 會插入 4 個空格, 而不是插入一個 "tab"

(由於 ts=8 及 noet, 所以它會看成 8 空格寬)

開新行(ENTER), 按 Tab 鍵(插入 4 個空格),

再按 Tab 鍵時, vim 會刪除前面的 4 個空格, 然後插入一個 tab 字符.

Remark

1. Backspace

    在插入模式下手動輸入 4 個空格, 此時按 Backspace 鍵只能刪除一個空格.

    退出插入模式, 再進入插入模式, 就能用 Backspace 鍵一次性刪除這 4 個空格.

smarttab (sta)

on: A "Tab" in front of a line inserts blanks according to'shiftwidth'

off: A "Tab" always inserts blanks according to 'tabstop' or 'softtabstop'

What gets inserted (a <Tab> or spaces) depends on the 'expandtab' option.

將 file 內所有 tab 換成"空格"

# Change all the existing tab characters to match the current tab settings

# After the 'expandtab' option is set

:retab

OR

:%s/\t/  /g

 

某類 file 用特定的 type

~/.vimrc

autocmd FileType python setlocal shiftwidth=4 tabstop=4 expandtab autoindent softtabstop=4

 


Compatible mode in Vim

 

# When you :set compatible, all the enhancements and improvements of Vi Improved are turned off.

a "vi" command that is implemented with "vim" in compatible mode

:set nocp

 


highlight search

 

# enable

:set hlsearch

# disable

:nohlsearch

# To turn off highlighting until the next search

:noh

 


箭嘴外的 "上下左右"

 

在這裡不能不提的是, 在 tiny-vim 裡,

上下左加只能用 k, j, h, l 這一行鍵操控. 原因=不詳 = , =??

圖示:

                       k
                   h     l
                     j

 


多檔案編輯

 

多檔案編輯是指用同一個 vi 打開多個檔案, 如

vi /etc/passwd /etc/group

查看開了什麼檔案

:ls

  1 %a   "/etc/resolv.conf"             line 1
  2      "/etc/passwd"                  line 0

我們可以用以下指令在它們之間切換

:n         編輯下一個檔案
:N         編輯上一個檔案
:files     列出正在在開啟的檔案

不過, 在 vi 內用 :e [file] 打開的檔案就叫作 buffer

它們不能用 :n, :N 切換 @@" 何苦呢 ??

因此要用以下 buffer 指令

:bn            編輯下一個檔案
:bp            編輯上一個檔案
:buffers      列出正在開啟的檔案 (如同 :files)
:buffer  n    跳到開啟的 檔案n

 


多窗分割

 

:sp [filename]        啟用多窗模式
ctrl+w k               移到上面的視窗。
ctrl+w j                移到下方的視窗。
ctrl+w q                結束當前視窗 ( :q )

 

 

 


快速移動

 

e – jump to the end of the current word

b – jump to the beginning of the current word

w - jump to the beginning of next word

B – jump to the beginning of previous word

 

0     行頭

$     行尾

 

%    移到相對應的 (){}[]

n|    移到第 n column

 

{ – move the cursor to the start of the current paragraph

} – move the cursor to the end of the paragraph.
 


Undo & Redo

 

u                 Undo
.                  Redo
:e [file]         除消所有修改(重開 file)

=======================================

區塊複製:

 

  • v           單字選擇 ("-- VISUAL --")
  • V           整行選擇 (可連續多行 "-- VISUAL LINE --")
  • ctrl+v    區塊選擇 ("-- VISUAL BLOCK --")
  • y           複製選擇了的地方
  • d           刪除選擇了的地方

 

In visual block mode, you can press I to insert text at the same position in multiple lines

Ctrl-V-> select the block -> press I -> type # -> Esc

* I 一定要大寫

help:

:h v_b_I

Visual-block Insert                     *v_b_I*

* 要 vim 才有完整支援

=======================================

在 shell 上執行指令:

 

:! command

如 :!ls

=======================================

字串取代:

 

:n1,n2s/word1/word2/
// 一次取代

它是指在 n1 與 n2 行之後, 把 word1 取代成 word2

k          //重複以上取代指令

:n1,n2s/word1/word2/g
// 執行取代直到文尾

:1,$s/word1/word2/gc
// 使用者確認 (conform) 是否要取代當前一字

 

相當於 

:%s/OLD/NEW/g

 

=======================================

範圍操作:

 

在 vim 上, 單一個數字即代表重複做之後動作幾次, 如

 

3d

代表刪除 3 行, 相等於 dd, dd, dd, 又如

 

3dw

代表刪除 3 個字, 相等於 ctrl+w, ctrl+w, ctrl+w

 

另一方面, 有 , 豆號的代表一個範圍, 如

4,7d

這個刪除 第 4 行 至 第 7 行 的內容 ~

Remark

dd 刪除一行
dw 刪除一個字
D  刪至行尾
d0 刪至行首

 


設定功能

 

顯示行號:

:set nu

自動縮排: autoindent(ai) 與 smartindent(si)

autoindent

...

smartindent

Normally 'autoindent' should also be on when using 'smartindent'.

 * When typing '#' as the first character in a new line, the indent for that line is removed

自動儲存備份檔

:set backup
// 在編輯的檔案會 backup 成 filename~

 


語法顏色(syntax)

 

# Enable(on) / Disable(off) syntax highlight

:syntax on

# 設定用什麼 highlight

# set filetype

:set ft=dosini

# set syntax

:set syntax=dosini

# 查看此 syntax highlight 了什麼

:syntax list

No Syntax items defined for this buffer

OR

--- Syntax items ---
dosiniNumber   xxx match /\<\d\+\>/
                   match /\<\d*\.\d\+\>/
                   match /\<\d\+e[+-]\=\d\+\>/
                   links to Number
dosiniLabel    xxx match /^.\{-}=/
                   links to Type
dosiniHeader   xxx start=/^\s*\[/ end=/\]/
                   links to Special
dosiniComment  xxx match /^[#;].*$/
                   links to Comment

自定 Syntax - nginx

套用別人寫好的 Syntax

ls /usr/src/nginx/nginx-1.16.0/contrib/vim

ftdetect  ftplugin  indent  syntax

cp -a /usr/src/nginx/nginx-1.16.0/contrib/vim ~/.vim

設定

用 filepath 設定 filetype

~/.vim/ftdetect/nginx.vim

au BufRead,BufNewFile *.nginx set ft=nginx
au BufRead,BufNewFile */etc/nginx/* set ft=nginx
au BufRead,BufNewFile */usr/local/nginx/conf/* set ft=nginx
au BufRead,BufNewFile nginx.conf set ft=nginx

Notes: au

:au[tocmd] [group] {event} {pat} [nested] {cmd}

Add {cmd} to the list of commands that Vim will execute automatically on {event} for a file matching  {pat}.

~/.vim/syntax/nginx.vim

" Vim syntax file
" Language: nginx.conf

if exists("b:current_syntax")
  finish
end

" general syntax

...

 


Macro

 

q mymacro             最之後的操作建立為 mymacro
q                           中止記錄
@mymacro             執行 mymacro

 


Bookmark

 

建立

mc             // 將當前一行 bookmark 為 c

它支援 characters 有 a-z 不過只能用單字母

a-z 只用於當前檔案, 離開後就消失

0-9 留了給 "最近開過的檔案"月1

A-Z 係擁有永久保存能力的 bookmark 來, 而且可以跨

此外, 我們可以用 :marks 查看 bookmark 了什麼

跳到

'c              // 返回 bookmark c

刪除

:delmarks [markid] ...          // 刪除數個指定的 bookmark
:delmarks!                         // 刪除所有 bookmark

 


實用 hotkey

 

ZZ        保存並且離開 (相等於 :x)

ZQ        離開 (相等於 :q!)

它們只會在瀏覽模式下生效

":wq" vs ":x"

它們都是寫入檔案並退出, 分別在於

:wq   即使檔案沒有被修改也寫入(更新檔案的修改時間)

:x    僅當檔案被修改時才寫入

 


編碼

 

  • set encoding=utf8
  • set fileencoding=utf-8

set encoding=utf8

# 指定 Vim 內部對於文字編碼方式

# The encoding written to file.

set fileencoding=utf-8

# This is a list of character encodings considered when starting to edit an existing file.

# Vim tries to use the first mentioned character encoding. If an error is detected, the next one in the list is tried

# If all fail, 'fileencoding' is set to an empty string, which means the value of 'encoding' is used.

# (The encoding written to file.)
 


Disable automatic comment insertion

 

[方案1]

# turn off smartindenting and autoindenting

:set nosi noai

[方案2]

# turn on paste before pasting

:set paste

paste

:set nopaste

[方案2]

# 有時縮是 filetype 負責的

:filetype plugin indent off

 


^M

 

^M is a carriage return, and is commonly seen when files are copied from Windows (Control+M or ^M)

Line Feed(LF)           – \n            # a move to the next line

Carriage Return(CR) – \r             # to move the position of the cursor to the first position on the same line

 * Windows should be "CR+LF" whereas on Unix, it's just "LF"

<CRLF>  # \r\n

Unix uses 0xA for a newline character. Windows uses a combination of two characters: 0xD 0xA.

 

You can remove all the ^M characters by entering the following:

:%s/CTRL-V+CTRL-M/\r/g

 


Format Options

# check your format options:

:set formatoptions?

P.S.

縮寫 formatoptions => fo

Default:

formatoptions=tcq

# 設定

(-=)
(+=)

# formatoptions=croql

:set formatoptions-=r

# stop Vim from auto-creating comments

To disable it while hitting ENTER in insert mode

set formatoptions-=r

To disable it while hitting o or O in normal mode

set formatoptions-=o

# Help

:help fo-table

:help 'formatoptions'

 


vim save file 過程

 

mySecRules.conf -> mySecRules.conf~

.mySecRules.conf.swp -> mySecRules.conf

delete mySecRules.conf~

 


多了 1 byte

 

vim test.txt

i A <Esc> ZZ             # 插入一個字 A (0x41)

"test.txt" [New] 1L, 2C written

即使只鍵入一個字, test.txt 也會多了 0a (Line Feed - \n)

hexdump -C test.txt

00000000  31 0a                                             |1.|
00000002

 


設定 hotkey(shortcut) - noremap

 

echo "noremap ww :w<CR>" >> ~/.vimrc

noremap = Normal-Mode "Remap"

 

 


Color Scheme

 

ls -1 /usr/share/vim/vim*/colors/

...
default.vim

查看用緊那 scheme

:colorscheme

default

設定

:colorscheme delek

highlight

查看當前 colorscheme 的顏色

:highlight

 

highlight clear                # to reset everything to the defaults

background

set background={light or dark}

 


File Type Detection

 

vim 一共有兩個 detection 方式, 分別:

  • filename
  • inspecting the contents of the file for specific text.

查看現在的 filetype

:filetype

filetype detection:ON  plugin:ON  indent:OFF

它們的 ON/OFF

  • :filetype on
  • :filetype plugin on        #  enable loading the plugin files for specific file types
  • :filetype indent on

:verbose set ft ?

  filetype=nginx
        Last set from ~/.vim/ftdetect/nginx.vim

設定 syntax

:set syntax=modsecurity

ftplugin (filetype plugin)

This lets us execute arbitrary Vimscript or set other settings whenever the file is sourced.

檔案: modsecurity.vim

" ftplugin/modsecurity.vim
setlocal commentstring=#\ %s
setlocal tabstop=2
setlocal softtabstop=2
setlocal shiftwidth=2
setlocal expandtab
setlocal syntax=modsecurity

commentstring

A template for a comment.
Currently only used to add markers for folding.
The "%s" in the value is replaced with the comment text.

所以 comment 的 color 不是由它設定

設定自定的 filetype

~/.vim/ftdetect/12-modsecurity.vim

augroup filetype
        au!
        au BufRead,BufNewFile /etc/nginx/modsec/*.rules set ft=modsecurity
        au BufRead,BufNewFile /etc/nginx/modsec/*.conf set ft=modsecurity
augroup END

# 加 "12-" 的原因

ls -1 ~/.vim/ftdetect

11-nginx.vim
12-modsecurity.vim

:au[tocmd] [group] {event} {pat} [nested] {cmd}

When the [group] argument is not given, Vim uses the current group (as defined with ":augroup");

otherwise, Vim uses the group defined with [group].

 


Syntax Highlight

 

Vim stores the name of the syntax that has been loaded in the "b:current_syntax" variable.

The order in which syntax scripts are sourced

應用1: 查看當前的 syntax

:echo b:current_syntax

python

Notes

:setlocal syntax?

syntax=nginx

應用2: stop vim reading default syntax

 * prevents it from being loaded if syntax highlighting has already been enabled for this buffer.

if exists("b:current_syntax")
  finish
end
let b:current_syntax = "modsecurity"
...

The order in which syntax scripts are sourced

:scriptnames

  1: /etc/vimrc
  2: /usr/share/vim/vim74/syntax/syntax.vim
  3: /usr/share/vim/vim74/syntax/synload.vim
  4: /usr/share/vim/vim74/syntax/syncolor.vim
  5: /usr/share/vim/vim74/filetype.vim
  ...

查看 syntax cmd

:syntax list

自定 Syntax

syntax/modsecurity.vim

" Vim syntax file
" Language: modsecurity

if exists("b:current_syntax")
  finish
end

syn match modsecComment '\v#.*'
hi def link modsecComment Comment

syn keyword modsecKeyword SecRule
hi def link modsecKeyword Keyword

syn keyword modsecVariable REQUEST_URI REQUEST_FILENAME QUERY_STRING
hi def link modsecVariable Identifier

syn keyword modsecVariable REQUEST_HEADERS nextgroup=reqHeader
syn match reqHeader '\v:\w+' contained
hi def link reqHeader PreProc

syn region Oper start=/\v\s"\S/ skip=/\v\\./ end=/\v\S"\s/
hi def link Oper Operator

syn region Action start=/\v\s"id=/ skip=/\v\\./ end=/\v\S"\n/ skipwhite skipnl
hi def link Action String

let b:current_syntax = "modsecurity"

File Header

" Vim syntax file
" Language: modsecurity

Start with a header that explains what the syntax file is for

防止 syntax file double load

if exists("b:current_syntax")
  finish
end
let b:current_syntax = "modsecurity"

syntax

syntax 的設定一共有 3 種方式, 分別係 Keywords, Match, Region

keyword

syn keyword modsecKeyword  SecRule
syn keyword modsecVariable REQUEST_URI REQUEST_FILENAME

match

syn match FooKey /REQUEST_HEADERS:\w/

Magic (\X)

\v            # "^$.*+()|" 等直接係有 regex 的功效, 不用加 \ 在前 (e.g. \* \.)

  • \d+    match one or more digits
  • \s      whitespace character
  • \S      non-whitespace character; opposite of \s
  • \w     word character:  [0-9A-Za-z_]
  • \W     non-word character: [^0-9A-Za-z_]

nextgroup

nextgroup={groupname}

i.e.

syn keyword MyKey1 MyKey2 nextgroup=myNumber skipwhite
syn match myNumber '\d\+'

會中 "MyKey1 1234", "MyKey2 5678"

skipX(skipwhite skipnl skipempty)

skipnl (:help syn-skipnl)

When "skipnl" is present, the match with nextgroup may be found in the next line.

skipwhite

The match must begin exactly after the end of the current group.
If you need to include the leading whitespace in the id group match: \s\+, or add skipwhite.

"contains" 與 "containedin"

"contains=GRUOP"

To configure other syntax highlighting groups to be contained within an "outer group".

syn keyword myKeyword int
syn region BraceBlock start='{' end='}' contains=myKeyword

* The "contains=" argument is also inherited from the item it is contained in
   To avoid that unwanted items are contained, use "contains=NONE"

* "contains=CONTAINED" If the first item in the contains list is "CONTAINED",
   then all groups will be accepted that have the "contained" argument.

* "contains=CONTAINED,{group-name},..
    Like "CONTAINED", but excluding the groups that are listed.

"containedin=GRUOP"

syn region BraceBlock start='{' end='}'
syn keyword myKeyword int containedin=BraceBlock

"contained"

When the "contained" argument is given, this item will not be recognized at the top level,
but only when it is mentioned in the "contains" field of another match.   

=> To avoid that the group matches anywhere else, just add contained.

syn region BraceBlock start='{' end='}' contains=CONTAINED
syn keyword myKeyword int contained

region

syntax region msOper start=/\v\s"\S/ skip=/\v\\./ end=/\v\S"(:?\n|\s)/ contained

"skip"

skip=/\v\\./

 

To ignore anything that matches skip, even if it would normally be considered the end of the region

i.e.

"She said: \"Vimscript is tricky, but useful\"!".

Cluster

A list of syntax groups together under a single name.

syntax keyword myKeyword int
syntax region BraceBlock start='{' end='}' contains=@myCluster
syntax cluster myCluster contains=myKeyword
syntax keyword myConditional if else
syntax cluster myCluster add=myConditional

Usage

調用 cluster: @ClusterGroup

contains={group-name}

    The cluster is set to the specified list of groups.

add={group-name}

    The specified groups are added to the cluster.

remove={group-name}

    The specified groups are removed from the cluster.

 

highlight

highlighting group = color scheme

List highlighting group

:highlight                    # 看每個 Group 的顏色

:help group-name        # Color Group 的名稱

設定顏色的方法

  • To set a link
  • 設定 Group 的顏色

To set a link:

:hi[ghlight][!] [default] link {from-group} {to-group}

The [default] argument is used for setting the default highlighting for a group.

If highlighting has already been specified for the group the command will be ignored.

i.e.

highlight link modsecKeyword Keyword

"link" keyword group(i.e. modsecKeyword) to a highlighting group( i.e. Keyword)

To remove a link:

:hi[ghlight][!] [default] link {from-group} NONE

設定 Group 的顏色

highlight GROUP ctermfg=COLOR

ctermfg  # 字
cterm    # 背景
guifg    # 字
guibg    # 背景

i.e.

ctermfg=Yellow

Color Name

# "NR-16" is used for 16-color terminals

:h cterm-colors

NR-16       COLOR NAME
0           Black
1           DarkBlue
2           DarkGreen
3           DarkCyan
4           DarkRed
5           DarkMagenta
6           Brown, DarkYellow
7           LightGray, LightGrey, Gray, Grey
8           DarkGray, DarkGrey
9           Blue, LightBlue
10          Green, LightGreen
11          Cyan, LightCyan
12          Red, LightRed
13          Magenta, LightMagenta
14          Yellow, LightYellow
15          White

 

 


Other

 

輸入特別字元

在 insert mode 內,  我們可以鍵入 ctrl+v 之後,

輸入特別字元的 ascii 碼, 那就可輸入它們

如 ctrl+v 48 是 0