沒穿方服

索引

顯示╱隱藏內文

TYPE IV~沒穿方服~ 從地下的屍體放置場冒出來的僵屍,即使已經死了,但還保留著吃東西的本能。 
文獻來自 PS 恐怖遊戲之非官方印刷品。

遊戲結局數分鐘前才登場的 lo-fi 多邊形喪屍,已經失去 9 成以上的嚇人能力,然後惡靈古堡就爆炸了。

跟洋館的怪物相比實在是很無味的角色,幸好有個多麼好聽的名字而被人記住。

編譯沒有 gui 的 Vim 7.3,無特殊需求,純升級。

  1. ftp.vim.org/pub/vim/unix/ 下載 unix 用的原始碼 vim-7.3.tar.bz2,解開後進入 vim73 目錄。
  2. 直接選 big 包的 features(包括 multi_byte 等沒理由不要的功能)。
    ./configure --with-features=big

(也可加 --enable-rubyinterp 等 optional feature,詳見 ./configure --help)

  1. make
  2. make install

之後下 vim --version 應該就能看到新設定。


部份相關設定(非全部的新功能)

vimrc 基本設定部份

if version >= 703
  set conceallevel=1
  set concealcursor=nc
  set colorcolumn=+1
  set cinoptions+=L0
  set undofile
  set undodir=~/.vim/undofiles
  if !isdirectory(&undodir)
    call mkdir((&undodir, "p")
  endif
  map  <C-ScrollWheelDown> <ScrollWheelRight>
  map  <C-ScrollWheelUp>   <ScrollWheelLeft>
  imap <C-ScrollWheelDown> <ScrollWheelRight>
  imap <C-ScrollWheelUp>   <ScrollWheelLeft>
endif
  • conceal 的設定以不影響排版為主。下圖說明:

    上半 normal mode,下半 insert mode

    以 help 檔為例,平時只要把 |:autocmd| 左右的「|」塗黑,不必真的移除。
    但游標移到該行時,因為 CursorLine 有上深灰,所以能識別有文字被隱藏掉。
    最後在 insert  mode(如圖下半部)或  visual mode,應照實顯示原文。

  • colorcolumn 在 textwidth 右邊標顏色。
    從 PSPad 轉到 Vim 的時候就想要這功能,不過出來以後效果挺醜的(也太麤了吧),所以最後配合 colorscheme 調成只有在游標所在的行能看見。前面擷圖中最右邊黑 column 即是。
  • L 是 cindent 新增的設定值,參考 :help cinoptions-values。
    另有新增 J 給 JavaScript 用,不過似乎預設就包含了。
  • undofile 沒設定的話就完全沒效果……
    這可是讓 :e! 或下次進入 Vim 後還能 undo 的便利功能啊。
  • 新增的水平 ScrollWheel 系列,測試沒效,先放置不管。

偵測到檔案類型為 help 時要跑的設定(help_rc 這種寫法是參考 c9s 的 gist 學來的)

fun! s:help_rc()
  set number
  if version >= 703
    set conceallevel=1
    set concealcursor=nc
    set colorcolumn=+1
  endif
endf
au FileType help :call s:help_rc()

因 help 類型檔案會重設 conceal 設定所以為之。

colorscheme

if version >= 703
  hi Conceal ctermfg=240 ctermbg=Black guifg=#585860 guibg=Black
  hi ColorColumn ctermbg=Black guibg=Black
endif

為了前述效果所用的顏色設定(換個跟我不一樣的 colorscheme 就不適用了。)

FuzzyFinder 找分頁

如果用了之前寫的 Vim 分頁列(tabline)設定,script 空間就會出現變數 s:tabLineTabs,內含所有分頁編號、檔名等資料。

於是可以用 FuzzyFinder 尋找分頁,例如 map <Leader>fg 叫出下面選單:

僅供參考,某些檔案是沒法用 Vim 編輯的

接著按 <CR> 便會跳到該分頁,按 <LocalLeader><CR> 則是關閉該分頁。(當然 g:fuf_keyOpen 系列變數要先設好)


原始碼展開如下(放在 .vimrc)

let g:fuf_tabListener = {}

function! g:fuf_tabListener.onComplete(item, method)
  let l:tabnr = matchstr(a:item, '\d\+')
  if a:method == 4
    silent exec 'normal ' . l:tabnr . 'gt'
  else
    silent exec 'tabclose ' . l:tabnr
  endif
endf

function g:fuf_tabListener.onAbort()
endf

function! g:fuf_tabFinder()
  if exists("s:tabLineTabs")
    let l:tabList = []
    for tab in s:tabLineTabs
      let label = tab.n . '. ' . (strlen(tab.split) > 0 ? ('(' . tab.split . ')') : '') . tab.flag . tab.filename
      if tab.n == tabpagenr()
        let label = '*' . label
      endif
      call add(l:tabList, label)
    endfor
    call fuf#callbackitem#launch('', 1, 'tabs>', g:fuf_tabListener, l:tabList, 0)
  endif
endf

nnoremap <LocalLeader>fg :call g:fuf_tabFinder()<CR>

若沒有用之前寫的 tabline 設定,也可嘗試取該 tabline 原始碼產生 s:tabLineTabs 的部分來用;或從 :tabs 抓分頁資料,再仿照 用 FuzzyFinder 尋找 register 自己建立分頁資料 list。

預設分頁列的不足

  1. 無顯示分頁編號。想用 Ngt 跳到第 N 個分頁時,不易判斷 N 要下多少。
  2. 分頁很多時,超出畫面外的分頁無法顯示。(gVim 會顯示捲動按鈕,故無此問題)
原始的 tabline

修改方式

修改方式是重寫 tabline 這個選項,實際上頗為麻煩,因為整條 tabline 必須一次輸出,而非設定個別 tab 即可。參考 :help setting-tabline,其中給的例子也只提示基本功能而已。

受惠於 Vim 7.3 的幾個進化,這才把 tabline 調成比較堪用的狀態。調整如下:

  1. 顯示分頁編號
  2. 變更了分頁文字內容
    • 僅顯示檔名(不含路徑)
    • 顯示是否修改過(+)和分頁中的分割視窗數(n),大致上和預設相同
    • 新 buffer 顯示 '[New]' ,無檔案的 buffer 顯示 '[Scratch]'
  3. 不顯示關閉按鈕(原本擺在分頁列尾端的 'X')
  4. 使用幾個額外的自訂 highlight group
  5. 可指定分頁最小/最大寬度
  6. 分頁過多時,可指定是否自動平均分頁寬度;且可指定此狀況下的最小分頁寬度
  7. 可指定分頁過長而被截短時,要補上去的省略字串(例:'…'
  8. 可指定目前分頁左右,至少要顯示幾個分頁

原始碼

gist: 523783 - Vim tabline setting

console 擷圖

最後分頁第一個 ~ 來自 strCrop(中文不能只砍半個字),第二個 ~ 來自分頁的截短

gui 擷圖(「分割視窗數」使用了斜體)

前後都有省略符號

選項

因為沒寫成 plugin,只是放在 .vimrc 的 function,所以請直接改原始碼的下列項目:

  • let tabMinWidth = 0
    最小分頁寬度(0: 不限)
  • let tabMaxWidth = 40
    最大分頁寬度(0: 不限)
  • let tabMinWidthResized = 15
    設定 tabDivideEquel 有效時,採用的最小分頁寬度
  • let tabScrollOff = 5
    目前分頁左右至少顯示幾個分頁
  • let tabEllipsis = '…'
    分頁過長而被截短時,要顯示的替代文字
  • let tabDivideEquel = 0
    分頁總長超出畫面時,是否自動均分各分頁寬度

已知問題

在 Vim 7.3e BETA 測試,全型字和自訂 highlight 有時會造成 tabline 重繪不正確。有先發到 vim-dev 再看看情況。
不幸地 Vim 7.3f 狀況仍然存在。

為什麼要 Vim 7.3?

為了計算字串的實際顯示寬度(column 數),需用到新增的 strwidth() 函數。(目前程式若找不到此函數,就會改用 strlen(),計算全型字寬度時結果便不正確)
註:關於全型半型甚至無法確定的狀況,可參考 LGJ Notes | 全型字(Full-Width)、半型字(Half-Width)

此外 Vim 7.3 還新增了滑鼠拖曳分頁調整順序的功能,比起以往只能用 :tabmove N 方便得多。

相關配套調整

  • 永久顯示分頁列
    set showtabline=2
  • gui 也使用純文字的 tabline
    set guioptions-=e
  • 未知寬度的字以兩個 column 顯示
    一般中文字型建議設定 set ambiwidth=double 以避免 '…' 等不定寬度的字顯示錯誤。
  • 相關 highlight group
    因為增加了新的 gorup 而非使用預設值,所以需特別設定下列 highlight。
    建議放在自己的 colorscheme 裡面,或寫成 function 在 autocmd ColorScheme 時呼叫,否則根據經驗,Vim 讀取 session 後自訂的 highlight 會被重設。
    hi TabLine           cterm=underline ctermfg=15    ctermbg=242   gui=underline guibg=#6c6c6c guifg=White
    hi TabLineSel        cterm=bold      gui=NONE      guifg=White
    hi TabLineNr         cterm=underline ctermbg=238   guibg=#444444
    hi TabLineNrSel      cterm=bold      ctermfg=45    guifg=#00d7ff
    hi TabLineFill       cterm=reverse   gui=reverse
    hi TabLineMore       cterm=underline ctermfg=White ctermbg=236   gui=underline guifg=White   guibg=#303030
    hi TabLineSplitNr    cterm=underline ctermfg=148 ctermbg=240   gui=underline,italic guifg=#afd700   guibg=#6c6c6c
    hi TabLineSplitNrSel cterm=NONE      ctermfg=148 ctermbg=236   gui=NONE,italic      guifg=#afd700   guibg=#303030

Vim 外掛程式 FuzzyFinder 實在方便。(但這篇不含介紹)

除了找檔案、buffer、help 等 13 目標外,亦有 API 讓其他資料享用其搜尋介面。

以下使用 FuzzyFinder 的 Callback-Item 模式,列出所有 register,選取項目並開啟時,便直接貼上 register 內容,或噴到一個新視窗(可編輯後再手動 :%y x 存回 x register)。 尚有毛病但還堪用。

具體用例:

  • <LocalLeader>fp → 開啟 registers 選單。選好按 <CR> 貼上,或按 <LocalLeader><CR> 開到新視窗。
  • <LocalLeader>fP → 同上,但貼在游標之前。

選單展開(看得出顯示有問題)

單行太長時,顯示有問題

將 @7 內容開到新視窗

上面視窗即 @7 的內容


程式碼展開如下(放在 .vimrc)

let g:fuf_regListener = {}
let g:fuf_regListener.putBefore = 0   " 0: p, 1: P

function! g:fuf_regListener.onComplete(item, method)
  let l:regName = strpart(a:item, 1, 1)
  if a:method == 4
    silent exec 'normal "' . l:regName . (g:fuf_regListener.putBefore ? 'P' : 'p')
  else
    exec '7new [@' . escape( l:regName, '"' ) . ']'
    setlocal noswapfile buftype=nofile bufhidden=wipe
    exec '0put=@' . l:regName
    redraw
    setlocal nomodified
  endif
endf

function! g:fuf_regListener.onAbort()
endf

function! g:fuf_regFinder(putBefore)
  let g:fuf_regListener.putBefore = a:putBefore
  redir => l:regs
  silent exec ':registers'
  redir END
  let l:regList = split(l:regs, '\n')
  let l:regList = filter(l:regList, 'v:val =~ "' . escape('\m^".\s\{3,}\S\+', '\"') . '"')  " remove non-register lines
  "let l:regList = map(l:regList, 'substitute(v:val, "\\m.\\{' . &columns . '}\\zs.*", "...", "")')  " has problem with long line
  call fuf#callbackitem#launch('', 1, 'registers>', g:fuf_regListener, l:regList, 0)
endf

nnoremap <LocalLeader>fp :call g:fuf_regFinder(0)<CR>
nnoremap <LocalLeader>fP :call g:fuf_regFinder(1)<CR>

其中 onCompletemethod 參數,取決於選擇項目時按了哪個 FuzzyFinder 的 mapping(詳見 |fuf-options|):

  • 1 → 普通開啟
  • 2 → split 開啟
  • 3 → vsplit 開啟(我 map 到 <LocalLeader><CR>
  • 4 → tab 開啟(我 map 到 <CR>

程式在 register 單行內容很長時會有問題:選單顯示錯誤/無法取得 register 名稱。把後面截斷可解決(但截掉部份當然搜不到)。暫且加上 nowrap 減少狀況:autocmd BufEnter \[fuf\] setlocal nowrap


幾支 register 相關 plugin,也許這才是你要的:

  • YankRing.vimp 貼完以後,按 <CTRL-P> 可以立刻換成其他剪下的內容。也可開視窗檢視過去 yank 內容。
  • tregisters: 可列出 register 還能直接編輯,不過我沒裝成功。