Skip to content

vim script實作練習 - 打造html檔IDE為例

需求

編輯html會有諸多快捷鍵或補全的需求,這裡先列出幾個基本需求來實作
1.限定檔案的括號補全
如打完<希望能自動補全>
但是希望限定html檔使用
因為其他語言數學式常用到大小於,通常不希望被補全

2.快速打出tag
自訂快捷鍵,快速產生tag
如打出;b 可以快速產生 <b></b>
或 ;p 可以快速產生 <p></p>

3.設定跳躍點
希望在打完tag內容後,可以快速跳到下一行

<p>content</p>

+jump+

打完content內容後,可以快速跳躍到外面

4.使用說明
希望在打開html檔後,可以跳出一個說明檔告知如何使用

實作

先看看實作script

"每當打開html檔,自動執行
autocmd FileType html call InitHtml()


"接收使用者輸入的function
function InputTag()
     call inputsave()
     let g:tag = input("your tag")
     call inputrestore()
endfunction

"打開html所需執行的設定函數
function InitHtml()
	"自動補全角括號
	inoremap < <><Left>
	
	"""
	在normal模式按下; 接續輸入會成為tag與跳點
	如;p  會生成 <p></p>
				 跳點
	並將光標移回tag中間,同時切換成insert模式
	"""
	nnoremap ; <ESC>:call InputTag()<CR>i<<C-R>=tag<CR>>OwwOw</<C-R>=tag<CR>><Space><Enter><++><Esc>/OwwOw<CR>5xi

	"在插入模式按下;; 會跳至跳點,並切換成normal
	inoremap ;;  <ESC>/<++><Enter>4x<ESC>
endfunction

結果如下圖

講解

以下是依次講解使用到的script

autocmd

autocmd 事件 匹配 指令 可以在條件滿足時,自動執行後面的指令

1. 事件

常見事件有 讀寫檔案 關閉、離開vim、buffer、window ...

並且事件也可以用FileType等指令來依 不同種類檔案來執行不同指令

2. 匹配

匹配特定的檔案,讓autocmd執行在你想要執行的檔案 並且可以使用萬用字元,比如*表示任何檔案
  • Note: FileType 後的檔案類型本身就已經囊括匹配了

以下是一些例子 (參考:http://vimdoc.sourceforge.net/htmldoc/autocmd.html#{event})

autocmd BufRead * :vs test   #開啟任何檔案時自動打開test
autocmd BufRead /tmp/*.py	set ts=4   #打開python時自動設定tab長度為4

autocmd BufWrite * :!ls #在儲存檔案時自動ls當前目錄 


FilType

檢查當前檔案是甚麼,檢查方式是看檔案的 副檔名
比如.py , .html , .md …

可以使用指令set filetype? 來查看當前filetype

此外,也可以在~/.vim/after/ftplugin/<FileType>.vim中為不同副檔名分檔設定
(其中<FileType>要填入對應的副檔名,比如html.vim)

結合autocmd ,就變成當filetype == 你想要的type才執行後續指令

vim function

1. function 介紹

vim 中的function可以同時進行多個設定

比如今天想執行三個設定A B C
autocmd 不需要打三次,直接call function就好

也就是

autocmd FileType html A  
autocmd FileType html B  
autocmd FileType html C  

可以改寫成

function setting()
	A
	B
	C
endfunction  

autocmd FileType html call setting()

  • Note: 使用時要call 函數名稱()

2. function 結構

結構大概是
function 名稱()
   // your function 
endfunction

注意function範圍是由function ~ endfunction決定
不是縮排,也沒有括號
此外,關於函數參數以後用到會再補上講解

map

1. mapping 介紹

可以讓按鍵進行替換,用途非常多(補全、快捷鍵)

基本格式為
[模式][遞迴]map {原按鍵} {替換按鍵}

如將( 替換成 () 就能自然打出括號補全

補全也可以用於打出指令,也有遞迴的補全,此外也可以模擬任何按鍵,以下為介紹

2. mapping 方式

mapping方式可以依 模式區分,並且可以選擇不要遞迴mapping
(舉例而言 map A B , map B C ,若遞迴map,按下A就會被映射到C)

可以將模式加在map前面
例如imap, nmap

預設為遞迴,可以將nore加在模式與map之間
如inoremap, nnoremap

還有更多進階用法,以後用到也會介紹(參考:https://vim.fandom.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_1))

3. 按鍵

除了基本英文字母以外,mapping也可以模擬其他按鍵 比如方向鍵

<Left> < Right> <Up> <Down>

Enter 鍵、ESC鍵、 空白鍵
<CR>(或<Enter>) <Esc> <Space>

  • Note: ESC鍵可以從insert mode 轉換成 normal mode,常用

Control + x
<C-r> #Control+r 以此類推

4. 綜合應用

1.括號補全

inoremap { {}<LEFT> #補全後回到括號中間,方便輸入

此例告訴我們可以map任何按鍵,包括用方向鍵移動光標

2.跳點

inoremap <Space> <Esc>/<++><Enter>4xi 按下space後
先利用ESC回到normal
利用/搜尋跳點
按下enter找到跳點
利用4x刪除跳點,完成跳躍
最後切換模式回insert

此例告訴我們甚至可以map normal mode下的指令,以及模式間的切換

input()

input()可以回傳使用者的輸入
例如
let g:name = input(“your name”)
並且裡面的參數可以收字串,告知使用者該輸入甚麼(與python的input用法一樣)

而在使用input()時,為了防止vim的自動補全,通常會在前後加入
inputsave(),inputrestore()

比如

function inPutPattern()
call inputsave()
let g:name = input("your name")
call inputstore()
endfunction

(g表示全域變數,這樣function外部也可以使用到name)

打出變數的方法

用input()紀錄使用者輸入後,可以在insert mode下用Ctrl+r再輸入=變數名打出該變數內容

(注意,若是在normal模式 <c-r> 是回復)

舉例如下gif

實作講解

autocmd FileType html call InitHtml() 當開啟.html時,自動呼叫InitHtml()

function InitHtml()
...
endfunction

定義InitHtml()

inoremap < <><Left>
自動補全角括號

nnoremap ; <ESC>:call InputTag()<CR>i<<C-R> =tag<CR>>OwwOw</<C-R> =tag<CR>><Space><Enter><++><Esc>/OwwOw<CR>5xi 按下;時
切換成normal
呼叫InputTag()
按下確定
切換成insert
完成補全並留下記錄點(OwwOw)
在外面留下跳躍點(<++>)
切換成normal
跳回OwwOw,並清空(4x)
最後切換成insert

function InputTag()
     call inputsave()
     let g:tag = input("your tag")
     call inputrestore()
endfunction  

接收輸入者輸入tag

inoremap ;; <ESC>/<++><Enter>4x 前面解釋過的跳點