Skip to content

bootleq/vim-cycle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cycle.vim

Cycle text within predefined candidates.

  • yesnoyes
  • JanuaryFebruaryMarch
  • trUefaLse   keep case by default
  • "'   can handle non-keywords
  • → 可   multibyte is fine
  • Rails MetalThrashTechnical Death   handle multi-words by visual selection, or smart auto search
  • <em>important</em><strong>important</strong>   tag pairs cycle together (even across lines)
  • quotedquoted   special pairs cycle together
  • ""^^   the two sides can be identical (must has only 1 char currently)
  • { :one => 'two' }{ one: 'two' }   now supports pattern replace like switch.vim
  • foo-bar-bazFOO_BAR_BAZfooBarBaz naming convention
  • covid-19-mk2covid_19Mk2Covid_19Mk2 alternative number handling
  • 民國 40昭和 26พ.ศ. 24951951   cycle calendar era systems with "year" option

Demo

The selection UI is telescope.nvim and sound is setup by vim-noise.

(This video has audio)

vim-cycle.mp4
Sound credit:

Configuration Example

let g:cycle_no_mappings = 1
let g:cycle_max_conflict = 14
let g:cycle_select_ui = 'telescope'
let g:cycle_conflict_ui = 'confirm'

nmap <silent> <LocalLeader>a <Plug>CycleNext
vmap <silent> <LocalLeader>a <Plug>CycleNext
nmap <silent> <Leader>a <Plug>CyclePrev
vmap <silent> <Leader>a <Plug>CyclePrev
nmap <silent> <LocalLeader>ga <Plug>CycleSelect
vmap <silent> <LocalLeader>ga <Plug>CycleSelect

let g:cycle_filetype_links = {
      \   'ghmarkdown': 'markdown',
      \   'typescriptreact': 'jsx',
      \ }

let g:cycle_default_groups = [
      \   [['true', 'false']],
      \   [['yes', 'no']],
      \   [['on', 'off'], 'match_word'],
      \   [['+', '-']],
      \   [['>', '<']],
      \   [['==', '!='], { 'cond': function('s:not_lua_context') }],
      \   [['0', '1']],
      \   [['and', 'or']],
      \   [['asc', 'desc']],
      \   [['', '']],
      \   [['', '']],
      \   [['', '', '']],
      \   [['', '', '', '', '', '', '', '']],
      \   [['lat', 'lon'], 'match_word'],
      \   [['latitude', 'longitude']],
      \   [['ancestor', 'descendant']],
      \   [['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
      \     'Friday', 'Saturday'], ['hard_case', {'name': 'Days'}]],
      \   [['":"', "':'"], 'sub_pairs'],
      \   [['(:)', '(:)', '「:」', '『:』'], 'sub_pairs'],
      \   [['民國', '令和', '平成', '昭和', '大正', '明治', 'พ.ศ.', 'CE'], 'year'],
      \ ]

" For fileType "lua" only
let g:cycle_default_groups_for_lua = [
      \   [['==', '~=']],
      \ ]

" For fileType "plaintex" only
let g:cycle_default_groups_for_plaintex = [
      \   [
      \     '\left(:\right)',
      \     '\mleft(:\mright)',
      \     '\Bigl(:\Bigr)',
      \     '(:)',
      \   ],
      \   'sub_pairs', 'hard_case', 'match_case'
      \ ]
      " Note (:) must be put at the end. The search runs in sequence,
      " an earlier ( match can short-circuit the following items.

" For filetype "ruby" only
" This uses "regex" option to works on patterns
" 1. cycles:  :bar =>    bar:
" 2. cycles: "foo" 'foo' :foo
let g:cycle_default_groups_for_ruby = [
      \   [[':\(\k\+\)\s*=>\s*', '\<\(\k\+\): '],
      \    #{regex: ['\1: ', ':\1 => '], name: 'ruby hash style'}],
      \   [['"\(\k\+\%([?!]\)\=\)"',
      \     '''\(\k\+\%([?!]\)\=\)''',
      \     ':\(\k\+\%([?!]\)\=\)\@>\%(\s*=>\)\@!'
      \    ], #{regex: ['''\1''', ':\1', '"\1"\2']}]
      \ ]

" For "jsx" only (not real filetype, but linked from typescriptreact)
let g:cycle_default_groups_for_jsx = [
      \   [['\v\="(.+)"', '\v\=''(.+)''', '\v\=\{`\$@!(.+)`}'], #{regex: ['=''\1''', '={`\1`}', '="\1"']}],
      \   [['={`${\(.\+\)}`}', '={`\@!\(.\+\)}'], #{regex: ['={\1}', '={`${\1}`}']}],
      \ ]

" For fileType "markdown" only
let g:cycle_default_groups_for_markdown = [
      \   [['^\(\s*\)- \[ \] ', '^\(\s*\)- \[x\] '],
      \    #{regex: ['\1- [x] ', '\1- [ ] '], name: 'markdown_task_item'}],
      \ ]

" For HTML, but here just blindly add to global groups
let g:cycle_default_groups += [
      \   [['h1', 'h2', 'h3', 'h4'], 'sub_tag'],
      \   [['ul', 'ol'], 'sub_tag'],
      \   [['em', 'strong', 'small'], 'sub_tag'],
      \ ]

let g:cycle_default_groups += [
      \   [['', '', '', '', '', '', '']],
      \   [['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
      \     'Aug', 'Sep', 'Oct', 'Nov', 'Dec']],
      \   [['January', 'February', 'March', 'April', 'May', 'June', 'July',
      \     'August', 'September', 'October', 'November', 'December']],
      \   [['portrait', 'landscape']],
      \ ]


" Set another mapping for certain groups
let s:tx_groups = [
      \   [['snake_case', 'kebab-case', 'camelCase_1',
      \     'PascalCase_1', 'SCREAMING_SNAKE_CASE'], 'naming'],
      \ ]
function! s:cycle_tx_groups() abort " {{{
  let groups = s:tx_groups
  " ... can do more dynamic handling to make your groups

  " must translate to internal format
  let parsed = map(deepcopy(groups), {i, g -> cycle#parse_group(g)})
  let parsed = flatten(parsed)
  return #{groups: parsed}
endfunction " }}}
nnoremap <silent> <LocalLeader>x <Cmd>call Cycle('w', 1, v:count1, <SID>cycle_tx_groups())<CR>
vnoremap <silent> <LocalLeader>x <Cmd>call Cycle('v', 1, v:count1, <SID>cycle_tx_groups())<CR>
nnoremap <silent> <LocalLeader>gx <Cmd>call CycleSelect('w', <SID>cycle_tx_groups())<CR>
vnoremap <silent> <LocalLeader>gx <Cmd>call CycleSelect('v', <SID>cycle_tx_groups())<CR>

Similar Projects

  • SwapIt by Michael Brown
    Original ideas of special features including visual multi-words, xml tag pairs, omni-complete cycling.

  • Cycle.vim by Zef
    Yes, there is already a plugin named 'Cycle'. Maybe I have to rename mine.

  • switch.vim by AndrewRadev
    Supports more complicated patterns like ruby :a => 'b' to a: 'b', which is generally unable to achieve by alternative projects.

  • vim-clurin by syngan
    Another early implementation, seems to have custom pattern and replace function features, but lacks documentation.

  • toggle.vim by Timo Teifel
    Maybe the very first plugin that introduced this idea.

Blog Posts

TODO

wiki/TODO

Development

Test

Run the test scripts, will clone vim-themis and execute it.

make test

Or directly run:

./test/run.sh
THEMIS_VIM=nvim ./test/run.sh
./test/run.sh --reporter dot --target 'respects .match_case"'
./test/run.sh --help

About

Cycle text within predefined candidates.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •