2010年10月31日 星期日

BAT大補帖 - First BAT (01)

在Linux下與Windows下,都有一個script的東西。
script顧名思義就是一個腳本。
就是原本要執行的二十個指令,寫在一個script中,系統由檔案中,逐行執行~
為什麼要這麼做呢?
如果常常使用指令模式在操作電腦,常常會輸入不同的指令與不同的參數,而其中可能會有許多重覆的部分,正所謂,「做重複的事情是罪惡的」,所以,我們才要把寫在一個script檔案中,讓之後可以重複利用,結省所謂的時間。

而makefile也是另一種script,但是,他算是比較進階且較我們要討論的script嚴謹。在某一些情況,要達到一樣的結果,在makefile要寫好幾行,而在script只需要寫一行。所以,我認為makefile與script都需要去學習,因為,它們都是節省重複動作的工具,值的學習!

而這一個script在windows下,就稱為bat file。

寫第一個bat程式
hello.bat
REM show message
ECHO "Hello Bat!!"
PAUSE

1. 以REM開頭的就是註解,就像C語言中的//
註解後面的東西是不會被執行的。
2. ECHO這一個指令是非常重要的,就像printf一樣,我們可以在程式中途插入一個echo,印出我們想了解某一個變數目前的數值,看是不是我們想要的數值。
3. 當script執行到PAUSE時,會停在PAUSE的地方,等待使用者輸入任意鍵再繼續。這一個指令在BAT檔中,debug是非常需要的。在bat的debug是非常弱的,他不會跟你說你第幾行出現錯誤,必需要使用PAUSE來下斷點,了解在執行哪一行後,才出現錯誤。

當執行完後,你會發現,怎麼程式碼每一行指令都被印出來啊?
我們可以在檔案的最上面透過ECHO OFF關掉這一個功能。
嗯,確實有效,但是還是會出現ECHO OFF這一個字串還是會被顯示出現。
這個時候在ECHO OFF前面加入@,表示不顯示目前這一行程式。
再執行,結果看起來清爽多了~
另外,ECHO後面也可以印出變數的內容,目前就是把USERNAME的內容印出來,要提取變數內容,必需要透過%,把變數名稱夾起來~
hello.bat
@ECHO OFF
REM show message
ECHO "Hello %USERNAME%!!"
PAUSE


另外,要善用說明檔~
help印出目前系統可以使用的指令
ECHO /?
PAUSE /?
CMD /?
通常裡面會有很多解釋和例子,值的參考!!

進階用法
Q: 為了排版,如何印出一個空白行?
A: ECHO.

[總結]
在這裡,你應該學會了以下指令或關鍵字的用法
ECHO
PAUSE
HELP
REM
@

2010年10月29日 星期五

依檔名設定filetype

在vim中,會自動判斷副檔名或是檔案內容決定這是何種檔案~

但是,有時候會有一些新的副檔名沒有辦法被vim判斷出來!

這個時候,就要在filetype.vim修改,當什麼副檔名的時候,自動設定filetype特定的filetype。

例如要把*.dsc設定與*.c的配色相同,則在filetype.vim最下面加入以下的內容

augroup filetypedetect
au! BufRead,BufNewFile *.dsc setfiletype c
augroup END


如此一來,所有的dsc檔的配色都會與c的相同

[2014.05.08 補充]
若想知道目前vim的環境變數為何,
直接輸入
:set

而若想知道filetype這一個環境變數值為何,
直接輸入
: set filetype

參考資料:
Vim Tips

2010年10月10日 星期日

加入註解

好的編輯器送你上天堂,不好的編輯器送你住套房。

但是,有好的編輯器還是要有好的設定,才能送你上天堂。

同時註解多行
用virtual mode的方式選取多行
:'<,'>s/^/\/\//g

把暫存器a的內的東西貼出來
"ap

一般來說 :g 的運作方式是根據一行一行來做的,當你用下面指令的時候,
:g/pattern/y a
這代表的意思其實只是把每次比對到的那行都 yank 複製到"a這裡面去。所以這就會造成我們最後只會拿到最後一行的結果,而不是每個比對到的都會進入到"a去。所以就必須告訴 vim 我們指定的內容是要做附加而不是覆蓋:
:g/pattern/y A

刪除選取的行數,並且存到暫存器a
"aD

:'<,'>d a

取得目前檔案的目錄
:echo fnamemodify("%", ":p:h")
%表示current file name

取得目前檔案的名稱
:echo expand("%")

若執行的指令很可能會出現錯誤訊息,但仍不想要顯示錯誤訊息的話,可以使用silent,例:
:silent! exe "normal /path\<CR>"

:silent! /xxxfdafd

在目前位置加入時間
::map <F2> a<C-R>=strftime("%c")<CR><ESC>


流程
1. 把目前的時間存到暫存器a
//[-start-strftime("%y%m%d")-CCD9527-remove]//
SET @a=time()

2. 註解掉目前選取的所有行數
:'<,'>s/^/\/\//g

3. 把選取的部分附加到暫存器a
"AD

4. 把目前的時間存到暫存器a
//[-end-strftime("%y%m%d")-CCD9527-remove]//
SET @A=time()

5. 把暫存器a貼到目前的位置
"ap


line
append
cursor
getline
mode
confirm
repeat

一行一行讀出來(getline)
加工(substitute)
加到list(add)
刪除原本的資料

_vimrc_utils
" Decide comment symbol
function CommentSymbol ()
"
" Set the default comment
"
let markid_start='//'
let markid_end='//'

"
" Set the comment by the different file type
"
if exists("&filetype") != 0
if (&filetype == "asm") || (&filetype == "pov")
let markid_start=';'
let markid_end=';'
elseif (&filetype == "make") || (&filetype == "inform") || (&filetype == "conf")
let markid_start='#'
let markid_end='#'
elseif &filetype == "dosbatch"
let markid_start='rem '
let markid_end='//'
endif
endif

return [escape(markid_start, ' /'), markid_start, markid_end]
endfunction

"Mark from N to M
function MarkN2MbyComment (N, M, Comment)
let ln = a:N
while ln <= a:M
call MarkByLine (ln, a:Comment)
let ln = ln + 1
endwhile
let @/=''
endfunction

" Remove Mark from N to M
function RemoveMarkN2MbyComment (N, M, Comment)
let ln = a:N
while ln <= a:M
call RemoveMarkByLine (ln, a:Comment)
let ln = ln + 1
endwhile
let @/=''
endfunction

" Set UserID from user input
function SetUserID ()
if exists("g:UserID") == 0

let g:UserID = inputdialog("Set Comment Symbol : (EX:IB06920001)")

if g:UserID == ""
let g:UserID = "TempUser"
endif

endif
endfunction

" Clear UserID
function ClearUserID ()

if exists("g:UserID") != 0
unlet g:UserID
endif

endfunction

" Add ceiling and floor comment
function CeilFloorComment (lnL, lnF, markid_start, markid_end, type)

exe append(a:lnL, a:markid_start . "[-end-" . strftime("%y%m%d"). "-" . g:UserID . "-" . a:type . "]" . a:markid_end)
exe append(a:lnF - 1, a:markid_start . "[-start-" . strftime("%y%m%d"). "-" . g:UserID . "-" . a:type . "]" . a:markid_end)
exe "normal " . (a:lnL + 2) . "G"

endfunction

" AddCommentBlock (F9)
function AddCommentBlock (lnF, lnL)
if line(".") == a:lnL

call SetUserID ()

let [comment, markid_start, markid_end] = CommentSymbol ()

call CeilFloorComment (a:lnL, a:lnF, markid_start, markid_end, "add")

endif
endfunction

" ModifyCommentBlock (F10)
function ModifyCommentBlock (lnF, lnL)
if line(".") == a:lnL

call SetUserID ()

let [comment, markid_start, markid_end] = CommentSymbol ()

call CeilFloorComment (a:lnL, a:lnF, markid_start, markid_end, "modify")

endif
endfunction

" RemoveCommentBlock (F11)
function RemoveCommentBlock (lnF, lnL)
if line(".") == a:lnL

call SetUserID ()

let [comment, markid_start, markid_end] = CommentSymbol ()

call MarkN2MbyComment (a:lnF, a:lnL, comment)

call CeilFloorComment (a:lnL, a:lnF, markid_start, markid_end, "remove")

endif
endfunction

function VisualAddCommentBlock ()
let lnF = line("'<")
let lnL = line("'>")
call AddCommentBlock (lnF, lnL)
endfunction

function NormalAddCommentBlock ()
let lnF = line(".")
let lnL = line(".")
call AddCommentBlock (lnF, lnL)
endfunction

function VisualModifyCommentBlock ()
let lnF = line("'<")
let lnL = line("'>")
call ModifyCommentBlock (lnF, lnL)
endfunction

function NormalModifyCommentBlock ()
let lnF = line(".")
let lnL = line(".")
call ModifyCommentBlock (lnF, lnL)
endfunction

function VisualRemoveCommentBlock ()
let lnF = line("'<")
let lnL = line("'>")
call RemoveCommentBlock (lnF, lnL)
endfunction

function NormalRemoveCommentBlock ()
let lnF = line(".")
let lnL = line(".")
call RemoveCommentBlock (lnF, lnL)
endfunction

function VisualAddSelectionComment ()
let lnF = line("'<")
let lnL = line("'>")

call AddSelectionComment (lnF, lnL)

endfunction

function NormalAddSelectionComment ()

let lnF = line(".")
let lnL = line(".")

call AddSelectionComment (lnF, lnL)

endfunction

function AddSelectionComment (lnF, lnL)
if line(".") == a:lnL

let [comment, markid_start, markid_end] = CommentSymbol ()

call MarkN2MbyComment (a:lnF, a:lnL, comment)

endif
endfunction

function RemoveSelectionComment (lnF, lnL)
if line(".") == a:lnL

let [comment, markid_start, markid_end] = CommentSymbol ()

call RemoveMarkN2MbyComment (a:lnF, a:lnL, comment)

endif
endfunction

function NormalRemoveSelectionComment ()

let lnF = line(".")
let lnL = line(".")

call RemoveSelectionComment (lnF, lnL)

endfunction

function VisualRemoveSelectionComment ()

let lnF = line ("'<")
let lnL = line ("'>")

call RemoveSelectionComment (lnF, lnL)

endfunction

function MarkByLine (CurrentLine, comment)
let TempContent = getline(a:CurrentLine)
let TempContent = substitute (TempContent, '^', a:comment,'g')
exe a:CurrentLine . "d"
exe append (a:CurrentLine - 1, TempContent)
exe "normal " . a:CurrentLine . "G"
endfunction

function RemoveMarkByLine (CurrentLine, comment)
let TempContent = getline(a:CurrentLine)
let TempContent = substitute (TempContent, '^\(\s*\)' . a:comment, '\1', 'g')
exe a:CurrentLine . "d"
exe append (a:CurrentLine - 1, TempContent)
exe "normal " . a:CurrentLine . "G"
endfunction

"AddSelectionComment
nmap <F3> :call NormalAddSelectionComment ()<CR>
vmap <F3> :call VisualAddSelectionComment ()<CR>
"RemoveSelectionComment
nmap <F4> :call NormalRemoveSelectionComment ()<CR>
vmap <F4> :call VisualRemoveSelectionComment ()<CR>

" 移除每一行最後多餘的空白
nmap <F6> :silent! %s/ \+$//gc<CR>

" 把tab轉換成空白
nmap <F7> :silent! %s/\t/ /gc<CR>

nmap <F8> :call ClearUserID ()<CR>
vmap <F8> :call ClearUserID ()<CR>
vmap <F9> :call VisualAddCommentBlock ()<CR>
nmap <F9> :call NormalAddCommentBlock ()<CR>
vmap <F10> :call VisualModifyCommentBlock ()<CR>
nmap <F10> :call NormalModifyCommentBlock ()<CR>
vmap <F11> :call VisualRemoveCommentBlock ()<CR>
nmap <F11> :call NormalRemoveCommentBlock ()<CR>


參考資料:
vim 的選擇模式 (visual mode)
有多少種方式可以在vim中插入行號
我的 VIM 整理
vim 提供的函數
vim 選擇模式下的熱鍵( Key mapping )