pretty code

2025年5月10日 星期六

Vim script 最佳學習指南


上面這個應該是我覺得寫得最好的,再加上又是中文,雖然是簡體,但還是比讀英文快多了XD

Learn Vimscript the Hard Way 雖然也是不錯,但我還是覺得敘事過慢,不用工作當然無所謂,但是畢竟人還要上班,一個傳統目錄的網站列表還是比較符合我的需求。

總之,一樣主題的書就是要多買幾本,彼此互相參照學習最快,想當年我初學 C 語言,C 語言的書買了至少有 10 來本,每本書都可以從中找到我所需要的部分,雖然這些書也早就丟光了XD

買過丟掉的書就不算了,手邊大概還有 10 來紙本書放在公司,如果電子書也不算的話,底下就是我手上目前僅存資訊相關的書籍了,很多都是我很喜歡的書,以後如果有出電子書我應該會再買一次來收藏,畢竟我家這般潮濕的天氣,什麼時候書會 gone 我都不知!

誠品就只有一個小小的櫃有資訊相關的書,至少有一半是 AI 和我不需要的文書處理的書,故每次跟我老婆說要去誠品巡巡田水,也不期待會有我想買的書。

買書還是得去天瓏,但想到要上台北還是覺得累。

不過今天還是買了一本我想看的書《無瑕的程式碼 - 函數式設計篇》,希望可以多少給我一些啟發。

人生好難呀XD













2025年5月8日 星期四

使用全域變數真的要小心,尤其在 Golang

可能我不常寫多執行緒的程式再加上常用很深的遞迴,故有時候我都會直接用全域變數XD

在別的程式語言也許還好,但在 Golang 的時候,一個變數是否是新的變數端看他是否有用到 :=

如果這時不小心,在操作全域變數時加上 :=,這時存取的就是一個新的 local 變數。

雖然除錯也花不了多少時間,但也是很難第一時間就馬上想到。

另外,為了收集資料,我的函數有時可以 for single job,有時也可以 for  accumulated job,如果這時忘記清空原本的全域變數,就會導致資料變成好幾次的累積結果。

以後除了很深的遞迴,我看還是少用全域變數XD

有時候也不是想用全域變數,但一開始如果不用一個 struct 包住變數,再加上隨著需求逐漸明朗,很多時候函數的參數都會逐漸膨脹,很容易就超過 5 個以上,再加上我的 code 大部分都函數化,有時一改就是好幾層,只好偷懶用全域變數XD

我想以我的 coding style 來說,一定要養成 struct 進,struct 出的習慣,這樣應該能避免全域變數的使用?

不過這樣 struct 也會變得腫脹,真是兩難?

2025年5月4日 星期日

我的第一版 netrw

終於有個樣子了,現在只剩下幾個問題
01. 沒有比較好的方法去禁止編輯,map key 不只影響 netrw 的 filetype,可能我的理解還是有誤。
02. statusline 不知為何沒有生效。

" for my file explorer
augroup explorer_group
    autocmd!
    autocmd BufEnter * call s:MK_Browse("")
    "autocmd FileType netrw nnoremap :q :q!
    autocmd FileType netrw nnoremap <CR> :call <SID>MK_Enter_Browse(<SID>GetCurrNetrwFile())<CR>
    "autocmd FileType netrw nnoremap i <ESC>
    "autocmd FileType netrw nnoremap I <ESC>
    "autocmd FileType netrw nnoremap a <ESC>
    "autocmd FileType netrw nnoremap A <ESC>
    "autocmd FileType netrw nnoremap x <ESC>
    "autocmd FileType netrw nnoremap s <ESC>
    "autocmd FileType netrw nnoremap y <ESC>
    "autocmd FileType netrw nnoremap p <ESC>
augroup END

function! <SID>MK_Enter_Browse(name)
    if isdirectory(a:name)
        let l:dir = a:name
        if has('win32')
            let l:dir = substitute(dir, "/", "\\", "")        
        endif
        
        execute ":e! " . l:dir
    else
        let g:MK_curr = getcwd()
        let g:MK_sv = winsaveview()
        execute ":tabe " . a:name
    endif
endfunction

function! s:MK_Browse(dir)
    " get current directory
    let curr = expand("%:p")
    if a:dir != ""
        let curr = a:dir
    endif

    " not directory, do nothing
    if !isdirectory(curr)
        execute ":set nocursorline"
        return
    endif

    " change folder for later using
    if getcwd() != curr
        call chdir(curr)
    endif

    " set up some options
    execute ":set filetype=netrw"
    execute ":setlocal nonumber"
    execute ":setlocal nowrap"
    execute ":setlocal cursorline"
    execute ":setlocal buftype=nowrite"
    
    " delete original path structure
    normal! dG

    let f_list = readdir(curr, 1)
    let n = 1

    " save paths
    let files = []
    let folders = []

    call add(folders, "../")
    call add(folders, "./")
    
    for f in f_list
        if f == ".swp" || f == "_.swp"
            continue
        endif

        let s = f
        if isdirectory(f)
            let s = s . "/"
            call add(folders, s)
        else
            call add(files, s)
        endif
    endfor
    
    " add folders
    for f in folders
        call setline(n, f)
        let n = n + 1
    endfor
    
    " add files
    for f in files
        call setline(n, f)
        let n = n + 1
    endfor

    " restore previous position
    if exists("g:MK_sv")
        if g:MK_curr == getcwd()
            call winrestview(g:MK_sv)
            unlet g:MK_sv
        endif
    endif

    " statusline
    call s:SetStatusLine()
endfunction

2025年4月28日 星期一

Add mouse menu on Windows

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\COMMAND_NAME\command]
@="EXE_PATH %1"

[HKEY_CLASSES_ROOT\directory\background\shell\COMMAND_NAME\command]
@="EXE_PATH ."

2025年4月27日 星期日

My simple netrw plugin

自己寫 Netrw 果然還是有點勉強XD


上面是一個簡單針對 BufEnter Event 的函數。

為了讓他像是一個檔案總管,其實還有很多事要做。

比如說:

set nu!
set nowrap
針對檔案總管顯示顏色
原本使用者設定的 vimrc 裡面的東西要回復

族繁不及備載

至少開始有點感覺了…

2025年4月26日 星期六

快速 parsing 檔案

以前需要臨時對檔案 parsing,一般來說我都會選擇 C 語言,因為這是唯一一個我不需要 google 就可以寫完的程式。

年紀大了還要編譯有點懶,再加上需要做這件事的時候,往往還需要搭配 regex。思來想去,想用一個簡單一點,語法好記的語言,於是便決定以後就用 Tcl 了。

bash script 好是好,但是速度有點慢,不知道是不是我剛沒寫好的關係?

set input "c:\\Vim\\vim91\\autoload\\netrw.vim"

set infile [open $input r]
fconfigure $infile -encoding utf-8

set func_pattern {^fun(\s|!)+ (.*)\s*\(.*}
set end_func_pattern {^endfun}

while {[gets $infile line] >= 0} {
    if {[regexp $func_pattern $line >= null f_name]} {

    } elseif {[regexp $end_func_pattern $line]} {
    
    } elseif {[string first "winrestview" $line] != -1} {
    
    }
}

剛剛希望找到 Netrw 所有呼叫 winrestview 回復 cursor position 的地方,很可惜,確認了幾個地方,但都不是對的地方,我到現在還找不到開啟右邊視窗後,回到原本 Netrw 瀏覽視窗的地方,到底是哪個函數破壞了我自己回存 position 的意圖?


我甚至把所有的 winrestview 都註解了,還是解不掉這個行為,我開始懷疑我的方向錯了?

2025/04/26 晚上更新


想要把之前註解掉的語句回復,使用上面 Tcl 語法,遇到 UTF-8 編碼,還是有少數幾句會有問題,這個問題先記錄起來,以後有空再回來確認。

後來想到可以使用巨集來回復,只要先設定 set nowrapscan,不要讓搜尋從頭開始,這樣就可以設定下面巨集了。ˊ

01. / winrestview 先 trigger search
02. gg 回到第一列
03. qq 開始記錄
04. n^x<ESC>j
05. q 停止紀錄
06. 100@q 執行 100 次巨集,數字要比所有的 winrestview 次數還要多。

04 巨集最重要的是最後面的 j 也就是跳到下一列,這樣按下 n 才會往下一個 winrestview 前進。

2025/04/27 更新

既然 Vim 巨集這麼好用,今天一口氣在每個函數入口加上 echom function_name 的功能,但居然都不是呼叫 winrestview 的函數被觸發而是 s:NetrwInsureWinVars。

現在只能猜測是 Netrw 有去動 buffer 或是什麼我不知道的東西?

有時在想,自己寫一個 directory explorer plugin 會不會比較簡單?

Tcl global error

之前用 Go 重寫 tool 時,改由自己得到 Top module name,不再從 command line arg 取得。

覺得這樣也蠻方便的,故將 Tcl code 也比照辦理。

由於之前的 Tcl code 遞迴用很深,故我很多參數都是拉出來變成全域變數,就只是忘了在 proc 中加上 global var 宣告,害我昨天找了老半天XD