沒穿方服

索引

顯示╱隱藏內文
顯示具有 vim-cycle 標籤的文章。 顯示所有文章
顯示具有 vim-cycle 標籤的文章。 顯示所有文章

vim-cycle 1.4.0

14 年前發布 vim-cycle 0.1.0貼文)有得到一些迴響,但後來可能宣傳上被同名 zef/vim-cycle 掩蓋,接著又有 switch.vim 打破限制支援 pattern,繼續用 vim-cycle 的理由就不多了。

今年為了清掉古早 issue,幫專案加了 test,體質提昇後就開始加功能,結果變出了不錯的成果。

新增 regex 選項,大致就是跟 switch.vim 一樣的機制,例如 ruby 的 :bar => 可以變成 bar: ,以往是做不到的。 設定上也可以收割 switch.vim 的豐富資產,只要做一些微調(主要是把 vim dictionary 換成 list)即可。

新增 matcher / changer 定義,也就是「什麼東西要 cycle」「要怎麼 cycle」變成可抽換的,這麼一來 regex 也只是一種變體而已。

於是出現了紀年轉換,可以從民國年、日本元号、泰國佛曆、西元年之間轉換。
還有 naming convention 也被獨立出來,變成跟 regex 不太一樣的思維,比較好維護和擴充。

前陣子新增的 select 介面有時也很實用,將選項列出來用選的,而不是一個一個跳,也支援 telescope 等不同 UI。

錄了 demo 影片(影片有聲音):

歡迎多加利用或宣傳,至少讓類似專案的「類似專案」不要老是忽略我。

Group 是什麼

cycle.vim 搜尋相關候選字時 (例如目前是 true,應該要找到 false),會在一連串的 group 中查詢; 每個 group 是由 items 和 options 組成,以下便是一個簡單 group:
{ 'items': ['true', 'false'], 'options': {} }
如果想讓 foo 變成 bar,增加一個 items 為 ['foo', 'bar'] 的 group 就可以了。


怎麼設定 group

使用中的 groups 會存在 cycle_groups 這個變數,可以用 :echo string(g:cycle_groups) 查看; 但是這東西比較繁瑣,所以不建議直接修改它的值。

比較好的方式是在 .vimrc 定義 g:cycle_default_groups 這個變數, cycle.vim 啟動時會自動解析它,把需要的 group 都建好。

具體例子如下:

let g:cycle_default_groups = [
      \   [['true', 'false']],
      \   [['yes', 'no']],
      \   [['on', 'off']],
      \   [['+', '-']],
      \   [['>', '<']],
      \   [['"', "'"]],
      \   [['==', '!=']],
      \   [['0', '1']],
      \   [['and', 'or']],
      \   [['in', 'out']],
      \   [['up', 'down']],
      \   [['min', 'max']],
      \   [['get', 'set']],
      \   [['add', 'remove']],
      \   [['to', 'from']],
      \   [['read', 'write']],
      \   [['save', 'load', 'restore']],
      \   [['next', 'previous', 'prev']],
      \   [['only', 'except']],
      \   [['without', 'with']],
      \   [['exclude', 'include']],
      \   [['width', 'height']],
      \   [['asc', 'desc']],
      \   [['是', '否']],
      \   [['上', '下']],
      \   [['男', '女']],
      \   [['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
      \     'Friday', 'Saturday'], ['hard_case', {'name': 'Days'}]],
      \   [['{:}', '[:]', '(:)'], 'sub_pairs'],
      \   [['(:)', '「:」', '『:』'], 'sub_pairs'],
      \ ]

可以只為特定檔案類型設 group 嗎

cycle_groups 可以分成 global 和 buffer 兩個 scope(作用範圍)的版本,分別是 g:cycle_groupsb:cycle_groups 兩個變數。 搜尋的時候會以 buffer 版為優先,你可以讓 "get" 在 html 類型的 buffer 中轉為 "post",在其他類型 buffer 中則轉為 "set"

設定方式是在 .vimrc 定義 g:cycle_default_groups_for_{filetype},其中 {filetype} 表示想生效的檔案類型。
例如 html 專用的設定是:
let g:cycle_default_groups_for_html = [ ...(後略)

註:可以用 :echo string(b:cycle_groups) 檢查設定。


調整 group 行為

Group 的行為可以用 options 微調。目前(version 0.1.0)支援的選項如下:

  • name

    名稱,目前沒什麼用,只有處理衝突時(在多個 group 都有搜尋到目標字時)會顯示一下。

  • match_case

    搜尋候選字時,大小寫預設是不計的,所以 TruetruetrUe 都會被 cycle,只要設定其中一個即可。
    反之若要限制大小寫相符才 cycle,就要設定這個選項。

  • hard_case

    預設情形會保留關鍵字的大小寫位置,也就是 true/false 互換時,True 會變成 FalsetRUe 會變成 fALse
    這個選項可以停用此功能,互換時「若設定中是寫 fAlse,就一律換成 fAlse」。

  • sub_tag

    如果開啟這個選項,cycle.vim 會搜尋成對的 xml 開啟/結束標籤,有的話就一起 cycle 掉。
    例如 <EM>example</EM> 可以變成 <STRONG>example</STRONG>

  • sub_paris

    這個比較特別,它是 sub_pairend_withbegin_with 三個選項的簡易寫法,具體請看 doc。(建議用 sub_pairs 即可)

    [['(:)', '「:」'], 'sub_pairs'] 為例, 各個 item 會由 ":" 拆開, (:) 會拆成 「:」 會拆成
    cycle.vim 處理 "(" 時,會搜尋成對的 ")",若有的話就一起 cycle,
    例如 請保密) 可以變成 請保密」


具體要怎麼設定選項(options)

設定 group 時,每個 group 的第一個參數是 items,之後就都是 options 了。
支援以下各種型式:

  • [['true', 'false']] - 沒有 options
  • [['true', 'false'], {'match_case': 1}] - 以 hash 型式指定 options
  • [['true', 'false'], 'match_case'] - options 可以是字串,cycle.vim 會把它轉成 hash,hash 的預設值依各個 option 而不同,此處 'match_case' 的預設值為 1
  • [['true', 'false'], 'match_case', {'name': 'BOOL', 'sub_tag': 1}, 'hard_case'] - 字串和 hash 混著用也沒關係

你說完了沒

這篇應可滿足一般使用,我自己用到的也差不多這樣了。
在 doc 裡一些比較深入、低階的操作也有介紹,需要的話可以參考看看。

安裝

建議用 Vundle 裝 → Bundle 'bootleq/vim-cycle'
不然就用老方法,把所有檔案放到 runtimepath(預設在 ~/.vim)即可。
檔案在 https://github.com/bootleq/vim-cycle

簡易設定

要特別做的只有「哪些字能 cycle」設定,否則預設的字很少。
doc 287-341 行的範例 加進 vimrc,再視需要修改就可以了,應該很容易看懂。
進階選項再看 doc。

用途,例子

預設會加一個快速鍵 <Leader>a,其中 <Leader> 預設是 \ 所以實際是按 \a
(註:用 a 是取 Advance、Add 的 a,類似預設的 CTRL-A 功能)

<Leader>a 會把目前游標上的字換成下一個,以下舉例說明;若有特別標示,表示游標位置。

  • true false
    true 會變 false,false 會變 true;光這樣就很方便了。
  • Yes No
    大小寫會自動保持。
  • +-
  • ==!=

  • 特殊符號和中文都可以 cycle。
  • SundayMondayTuesdayWednesdayThursdayFridaySaturdaySunday
    typo 的機率降低了。
  • Rails MetalThrashTechnical Death
    即使游標在空白上,也能試著搜尋關鍵字。
  • $li.addClass('foo')$li.removeClass('foo') - jQuery element Attributes
  • position: 'upperLeft'position: 'upperRight' - MooTools Element.Position
  • :render_with_me:render_without_me - Rails alias_method_chain
    處理串在一起的字,實用性增加不少。
  • <em>example</em><strong>example</strong>
    HTML 標籤的開始/關閉標記可以一起 cycle。
  • 「例子『例子(例子
    成對的關鍵字可以一起 cycle。
    不過目前未支援頭尾相同的 pair,例如 "例子"

另外在 <Leader>a 前可以加 [count],例如 2\a 會 cycle 到第二個的候選, Monday 就會變成 Wednesday 而不是 Tuesday

還有在 visual mode 也可以用 <Leader>a,這樣就不會自動搜尋關鍵字,而是直接用選取的字來 cycle,遇到混淆時可以試試。

要怎麼把 Yes 換成 No? 標準答案是 ciw 再輸入 "No"。

更快的方法是寫 script 處理,很久以前看到一篇 Toggling yes-no, 把常用組合先定義好,只要一個鍵就能把 Yes 換成 No,再按一次就換回來,真是聰明啊~ 這方法我用了很久,當時改出來的設定如這個 gist

因為覺得方便,又有蠻多地方想改善,所以打算寫成 plugin。
搜尋 toggle 才發現真多人寫過,不過似乎大同小異,除了 SwapIt.vim

  • 用 visual 選起來,就可以處理含空白的 some words(原本的實作方式辦不到)。
  • 可以把 <H1>example</H1> 變成 <H2>example</H2>(一次換掉前後 tag)。
  • 可以吃 omni-completion 的結果,所以不必額外設定,就知道 CSS display block 可以換成 inlinenone 等等。
  • 其它。

我比較同意 SwapIt 的設計,認定 swap 這個功能,用力加強它。
SwapIt 的問題是實作還未成熟,所以我也 fork 它準備貢獻。 但是送第二個 pull request 前,覺得有點走不下去:

  • 繼續改下去,細部的實作幾乎都不一樣。
  • 重寫比重構簡單。
  • 在使用者立場,我想像的 interface 是另一番面貌,向前相容顯得多餘。
  • 我想全權處理所有問題。

另外對 SwapIt 這個名字也有點在意,至少我搜尋的時候就沒想到 swap 這關鍵字。
想起來最適合的字是 Cycle(因為是在一組字中循環,例如 top right bottom left),但是在 GitHub 一搜就發現已經有同名 plugin 了 ——zef/vim-cycle——很精簡,程式聰明漂亮,可惜作者太忙比較沒空更新。


結果我的 plugin 還是叫 cycle,這樣好嗎?

我把碰到的困難告訴兩位開發者 Michael BrownZef,他們都很開放,表示基本上不介意我這麼做(我想還是有點情緒干擾吧); 而雖然大家目標類似,但個人考量的點(有趣的是想法從 coding style 與用法設計就看得出來)還是不容易統合,變成一個專案。

這種情況下,我就先開發再說了,把手上的問題解決。

目前 0.1.0 版本已經是堪用階段: bootleq/vim-cycle - GitHub
之後會再寫一篇簡易使用說明。