Skip to content

Instantly share code, notes, and snippets.

@vimim
Last active July 31, 2024 13:55
Show Gist options
  • Save vimim/1937107 to your computer and use it in GitHub Desktop.
Save vimim/1937107 to your computer and use it in GitHub Desktop.
VimIM —— Vim 中文輸入法
" =================================
" VimIM —— Vim 中文輸入法
" =================================
:let vimimvim =<< trim EOF
https://gist.github.com/vimim/1937107
https://www.vim.org/scripts/script.php?script_id=2506
http://code.google.com/p/vimim/source/list
curl https://gist.githubusercontent.com/vimim/55f81fee12c965fe30274bcc538555ea/raw > bashrc
curl https://gist.githubusercontent.com/vimim/d717167eabf644f0f676e8e9e25cb079/raw > vimrc
EOF
let s:VimIM = [" ==== introduction ==== {{{"]
" =================================================
" File: vimim.vim
" Author: vimim <vimim@googlegroups.com>
" Readme: VimIM is a Vim plugin as an Input Method for i_CTRL-^ in Vim
" (1) do Chinese input without mode change: Midas touch
" (2) do Chinese search without typing Chinese: slash search
" Plug and Play
" (1) drop the script to the plugin folder: plugin/vimim.vim
" (2) drop the personized datafile: plugin/vimim.txt
" (3) drop the standard cjk datafile: plugin/vimim.cjk.txt
" Usage: VimIM takes advantage of the definition from Vim
" (1) use i_CTRL-^ for seamless Chinese input without popup window
" (2) use n Repeat the latest '/' or '?' ...
" ============================================= }}}
let s:VimIM += [" ==== initialization ==== {{{"]
" =================================================
if exists("g:Vimim_profile") || v:version<700 || !has("multi_byte")
finish
elseif &compatible
endif
scriptencoding utf-8
let g:Vimim_profile = reltime()
let s:plugin = expand("<sfile>:p:h")
function! s:vimim_initialize_backdoor()
" gvim -u $VIM/vimfiles/plugin/vimim.vim
let s:plugon = simplify(s:plugin . '/../../../hjkl/')
let s:titlestring = &titlestring
let s:cjk = { 'lines' : [] }
let s:english = { 'lines' : [], 'line' : "" }
let s:cjk.filename = s:vimim_filereadable("vimim.cjk.txt")
let s:english.filename = s:vimim_filereadable("vimim.txt")
let s:mandarin = len(s:english.filename) ? 0 : 1 " s/t chinese style
let s:hit_and_run = len(s:cjk.filename) ? 0 : 1 " onekey continuity
if len(s:cjk.filename)
highlight! PmenuSbar NONE
highlight! PmenuThumb NONE
highlight! Pmenu NONE
highlight! link PmenuSel NonText
endif
endfunction
function! s:vimim_debug(...)
sil!echo "\n::::::::::::::::::::::::"
if len(a:000) > 1
sil!echo join(a:000, " :: ")
elseif type(a:1) == type({})
for key in keys(a:1)
sil!echo key . '::' . a:1[key]
endfor
elseif type(a:1) == type([])
for line in a:1
sil!echo line
endfor
else
sil!echo string(a:1)
endif
sil!echo "::::::::::::::::::::::::\n\n"
endfunction
function! s:vimim_initialize_global()
highlight default lCursorIM guifg=NONE guibg=green gui=NONE
highlight! link lCursor lCursorIM
let s:space = ' '
let s:colon = ':'
let g:Vimim = "VimIM 中文輸入法"
let s:windowless_title = "VimIM"
let s:today = s:vimim_imode_today_now('itoday')
let s:multibyte = &encoding =~ "utf-8" ? 3 : 2
let s:localization = &encoding =~ "utf-8" ? 0 : 2
let s:seamless_positions = []
let s:starts = { 'row' : 0, 'column' : 1 }
let s:quanpin_table = {}
let s:abcd = split("'abcdvfgxz", '\zs')
let s:qwer = split("pqwertyuio", '\zs')
let s:az_list = map(range(97,122),"nr2char(".'v:val'.")")
let s:valid_keys = s:az_list
let s:valid_keyboard = "[0-9a-z']"
let s:shengmu_list = split('b p m f d t l n g k h j q x r z c s y w')
let s:pumheights = { 'current' : &pumheight, 'saved' : &pumheight }
let s:backend = { 'datafile' : {}, 'directory' : {} }
let s:ui = { 'root' : '', 'im' : '', 'quote' : 0, 'frontends' : [] }
let s:rc = {}
let s:plugin = s:plugin[-1:] != "/" ? s:plugin."/" : s:plugin
let s:windowless = {'onekey':0,'windowless':1,'dynamic':0,'static':0}
endfunction
function! s:vimim_set_frontend()
let i = 0
let keycode_string = ""
while i < 16*16
if nr2char(i) =~# s:valid_keyboard
let keycode_string .= nr2char(i)
endif
let i += 1
endwhile
let s:valid_keys = split(keycode_string, '\zs')
let logo = s:chinese('dscj')
let tail = s:mode.windowless ? s:today : ''
let g:Vimim = "VimIM".s:space.logo.' '.s:vimim_im_chinese().' '.tail
call s:vimim_set_title(g:Vimim)
endfunction
" ============================================= }}}
let s:VimIM += [" ==== easter eggs ==== {{{"]
" =================================================
function! s:vimim_easter_chicken(keyboard)
try
return eval("s:vimim_egg_" . a:keyboard . "()")
catch
sil!call s:vimim_debug('egg', a:keyboard, v:exception)
endtry
return []
endfunction
function! s:vimim_egg_vimimgame()
let mahjong = "春夏秋冬 梅兰竹菊 中發白囍 東南西北"
return split(mahjong)
endfunction
function! s:vimim_egg_vimim()
let eggs = []
call add(eggs, s:chinese('date', s:colon) . s:today)
let os = "win32unix win32 win64 macunix unix x11"
for computer in split(os)
if has(computer) | let os = computer | break | endif
endfor
let time = reltimestr(g:Vimim_profile) . ' seconds'
call add(eggs, s:chinese('computer', s:colon) . os . time)
let encoding = s:chinese('encoding', s:colon) . &encoding
call add(eggs, encoding . s:space . &fileencodings)
call add(eggs, s:chinese('env', s:colon) . v:lc_time)
let revision = v:progname ."=". v:version
call add(eggs, s:chinese('revision', s:colon) . revision)
let db = s:chinese('database', s:colon)
let input = "VimIM" . s:space . s:vimim_im_chinese() . s:space
if len(s:cjk.filename)
let input .= s:chinese('4corner') . s:space
call add(eggs, db.s:chinese('cjk',s:colon).s:cjk.filename)
endif
if len(s:english.filename)
let input .= s:chinese('english') . s:space
call add(eggs, db.s:chinese('english').db.s:english.filename)
endif
for [root, im] in s:ui.frontends
let backend = s:backend[root][im]
call add(eggs, db . backend.chinese . db . backend.name)
endfor
call add(eggs, s:chinese('input', s:colon) . input)
let results = map(eggs, 'v:val . " " ')
return results
endfunction
" ============================================= }}}
let s:VimIM += [" ==== hjkl vimimgame ==== {{{"]
" =================================================
function! s:vimim_cache()
let results = []
if !empty(s:pageup_pagedown)
let length = len(s:match_list)
if length > &pumheight
let page = s:pageup_pagedown * &pumheight
let partition = page ? page : length+page
let B = s:match_list[partition :]
let A = s:match_list[: partition-1]
let results = B + A
endif
elseif s:touch_me_not
if s:hjkl_h | let s:hjkl_h = 0
for line in s:match_list
let oneline = join(reverse(split(line,'\zs')),'')
call add(results, oneline)
endfor
elseif s:hjkl_l | let s:hjkl_l = 0
let results = reverse(copy(s:match_list))
endif
endif
return results
endfunction
function! s:vimim_get_hjkl_game(keyboard)
let keyboard = a:keyboard
let results = []
let poem = s:vimim_filereadable(keyboard)
if keyboard =~# '^i' && keyboard =~ '\d'
return s:vimim_imode_number(keyboard)
elseif keyboard ==# 'itoday' || keyboard ==# 'inow'
return [s:vimim_imode_today_now(keyboard)]
elseif keyboard == "''''''"
return split(join(s:vimim_egg_vimimgame(),""),'\zs')
elseif s:vimim_get_unicode_ddddd(keyboard)
return s:vimim_unicode_list(s:vimim_get_unicode_ddddd(keyboard))
elseif keyboard == "''"
let before = '' " get one chinese char before
if !empty(len(s:vimim_left()))
let before = getline(".")[col(".")-1-s:multibyte : col(".")-2]
endif
if empty(before) || before !~ '[^\x00-\xff]'
if s:vimim_cjk() | return s:vimim_cjk_match('u') | endif
let before = nr2char(19968) " the 214 standard unicode index
endif " gi ,.. space ,.. space
return s:vimim_unicode_list(char2nr(before))
elseif !empty(poem)
let results = s:vimim_read_txt(poem) " [hjkl] file in hjkl folder
elseif keyboard ==# "vim" || keyboard =~# "^vimim"
let results = s:vimim_easter_chicken(keyboard) " [hidden] egg
elseif len(getreg('"')) > 3
if keyboard == "''''" " visual: display buffer inside omni
let results = split(getreg('"'), '\n')
elseif keyboard =~ "'''''" " visual: display one-line-cjk property
let line = substitute(getreg('"'),'[\x00-\xff]','','g')
if len(line)
for chinese in split(line, '\zs')
let menu = s:vimim_cjk_property(chinese)
let menu .= repeat(" ", 38-len(menu))
call add(results, chinese . " " . menu)
endfor
endif
endif
endif
if len(results)
let s:touch_me_not = 1
if s:hjkl_m % 4
for i in range(s:hjkl_m % 4)
let results = s:vimim_hjkl_rotation(results)
endfor
endif
let results = [s:space] + results + [s:space]
endif
return results
endfunction
function! s:vimim_hjkl_rotation(lines)
let max = max(map(copy(a:lines), 'strlen(v:val)')) + 1
let multibyte = match(a:lines,'\w') < 0 ? s:multibyte : 1
let results = []
let rotations = []
for line in a:lines
let spaces = '' " rotation makes more sense for cjk
if (max-len(line)) / multibyte
for i in range((max-len(line))/multibyte)
let spaces .= s:space
endfor
endif
let line .= spaces
call add(rotations, line)
endfor
for i in range(max/multibyte)
let column = ''
for line in reverse(copy(rotations))
let line = get(split(line,'\zs'), i)
if !empty(line) | let column .= line | endif
endfor
call add(results, column)
endfor
return results
endfunction
function! s:vimim_chinese_rotation() range abort
:%s#\s*\r\=$##
:let lines = getline(a:firstline, a:lastline)
:let lines = s:vimim_hjkl_rotation(lines)
:%d
:for line in lines | put=line | endfor
endfunction
" ============================================= }}}
let s:VimIM += [" ==== user interface ==== {{{"]
" =================================================
function! s:vimim_dictionary_statusline()
let one = " dscj 4corner input date cjk computer database "
let one .= " hit fullwidth halfwidth english chinese "
let one .= " pin pinyin revision env encoding "
let two = " 点石成金,點石成金 四角号码,四角號碼 输入,輸入 日期 "
let two .= " 标准字库,標準字庫 电脑,電腦 词库,詞庫 打 全角 半角 "
let two .= " 英文 中文 拼 拼音 版本 环境,環境 编码,編碼 "
let s:chinese_statusline = s:vimim_key_value_hash(one, two)
endfunction
function! s:vimim_dictionary_punctuations()
let s:antonym = " 〖〗 () 《》 【】 ‘’ “”"
let one = " { } ( ) < > [ ] "
let two = join(split(join(split(s:antonym)[:3],''),'\zs'))
let antonyms = s:vimim_key_value_hash(one, two)
let one = " , . + - ~ ^ _ "
let two = " , 。 + - ~ …… —— "
let mini_punctuations = s:vimim_key_value_hash(one, two)
let one = " @ : # & % $ ! = ; ? * "
let two = "   : # & % ¥ ! = ; ? ﹡"
let most_punctuations = s:vimim_key_value_hash(one, two)
call extend(most_punctuations, antonyms)
let s:punctuations = {}
let s:key_evils = { '\' : "、", "'" : "‘’", '"' : "“”" }
let s:all_evils = {} " all punctuations for onekey_evils
call extend(s:all_evils, mini_punctuations)
call extend(s:all_evils, most_punctuations)
call extend(s:punctuations, mini_punctuations)
call extend(s:punctuations, most_punctuations)
endfunction
function! g:Vimim_slash()
let range = col(".") - 1 - s:starts.column
let chinese = strpart(getline("."), s:starts.column, range)
let word = substitute(chinese,'\w','','g')
let @/ = empty(word) ? @_ : word
let repeat_times = len(word) / s:multibyte
let key = repeat("\<Left>\<Delete>",repeat_times) . g:Vimim_esc()
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_bracket(offset)
let cursor = ""
let range = col(".") - 1 - s:starts.column
let repeat_times = range / s:multibyte + a:offset
if repeat_times
let cursor = repeat("\<Left>\<Delete>", repeat_times)
elseif repeat_times < 1
let cursor = strpart(getline("."), s:starts.column, s:multibyte)
endif
return cursor
endfunction
function! s:vimim_get_label(label)
let labeling = a:label == 10 ? "0" : a:label
return labeling
endfunction
function! s:vimim_set_pumheight()
let &completeopt = s:mode.windowless ? 'menu' : 'menuone'
let &pumheight = s:pumheights.saved
if empty(&pumheight)
let &pumheight = 5
endif
let &pumheight = s:mode.windowless ? 1 : &pumheight
let s:pumheights.current = copy(&pumheight)
if s:touch_me_not
let &pumheight = 0
elseif s:hjkl_l
let &pumheight = s:hjkl_l % 2 ? 0 : s:pumheights.current
endif
endfunction
" ============================================= }}}
let s:VimIM += [" ==== statusline ==== {{{"]
" =================================================
function! s:vimim_set_title(title)
if &laststatus < 2
let &titlestring = a:title
redraw
endif
if &term == 'screen'
if s:mode.windowless
let &l:statusline = '%{"'. a:title .'"}%<'
else
let &l:statusline = g:Vimim .' %h%m%r%=%-14.(%l,%c%V%) %P %<%f'
endif
endif
endfunction
function! s:vimim_im_chinese()
if empty(s:ui.im)
return ""
endif
let backend = s:backend[s:ui.root][s:ui.im]
return backend.chinese
endfunction
function! s:vimim_windowless_titlestring(cursor)
let logo = "VimIM"
let west = s:all_evils['[']
let east = s:all_evils[']']
let title = substitute(s:windowless_title, west.'\|'.east, ' ', 'g')
if title !~ '\s\+' . "'" . '\+\s\+'
let title = substitute(title,"'",'','g')
endif
let title = substitute(title, '\s\*\=\d\=\s', ' ', '')
let words = split(title)[1:]
let cursor = s:cursor_at_windowless + a:cursor
let hightlight = get(words, cursor)
if !empty(hightlight) && len(words) > 1
let west = join(words[1 : cursor-1]) . west
let east .= join(words[cursor+1 :])
let s:cursor_at_windowless = cursor
let keyboard = get(words,0)=='0' ? "" : get(words,0)
let star = len(s:hjkl) ? s:hjkl : len(s:english.line) ? '*' : ''
let logo .= ' '. keyboard .' '. star . west . hightlight . east
endif
sil!call s:vimim_set_title(logo)
endfunction
function! g:Vimim_esc()
let key = nr2char(27) " <Esc> is <Esc> if onekey or windowless
if s:mode.windowless
sil!let key = s:vimim_stop() . key " <Esc> to escape
elseif pumvisible()
let key = g:Vimim_one_key_correction() " <Esc> as correction
endif
sil!exe 'sil!return "' . key . '"'
endfunction
" ============================================= }}}
let s:VimIM += [" ==== lmap imap nmap ==== {{{"]
" =================================================
function! g:Vimim_label(key)
let key = a:key
if pumvisible()
let n = match(s:abcd, key)
if key =~ '\d'
let n = key < 1 ? 9 : key - 1
endif
let yes = repeat("\<Down>", n). '\<C-Y>'
let omni = '\<C-R>=g:Vimim()\<CR>'
if len(yes)
sil!call s:vimim_reset_after_insert()
endif
let key = yes . omni
elseif s:mode.windowless && key =~ '\d'
let key = s:vimim_windowless(key)
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_page(key)
let key = a:key
if pumvisible()
let page = '\<C-E>\<C-R>=g:Vimim()\<CR>'
if key =~ '[][]'
let left = key == "]" ? "\<Left>" : ""
let right = key == "]" ? "\<Right>" : ""
let _ = key == "]" ? 0 : -1
let backspace = '\<C-R>=g:Vimim_bracket('._.')\<CR>'
let key = '\<C-Y>' . left . backspace . right
elseif key =~ '[=.]'
let s:pageup_pagedown = &pumheight ? 1 : 0
let key = &pumheight ? page : '\<PageDown>'
elseif key =~ '[-,]'
let s:pageup_pagedown = &pumheight ? -1 : 0
let key = &pumheight ? page : '\<PageUp>'
endif
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_hjkl(key)
let key = a:key
if pumvisible()
if key ==# 'n' | call s:vimim_reset_after_insert()
elseif key ==# 'm' | let s:hjkl_m += 1
elseif key ==# 'h' | let s:hjkl_h += 1 " h
elseif key ==# 'j' | let key = '\<Down>' " j
elseif key ==# 'k' | let key = '\<Up>' " k
elseif key ==# 'l' | let s:hjkl_l += 1 " l
elseif key ==# 's' | let s:hjkl__ += 1 " s/t transfer
elseif key =~ "[/?]"
let key = '\<C-Y>\<C-R>=g:Vimim_slash()\<CR>' . key . '\<CR>'
elseif match(s:qwer, key) > -1
let s:hjkl .= match(s:qwer, key)
endif
let key = key == a:key ? '\<C-R>=g:Vimim()\<CR>' : key
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Punctuation(key)
let key = a:key
if pumvisible() || getline(".")[col(".")-2] !~ '\w'
if has_key(s:punctuations, a:key)
let key = s:punctuations[a:key]
endif
endif
if pumvisible() " the 2nd choice
let key = a:key == ";" ? '\<C-N>\<C-Y>' : '\<C-Y>' . key
endif
sil!exe 'sil!return "' . key . '"'
endfunction
" ============================================= }}}
let s:VimIM += [" ==== mode: windowless ==== {{{"]
" =================================================
function! g:Vimim_tab()
" (1) Tab in insert mode => start Tab or windowless
" (2) Tab in pumvisible => print out menu
let key = "\t"
if empty(len(s:vimim_left()))
elseif pumvisible() || s:ctrl6
let @0 = getline(".") " undo if dump out by accident
let key = s:vimim_screenshot()
else
let key = s:vimim_start() . s:vimim_onekey_action()
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! s:vimim_windowless(key)
" workaround to test if active completion
let key = a:key " gi \bslash space space
if s:pattern_not_found " gi ma space xj space ctrl+u space
elseif s:vimim_left() && s:keyboard !~ ' ' " gi mmm.. space 7 space
elseif s:omni " assume completion active
let key = len(a:key) ? '\<C-E>\<C-R>=g:Vimim()\<CR>' : '\<C-N>'
let cursor = empty(len(a:key)) ? 1 : a:key < 1 ? 9 : a:key-1
if s:vimim_cjk() " gi ma space isw8ql
let s:hjkl .= a:key " 1234567890 for windowless filter
else " 234567890 for windowless choice
let key = a:key =~ '[02-9]' ? repeat('\<C-N>', cursor) : key
endif
call s:vimim_windowless_titlestring(cursor)
else
call s:vimim_set_title(g:Vimim)
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_pagedown()
let key = ' '
if pumvisible()
let s:pageup_pagedown = &pumheight ? 1 : 0
let key = &pumheight ? g:Vimim() : '\<PageDown>'
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_space()
" (1) Space after English (valid keys) => trigger keycode menu
" (2) Space after omni popup menu => insert Chinese
" (3) Space after pattern not found => Space
" (4) Space after chinese windowless => <C-N> for next match
let key = " "
if pumvisible()
let key = '\<C-R>=g:Vimim()\<CR>'
let key = '\<C-Y>' . key
elseif s:pattern_not_found
elseif s:mode.dynamic
elseif s:seamless_positions == getpos(".") " gi ma space enter space
let s:smart_enter = 0 " Space is Space after Enter
else
let key = s:vimim_onekey_action()
endif
call s:vimim_reset_after_insert()
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_enter()
let s:omni = 0
let key = ""
if pumvisible()
let key = "\<C-E>"
let s:smart_enter = 1 " single Enter after English => seamless
elseif s:vimim_left() || s:mode.windowless
let s:smart_enter = 1 " gi ma space enter space space
if s:seamless_positions == getpos(".")
let s:smart_enter += 1
endif
else
let s:smart_enter = 0
endif
if s:smart_enter == 1
let s:seamless_positions = getpos(".")
else
let key = "\<CR>" " Enter is Enter after Enter
let s:smart_enter = 0
endif
sil!call s:vimim_set_title(g:Vimim)
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_one_key_correction()
" :help i_CTRL-U Delete all entered characters ...
let key = nr2char(21)
if s:mode.windowless
if s:omni " one_key_correction " gi m space a space ctrl+u
let s:omni = -1 " gi mamahuhu space ctrl+u ctrl+u
let key = '\<C-E>\<C-R>=g:Vimim()\<CR>\<Left>\<Delete>'
endif
elseif pumvisible()
let range = col(".") - 1 - s:starts.column
let key = '\<C-E>' . repeat("\<Left>\<Delete>", range)
endif
sil!call s:vimim_reset_after_insert()
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Vimim_backspace()
" <BS> has special meaning in all 3 states of popupmenu-completion
let s:omni = 0 " disable active omni completion state
let key = pumvisible() ? '\<C-R>=g:Vimim()\<CR>' : ''
let key = '\<Left>\<Delete>' . key
sil!exe 'sil!return "' . key . '"'
endfunction
function! s:vimim_screenshot()
let keyboard = get(split(s:keyboard),0)
let space = repeat(" ", virtcol(".")-len(keyboard)-1)
if s:keyboard =~ '^vim'
let space = "" " no need to format if it is egg
elseif !empty(s:keyboard)
call setline(".", keyboard)
endif
let saved_position = getpos(".")
for items in s:popup_list
let line = printf('%s', items.word)
if has_key(items, "abbr")
let line = printf('%s', items.abbr)
if has_key(items, "menu")
let line = printf('%s %s', items.abbr, items.menu)
endif
endif
put=space.line
endfor
call setpos(".", saved_position)
let key = g:Vimim_esc()
sil!exe 'sil!return "' . key . '"'
endfunction
" ============================================= }}}
let s:VimIM += [" ==== mode: onekey ==== {{{"]
" =================================================
function! s:vimim_onekey_action()
let s:hjkl = ""
let key = s:vimim_onekey_evils()
if empty(key)
if s:vimim_left()
let key = g:Vimim()
elseif s:mode.windowless
let key = s:vimim_windowless("")
endif
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! s:vimim_onekey_evils()
let key = "" " punctuations can be made not so evil ..
let one = getline(".")[col(".")-2] " one byte before
let two = getline(".")[col(".")-3] " two byte before
let onekey_evils = copy(s:all_evils)
call extend(onekey_evils, s:key_evils)
if getline(".")[col(".")-3 : col(".")-2] == ".." " before_before
" [game] dot dot => quotes => popup menu
let three = getline(".")[col(".")-4]
if col(".") < 5 || empty(three) || three =~ '\s'
let key = "''''''" " <= .. plays mahjong
elseif three =~# "[0-9a-z]"
let key = "'''" " <= xx.. plays hjkl_m
else
let key = "''" " <= 香.. plays same cjk
endif
let key = "\<BS>\<BS>" . key . '\<C-R>=g:Vimim()\<CR>'
elseif one =~# "[0-9a-z]" || one =~# '\s' || empty(one)
elseif two =~# "[0-9a-z]" || one =~# '\u'
let key = " " " ma,space => ma, space
elseif has_key(onekey_evils, one)
for char in keys(onekey_evils)
if two ==# char || two =~# '\u'
return " " " no transfer if punctuation punctuation
endif
endfor
let bs = onekey_evils[one] " make Chinese punctuation
if one == '"' || one == '"'
let bs .= '\<Left>'
endif
let key = "\<Left>\<Delete>" . bs
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! s:vimim_get_no_quote_head(keyboard)
let keyboard = a:keyboard
if keyboard =~ '\d'
return keyboard
endif
if s:hjkl_m && s:hjkl_m % 2 || keyboard =~ '^\l\l\+'."'''".'$'
" [shoupin] hjkl_m || sssss.. => sssss''' => s's's's's
let keyboard = substitute(keyboard, "'", "", 'g')
let keyboard = join(split(keyboard,'\zs'), "'")
endif
if keyboard =~ "'" && keyboard[-1:] != "'"
" [quote_by_quote] wo'you'yi'ge'meng
let keyboards = split(keyboard,"'")
let keyboard = get(keyboards,0)
let tail = join(keyboards[1:],"'")
let tail = len(tail) == 1 ? "'" . tail : tail
let s:keyboard = keyboard . " " . tail
endif
return keyboard
endfunction
" ============================================= }}}
let s:VimIM += [" ==== mode: chinese ==== {{{"]
" =================================================
function! s:vimim_set_keyboard_maps()
let common_punctuations = split("] [ = -")
let common_labels = s:ui.im =~ 'phonetic' ? [] : range(10)
let common_punctuations += split(". ,")
let common_labels += s:abcd[1:]
let pqwertyuio = s:vimim_cjk() ? s:qwer : []
for _ in pqwertyuio + split("h j k l m n / ? s")
sil!exe 'lnoremap<buffer><expr> '._.' g:Vimim_hjkl("'._.'")'
endfor
for _ in s:mode.windowless ? [] : common_punctuations
if _ !~ s:valid_keyboard
sil!exe 'lnoremap<buffer><expr> '._.' g:Vimim_page("'._.'")'
endif
endfor
for _ in common_labels
sil!exe 'lnoremap<buffer><expr> '._.' g:Vimim_label("'._.'")'
endfor
endfunction
function! s:vimim_set_im_toggle_list()
let toggle_list = s:ui.frontends
let s:frontends = copy(toggle_list)
let s:ui.frontends = copy(toggle_list)
endfunction
function! s:vimim_get_seamless(cursor_positions)
if empty(s:seamless_positions)
\|| s:seamless_positions[0] != a:cursor_positions[0]
\|| s:seamless_positions[1] != a:cursor_positions[1]
\|| s:seamless_positions[3] != a:cursor_positions[3]
return -1
endif
let current_line = getline(a:cursor_positions[1])
let seamless_column = s:seamless_positions[2]-1
let len = a:cursor_positions[2]-1 - seamless_column
let snip = strpart(current_line, seamless_column, len)
if empty(len(snip))
return -1
endif
for char in split(snip, '\zs')
if char !~ s:valid_keyboard
return -1
endif
endfor
return seamless_column
endfunction
" ============================================= }}}
let s:VimIM += [" ==== input: visual ==== {{{"]
" =================================================
function! g:Vimim_visual()
let key = ""
let lines = split(getreg('"'), '\n')
let line = get(lines,0)
let space = "\<C-R>=repeat(' '," .string(virtcol("'<'")-2). ")\<CR>"
if len(lines) == 1 && len(line) == s:multibyte
" highlight one chinese => get antonym or number loop
let results = s:vimim_imode_visual(line)
if !empty(results)
let key = "gvr" . get(results,0) . "ga"
endif
if s:vimim_cjk()
let line = match(s:cjk.lines, "^".line)
call s:vimim_set_title(s:space.get(s:cjk.lines,line))
endif
elseif match(lines,'\d') > -1 && join(lines) !~ '[^0-9[:blank:].]'
call setpos(".", getpos("'>'")) " vertical digit block =>
let sum = eval(join(lines,'+')) " count*average=summary
let ave = printf("%.2f", 1.0*sum/len(lines))
let line = substitute(ave."=".string(sum), '[.]0\+', '', 'g')
let line = string(len(lines)) . '*' . line
let key = "o" . nr2char(4) . space . " " . line . nr2char(27)
else
sil!call s:vimim_start()
let visual = nr2char(30) . "\<C-R>=g:Vimim()\<CR>"
if len(lines) < 2 " highlight multiple cjk => show property
let s:seamless_positions = getpos("'<'")
let chinese = get(split(line,'\zs'),0)
let ddddd = char2nr(chinese) =~ '\d\d\d\d\d' ? "'''''" : line
let key = "gvc" . ddddd . visual
else " highlighted block => play block with hjkl
let key = "O^\<C-D>" . space . "''''" . visual
endif
endif
return feedkeys(key,"n")
endfunction
function! s:vimim_imode_visual(char_before)
let items = []
let numbers = []
let results = []
if empty(s:loops)
for i in range(len(s:numbers))
call add(items, split(s:numbers[i],'\zs'))
endfor
for j in range(len(get(items,0)))
let number = ""
for line in items
let number .= get(line,j)
endfor
call add(numbers, number)
endfor
for loop in numbers + split(s:antonym) + split("金石 真假 胜败")
let loops = split(loop, '\zs')
for i in range(len(loops))
let j = i==len(loops)-1 ? 0 : i+1
let s:loops[loops[i]] = loops[j]
endfor
endfor
endif
let char_before = a:char_before
if has_key(s:loops, char_before)
let start = char_before
let next = ""
while start != next
let next = s:loops[char_before]
call add(results, next)
let char_before = next
endwhile
endif
return results
endfunction
" ============================================= }}}
let s:VimIM += [" ==== input: number ==== {{{"]
" =================================================
function! s:vimim_dictionary_numbers()
let s:loops = {}
let s:numbers = {}
let s:numbers.1 = "一壹⑴①甲"
let s:numbers.2 = "二贰⑵②乙"
let s:numbers.3 = "三叁⑶③丙"
let s:numbers.4 = "四肆⑷④丁"
let s:numbers.5 = "五伍⑸⑤戊"
let s:numbers.6 = "六陆⑹⑥己"
let s:numbers.7 = "七柒⑺⑦庚"
let s:numbers.8 = "八捌⑻⑧辛"
let s:numbers.9 = "九玖⑼⑨壬"
let s:numbers.0 = "〇零⑽⑩癸"
let s:quantifiers = copy(s:numbers)
let s:quantifiers.2 .= "两俩"
let s:quantifiers.b = "百佰步把包杯本笔部班"
let s:quantifiers.c = "次餐场串处床"
let s:quantifiers.d = "第度点袋道滴碟顶栋堆对朵堵顿"
let s:quantifiers.f = "分份发封付副幅峰方服"
let s:quantifiers.g = "个根股管"
let s:quantifiers.h = "行盒壶户回毫"
let s:quantifiers.j = "斤家具架间件节剂具捲卷茎记"
let s:quantifiers.k = "克口块棵颗捆孔"
let s:quantifiers.l = "里粒类辆列轮厘领缕"
let s:quantifiers.m = "米名枚面门秒"
let s:quantifiers.n = "年"
let s:quantifiers.p = "磅盆瓶排盘盆匹片篇撇喷"
let s:quantifiers.q = "千仟群"
let s:quantifiers.r = "日人"
let s:quantifiers.s = "十拾时升艘扇首双所束手"
let s:quantifiers.t = "天吨条头通堂趟台套桶筒贴"
let s:quantifiers.w = "万位味碗窝晚微"
let s:quantifiers.x = "席些项"
let s:quantifiers.y = "月元叶亿"
let s:quantifiers.z = "种只张株支总枝盏座阵桩尊则站幢宗兆"
endfunction
function! s:vimim_dictionary_keycodes()
let s:keycodes = {}
let cloud = ' google sogou baidu qq mycloud '
for key in split( cloud . ' pinyin ')
let s:keycodes[key] = "['a-z0-9]"
endfor
for key in split('array30 phonetic')
let s:keycodes[key] = "[.,a-z0-9;/]"
endfor
for key in split('zhengma taijima wubi cangjie hangul xinhua quick')
let s:keycodes[key] = "['a-z]"
endfor
let s:keycodes.wu = "['a-z]" " s:ui.quote=1
let s:keycodes.nature = "['a-z]" " s:ui.quote=1
let s:keycodes.yong = "['a-z.;/]" " s:ui.quote=1
let s:keycodes.erbi = "['a-z.;/,]" " s:ui.quote=1
let s:keycodes.boshiamy = "['a-z.],[]" " s:ui.quote=1
let ime = ' pinyin_sogou pinyin_quote_sogou pinyin_huge'
let ime .= ' pinyin_fcitx pinyin_canton pinyin_hongkong'
let ime .= ' wubi98 wubi2000 wubijd wubihf'
let s:all_vimim_input_methods = keys(s:keycodes) + split(ime)
endfunction
let s:translators = {}
function! s:translators.translate(english) dict
let inputs = split(a:english)
return join(map(inputs,'get(self.dict,tolower(v:val),v:val)'), '')
endfunction
function! s:vimim_imode_today_now(keyboard)
let one = " year sunday monday tuesday wednesday thursday"
let one .= " friday saturday month day hour minute second"
let two = join(split("年 日 一 二 三 四 五 六"), " 星期")
let two .= " 月 日 时 分 秒"
let chinese = copy(s:translators)
let chinese.dict = s:vimim_key_value_hash(one, two)
let time = '公元'
let time .= strftime("%Y") . ' year '
let time .= strftime("%m") . ' month '
let time .= strftime("%d") . ' day '
if a:keyboard ==# 'itoday'
let time .= s:space .' '. strftime("%A")
elseif a:keyboard ==# 'inow'
let time .= strftime("%H") . ' hour '
let time .= strftime("%M") . ' minute '
let time .= strftime("%S") . ' second '
endif
let filter = "substitute(" . 'v:val' . ",'^0','','')"
return chinese.translate(join(map(split(time), filter)))
endfunction
function! s:vimim_imode_number(keyboard)
let keyboard = a:keyboard
let ii = keyboard[0:1] " sample: i88 ii88 isw8ql iisw8ql
let keyboard = ii==#'ii' ? keyboard[2:] : keyboard[1:]
let dddl = keyboard=~#'^\d*\l\{1}$' ? keyboard[:-2] : keyboard
let number = ""
let keyboards = split(dddl, '\ze')
for char in keyboards
if has_key(s:quantifiers, char)
let quantifier_list = split(s:quantifiers[char], '\zs')
let chinese = get(quantifier_list, 0)
if ii ==# 'ii' && char =~# '[0-9sbq]'
let chinese = get(quantifier_list, 1)
endif
let number .= chinese
endif
endfor
if empty(number) | return [] | endif
let results = [number]
let last_char = keyboard[-1:]
if !empty(last_char) && has_key(s:quantifiers, last_char)
let quantifier_list = split(s:quantifiers[last_char], '\zs')
if keyboard =~# '^[ds]\=\d*\l\{1}$'
if keyboard =~# '^[ds]'
let number = strpart(number,0,len(number)-s:multibyte)
endif
let results = map(copy(quantifier_list), 'number . v:val')
elseif keyboard =~# '^\d*$' && len(keyboards)<2 && ii != 'ii'
let results = quantifier_list
endif
endif
return results
endfunction
" ============================================= }}}
let s:VimIM += [" ==== input: unicode ==== {{{"]
" =================================================
function! s:vimim_i18n(line)
let line = a:line
if s:localization == 1
return iconv(line, "chinese", "utf-8")
elseif s:localization == 2
return iconv(line, "utf-8", &enc)
endif
return line
endfunction
function! s:vimim_unicode_list(ddddd)
let results = []
for i in range(99)
call add(results, nr2char(a:ddddd+i))
endfor
return results
endfunction
function! s:vimim_get_unicode_ddddd(keyboard)
let ddddd = 0
if a:keyboard =~# '^u\x\{4}$' " u9f9f => 40863
let ddddd = str2nr(a:keyboard[1:],16)
elseif a:keyboard =~# '^\d\{5}$' " 39532 => 39532
let ddddd = str2nr(a:keyboard, 10)
endif
let max = &encoding=="utf-8" ? 19968+20902 : 0xffff
if ddddd < 8080 || ddddd > max
let ddddd = 0
endif
return ddddd
endfunction
function! s:vimim_unicode_to_utf8(xxxx)
let utf8 = '' " u808f => 32911 => e8828f
let ddddd = str2nr(a:xxxx, 16)
if ddddd < 128
let utf8 .= nr2char(ddddd)
elseif ddddd < 2048
let utf8 .= nr2char(192+((ddddd-(ddddd%64))/64))
let utf8 .= nr2char(128+(ddddd%64))
else
let utf8 .= nr2char(224+((ddddd-(ddddd%4096))/4096))
let utf8 .= nr2char(128+(((ddddd%4096)-(ddddd%64))/64))
let utf8 .= nr2char(128+(ddddd%64))
endif
return utf8
endfunction
function! s:vimim_left()
let key = 0 " validate the character on the left of the cursor
let one_byte_before = getline(".")[col(".")-2]
if one_byte_before =~ '\s' || empty(one_byte_before)
let key = ""
elseif one_byte_before =~# s:valid_keyboard
let key = 1
endif
return key
endfunction
function! s:vimim_key_value_hash(single, double)
let hash = {}
let singles = split(a:single)
let doubles = split(a:double)
for i in range(len(singles))
let hash[get(singles,i)] = get(doubles,i)
endfor
return hash
endfunction
function! s:chinese(...)
let chinese = ""
for english in a:000
let cjk = english
if has_key(s:chinese_statusline, english)
let twins = split(s:chinese_statusline[english], ",")
let cjk = get(twins, 0)
if len(twins) > 1 && s:mandarin
let cjk = get(twins,1)
endif
endif
let chinese .= cjk
endfor
return chinese
endfunction
" ============================================= }}}
let s:VimIM += [" ==== input: cjk ==== {{{"]
" =================================================
function! s:vimim_cjk()
if empty(s:cjk.filename)
return 0
elseif empty(s:cjk.lines)
let s:cjk.lines = s:vimim_read_txt(s:cjk.filename)
if len(s:cjk.lines) != 20902 | return 0 | endif
endif
return 1
endfunction
function! s:vimim_cjk_in_4corner(chinese, info)
let digit_head = "" " gi ma 马  => 7712 <=> mali 7 4
let digit_tail = "" " gi mali 马力 => 7 4002 <=> mali74
let chinese = substitute(a:chinese,'[\x00-\xff]','','g')
for cjk in split(chinese, '\zs')
let line = match(s:cjk.lines, "^" . cjk)
if line > -1
let values = split(get(s:cjk.lines, line))
let digit_head .= get(values,1)[:0]
let digit_tail = get(values,1)[1:]
endif
endfor
let key = digit_head . digit_tail
let key = empty(a:info) && match(key, "^".s:hjkl) < 0 ? 0 : key
return key
endfunction
function! s:vimim_cjk_property(chinese)
let ddddd = char2nr(a:chinese)
let xxxx = printf('u%04x', ddddd)
let unicode = ddddd . s:space . xxxx
if s:vimim_cjk()
let unicode = repeat(s:space,3) . xxxx . s:space . ddddd
let line = match(s:cjk.lines, "^" . a:chinese)
if line > -1
let values = split(get(s:cjk.lines, line))
let digit = get(values, 1) . s:space
let frequency = get(values, -1) !~ '\D' ? 1 : 0
let pinyin = join(frequency ? values[2:-2] : values[2:])
let unicode = digit . xxxx . s:space . pinyin
endif
endif
return unicode
endfunction
function! s:vimim_cjk_match(key)
let key = a:key
if empty(key) || empty(s:vimim_cjk()) | return [] | endif
let grep = ""
let grep_frequency = '.*' . '\s\d\+$'
if key =~ '\d'
if key =~# '^\l\l\+[1-4]\>' && empty(len(s:hjkl))
let grep = key . '[a-z ]' " cjk pinyin: huan2hai2 yi1
else
let digit = ""
if key =~ '^\d\+' && key !~ '[^0-9]'
let digit = key " free style digit: 7 77 771 7712
elseif key =~# '^\l\+\d\+' " free style: ma7 ma77 ma771 ma7712
let digit = substitute(key,'\a','','g')
endif
if !empty(digit)
let space = '\d\{' . string(4-len(digit)) . '}'
let space = len(digit)==4 ? "" : space
let grep = '\s\+' . digit . space . '\s'
let alpha = substitute(key,'\d','','g')
if len(alpha)
let grep .= '\(\l\+\d\)\=' . alpha " le|yue: le4yue4
elseif len(key) == 1
let grep .= grep_frequency " grep l|y: happy music
endif
endif
endif
else
if len(key) == 1 " one cjk by frequency y72/yue72 l72/le72
let grep = '[ 0-9]' . key . '\l*\d' . grep_frequency
let grep = key == 'u' ? ' u\( \|$\)' : grep " 214 unicode
elseif key =~# '^\l\+' " cjk list: /huan /hai /yet /huan2 /hai2
let grep = '[ 0-9]' . key . '[0-9]'
endif
endif
let results = []
if !empty(grep)
let line = match(s:cjk.lines, grep)
while line > -1
let fields = split(get(s:cjk.lines, line))
let frequency = get(fields,-1)=~'\l' ? 9999 : get(fields,-1)
call add(results, get(fields,0) . ' ' . frequency)
let line = match(s:cjk.lines, grep, line+1)
endwhile
endif
let results = sort(results, "s:vimim_sort_on_last")
let filter = "strpart(" . 'v:val' . ", 0, s:multibyte)"
return map(results, filter)
endfunction
function! s:vimim_get_cjk_head(key)
let key = a:key
if empty(s:cjk.filename) || key =~ "'"
return ""
endif
if key =~# '^i' && empty (s:english.line) " iuuqwuqew => 77127132
let key = s:vimim_qwertyuiop_1234567890(key[1:])
endif
let head = ""
if s:touch_me_not || len(key) == 1
let head = key
elseif key =~ '\d'
if key =~ '^\d' && key !~ '\D'
let head = len(key) > 4 ? s:vimim_get_head(key, 4) : key
let s:hjkl = empty(len(s:hjkl)) ? head : s:hjkl
elseif key =~# '^\l\+\d\+\>' " 7712 in 77124002
let partition = match(key,'\d') " ma7 ma77 ma771
let head = key[0 : partition-1] " mali in mali74
let tail = key[partition :] " 74 in mali74
if empty(s:vimim_get_pinyin(head)) && tail =~ '[1-4]'
return key " pinyin with tone: ma1/ma2/ma3/ma4
endif
let s:hjkl = empty(len(s:hjkl)) ? tail : s:hjkl
elseif key =~# '^\l\+\d\+' " wo23 for input wo23you40
let partition = match(key, '\(\l\+\d\+\)\@<=\D')
let head = s:vimim_get_head(key, partition)
endif
elseif empty(s:english.line) " muuqwxeyqpjeqqq => m7712x3610j3111
if key =~# '^\l' && len(key)%5 < 1 " awwwr/a2224 arrow color
let dddd = s:vimim_qwertyuiop_1234567890(key[1:4])
if !empty(dddd)
let key = key[0:0] . dddd . key[5:-1]
let head = s:vimim_get_head(key, 5)
endif
else
let head = key " get single character from cjk
endif
endif
return head
endfunction
function! s:vimim_get_head(keyboard, partition)
if a:partition < 0 | return a:keyboard | endif
let head = a:keyboard[0 : a:partition-1]
if s:keyboard !~ '\S\s\S'
let s:keyboard = head
let tail = a:keyboard[a:partition : -1]
if !empty(tail)
let s:keyboard = head . " " . tail
endif
endif
return head
endfunction
function! s:vimim_qwertyuiop_1234567890(keyboard)
if a:keyboard =~ '\d' | return "" | endif
let dddd = "" " output is 7712 for input uuqw
for char in split(a:keyboard, '\zs')
let digit = match(s:qwer, char)
if digit < 0
return ""
else
let dddd .= digit
endif
endfor
return dddd
endfunction
function! s:vimim_sort_on_last(line1, line2)
let line1 = get(split(a:line1),-1) + 1
let line2 = get(split(a:line2),-1) + 1
if line1 < line2
return -1
elseif line1 > line2
return 1
endif
return 0
endfunction
function! s:vimim_chinese_transfer() range abort
" the quick and dirty way to transfer between Chinese
if s:vimim_cjk()
exe a:firstline.",".a:lastline.'s/./\=s:vimim_1to1(submatch(0))'
endif
endfunction
function! s:vimim_1to1(char)
if a:char =~ '[\x00-\xff]' | return a:char | endif
let grep = '^' . a:char
let line = match(s:cjk.lines, grep, 0)
if line < 0 | return a:char | endif
let values = split(get(s:cjk.lines, line))
let traditional_chinese = get(split(get(values,0),'\zs'),1)
return empty(traditional_chinese) ? a:char : traditional_chinese
endfunction
" ============================================= }}}
let s:VimIM += [" ==== input: english ==== {{{"]
" =================================================
function! s:vimim_get_english(keyboard)
if empty(s:english.filename)
return "" " english: obama/now/version/ice/o2
elseif empty(s:english.lines)
let s:english.lines = s:vimim_read_txt(s:english.filename)
endif " [sql] select english from vimim.txt
let grep = '^' . a:keyboard . '\s\+'
let cursor = match(s:english.lines, grep)
let keyboards = s:vimim_get_pinyin(a:keyboard)
if cursor < 0 && len(a:keyboard) > 3 && len(keyboards)
let grep = '^' . get(split(a:keyboard,'\d'),0) " mxj7 => mxj
let cursor = match(s:english.lines, grep)
endif
let oneline = "" " [pinyin] cong => cong
if cursor > -1 " [english] congr => congratulation
let oneline = get(s:english.lines, cursor)
if a:keyboard != get(split(oneline),0)
let pairs = split(oneline) " haag haagendazs
let oneline = join(pairs[1:] + pairs[:0])
let oneline = a:keyboard . " " . oneline
endif
endif
return oneline
endfunction
function! s:vimim_filereadable(filename)
let datafile_1 = s:plugin . a:filename
let datafile_2 = s:plugon . a:filename
if filereadable(datafile_1)
return datafile_1
elseif filereadable(datafile_2)
return datafile_2
endif
return ""
endfunction
function! s:vimim_read_txt(datafile)
let lines = []
if filereadable(a:datafile)
if s:localization
for line in readfile(a:datafile)
call add(lines, s:vimim_i18n(line))
endfor
else
return readfile(a:datafile)
endif
endif
return lines
endfunction
" ============================================= }}}
let s:VimIM += [" ==== input: pinyin ==== {{{"]
" =================================================
function! s:vimim_get_all_valid_pinyin_list()
return split(" 'a 'ai 'an 'ang 'ao ba bai ban bang bao bei ben beng bi
\ bian biao bie bin bing bo bu ca cai can cang cao ce cen ceng cha chai
\ chan chang chao che chen cheng chi chong chou chu chua chuai chuan
\ chuang chui chun chuo ci cong cou cu cuan cui cun cuo da dai dan dang
\ dao de dei deng di dia dian diao die ding diu dong dou du duan dui dun
\ duo 'e 'ei 'en 'er fa fan fang fe fei fen feng fiao fo fou fu ga gai
\ gan gang gao ge gei gen geng gong gou gu gua guai guan guang gui gun
\ guo ha hai han hang hao he hei hen heng hong hou hu hua huai huan huang
\ hui hun huo 'i ji jia jian jiang jiao jie jin jing jiong jiu ju juan
\ jue jun ka kai kan kang kao ke ken keng kong kou ku kua kuai kuan kuang
\ kui kun kuo la lai lan lang lao le lei leng li lia lian liang liao lie
\ lin ling liu long lou lu luan lue lun luo lv ma mai man mang mao me mei
\ men meng mi mian miao mie min ming miu mo mou mu na nai nan nang nao ne
\ nei nen neng 'ng ni nian niang niao nie nin ning niu nong nou nu nuan
\ nue nuo nv 'o 'ou pa pai pan pang pao pei pen peng pi pian piao pie pin
\ ping po pou pu qi qia qian qiang qiao qie qin qing qiong qiu qu quan
\ que qun ran rang rao re ren reng ri rong rou ru ruan rui run ruo sa sai
\ san sang sao se sen seng sha shai shan shang shao she shei shen sheng
\ shi shou shu shua shuai shuan shuang shui shun shuo si song sou su suan
\ sui sun suo ta tai tan tang tao te teng ti tian tiao tie ting tong tou
\ tu tuan tui tun tuo 'u 'v wa wai wan wang wei wen weng wo wu xi xia
\ xian xiang xiao xie xin xing xiong xiu xu xuan xue xun ya yan yang yao
\ ye yi yin ying yo yong you yu yuan yue yun za zai zan zang zao ze zei
\ zen zeng zha zhai zhan zhang zhao zhe zhen zheng zhi zhong zhou zhu
\ zhua zhuai zhuan zhuang zhui zhun zhuo zi zong zou zu zuan zui zun zuo")
endfunction
function! s:vimim_quanpin_transform(pinyin)
if empty(s:quanpin_table)
for key in s:vimim_get_all_valid_pinyin_list()
if key[0] == "'"
let s:quanpin_table[key[1:]] = key[1:]
else
let s:quanpin_table[key] = key
endif
endfor
for shengmu in s:shengmu_list + split("zh ch sh")
let s:quanpin_table[shengmu] = shengmu
endfor
endif
let item = a:pinyin
let index = 0 " follow ibus rule, plus special case for fan'guo
let pinyinstr = ""
while index < len(item)
if item[index] !~ "[a-z]"
let index += 1
continue
endif
for i in range(6,1,-1)
let tmp = item[index : ]
if len(tmp) < i
continue
endif
let end = index+i
let matchstr = item[index : end-1]
if has_key(s:quanpin_table, matchstr)
let tempstr = item[end-1 : end]
let tempstr2 = item[end-2 : end+1]
let tempstr3 = item[end-1 : end+1]
let tempstr4 = item[end-1 : end+2]
if (tempstr == "ge" && tempstr3 != "ger")
\ || (tempstr == "ne" && tempstr3 != "ner")
\ || (tempstr4 == "gong" || tempstr3 == "gou")
\ || (tempstr4 == "nong" || tempstr3 == "nou")
\ || (tempstr == "ga" || tempstr == "na")
\ || tempstr2 == "ier" || tempstr == "ni"
\ || tempstr == "gu" || tempstr == "nu"
if has_key(s:quanpin_table, matchstr[:-2])
let i -= 1
let matchstr = matchstr[:-2]
endif
endif
let pinyinstr .= "'" . s:quanpin_table[matchstr]
let index += i
break
elseif i == 1
let pinyinstr .= "'" . item[index]
let index += 1
break
else
continue
endif
endfor
endwhile
return pinyinstr[0] == "'" ? pinyinstr[1:] : pinyinstr
endfunction
function! s:vimim_more_pinyin_datafile(keyboard, sentence)
let results = []
let backend = s:backend[s:ui.root][s:ui.im]
for candidate in s:vimim_more_pinyin_candidates(a:keyboard)
let pattern = '^' . candidate . '\>'
let cursor = match(backend.lines, pattern, 0)
if cursor < 0
continue
elseif a:sentence
return [candidate]
endif
let oneline = get(backend.lines, cursor)
call extend(results, s:vimim_make_pairs(oneline))
endfor
return results
endfunction
function! s:vimim_get_pinyin(keyboard)
let keyboard = s:vimim_quanpin_transform(a:keyboard)
let results = split(keyboard, "'")
if len(results) > 1
return results
endif
return []
endfunction
function! s:vimim_more_pinyin_candidates(keyboard)
" make standard menu layout: mamahuhu => mamahu, mama
if len(s:english.line) || s:ui.im !~ 'pinyin'
return []
endif
let candidates = []
let keyboards = s:vimim_get_pinyin(a:keyboard)
if len(keyboards)
for i in reverse(range(len(keyboards)-1))
let candidate = join(keyboards[0 : i], "")
if !empty(candidate)
call add(candidates, candidate)
endif
endfor
if len(candidates) > 2
let candidates = candidates[0 : len(candidates)-2]
endif
endif
return candidates
endfunction
" ============================================= }}}
let s:VimIM += [" ==== backend: file ==== {{{"]
" =================================================
function! s:vimim_set_datafile(im, datafile)
let im = a:im
" if isdirectory(a:datafile)
" return
" else
" let im = 'pinyin'
" endif
let s:ui.root = 'datafile'
let s:ui.im = im
call insert(s:ui.frontends, [s:ui.root, s:ui.im])
let s:backend.datafile[im] = {}
let s:backend.datafile[im].root = s:ui.root
let s:backend.datafile[im].im = s:ui.im
let s:backend.datafile[im].name = a:datafile
let s:backend.datafile[im].chinese = s:chinese(im)
let s:backend.datafile[im].lines = []
endfunction
function! s:vimim_sentence_datafile(keyboard)
let backend = s:backend[s:ui.root][s:ui.im]
let fuzzy = s:ui.im =~ 'pinyin' ? ' ' : ""
let pattern = '^\V' . a:keyboard . fuzzy
let cursor = match(backend.lines, pattern)
if cursor > -1 | return a:keyboard | endif
let candidates = s:vimim_more_pinyin_datafile(a:keyboard,1)
if !empty(candidates) | return get(candidates,0) | endif
let max = len(a:keyboard)
while max > 1
let max -= 1
let pattern = '^\V' . strpart(a:keyboard,0,max) . ' '
let cursor = match(backend.lines, pattern)
if cursor > -1 | break | endif
endwhile
return cursor < 0 ? "" : a:keyboard[: max-1]
endfunction
function! s:vimim_get_from_datafile(keyboard)
let fuzzy = s:ui.im =~ 'pinyin' ? ' ' : ""
let pattern = '^\V' . a:keyboard . fuzzy
let backend = s:backend[s:ui.root][s:ui.im]
let cursor = match(backend.lines, pattern)
if cursor < 0 | return [] | endif
let oneline = get(backend.lines, cursor)
let results = split(oneline)[1:]
if len(s:english.line) || len(results) > 10
return results
endif
if s:ui.im =~ 'pinyin'
let extras = s:vimim_more_pinyin_datafile(a:keyboard,0)
let results = s:vimim_make_pairs(oneline) + extras
else " http://code.google.com/p/vimim/issues/detail?id=121
let results = []
let s:show_extra_menu = 1
for i in range(10)
let cursor += i " get more if less
let oneline = get(backend.lines, cursor)
let results += s:vimim_make_pairs(oneline)
endfor
endif
return results
endfunction
function! s:vimim_make_pairs(oneline)
if empty(a:oneline) || match(a:oneline,' ') < 0
return []
endif
let oneline_list = split(a:oneline)
let menu = remove(oneline_list, 0)
let results = []
for chinese in oneline_list
call add(results, menu .' '. chinese)
endfor
return results
endfunction
function! s:vimim_set_backend_embedded()
for im in s:all_vimim_input_methods
let datafile = s:vimim_filereadable("vimim." . im . ".txt")
if empty(datafile)
let filename = "vimim." . im . "." . &encoding . ".txt"
let datafile = s:vimim_filereadable(filename)
endif
if !empty(datafile)
call s:vimim_set_datafile(im, datafile)
endif
endfor
endfunction
" ============================================= }}}
let s:VimIM += [" ==== /search ==== {{{"]
" =================================================
function! g:Vimim_search()
let results = []
let english = @/
if len(english) > 1 && len(english) < 20 && english !~ "[^0-9a-z']"
\&& v:errmsg =~# english && v:errmsg =~# '^E486: '
try
let results = s:vimim_search_chinese_by_english(english)
catch
sil!call s:vimim_debug('slash search /', v:exception)
endtry
endif
if !empty(results)
let results = split(substitute(join(results),'\w','','g'))
call sort(results, "s:vimim_sort_on_length")
let slash = join(results[0:9], '\|')
let @/ = empty(search(slash,'nw')) ? english : slash
endif
echon "/" . english
let v:errmsg = ""
endfunction
function! s:vimim_sort_on_length(i1, i2)
return len(a:i2) - len(a:i1)
endfunc
function! s:vimim_search_chinese_by_english(key)
let key = tolower(a:key)
let results = []
" search unicode or cjk /search unicode /u808f
let ddddd = s:vimim_get_unicode_ddddd(key)
if !empty(ddddd)
let results = [nr2char(ddddd)]
elseif s:vimim_cjk()
while len(key) > 1
let head = s:vimim_get_cjk_head(key)
if empty(head) " /muuqwxeyqpjeqqq
break " /m7712x3610j3111
else " /ma77xia36ji31
let matches = s:vimim_cjk_match(head)
if len(matches)
let chinese = join(matches[:9], '')
call add(results, "[" . chinese . "]")
endif
let key = strpart(key, len(head))
endif
endwhile
let results = len(results) > 1 ? [join(results,'')] : results
endif
if len(results) | return results | endif
" search datafile and english: /ma and /horse
let key = tolower(a:key)
let results = split(s:vimim_get_english(key))
if empty(results)
let results = s:vimim_embedded_backend_engine(key)
endif
return results
endfunction
" ============================================= }}}
let s:VimIM += [" ==== core workflow ==== {{{"]
" =================================================
function! s:vimim_start()
sil!call s:vimim_save_vimrc()
sil!call s:vimim_set_vimrc()
sil!call s:vimim_set_frontend()
sil!call s:vimim_set_keyboard_maps()
lnoremap <silent><buffer> <expr> <BS> g:Vimim_backspace()
lnoremap <silent><buffer> <expr> <Esc> g:Vimim_esc()
lnoremap <silent><buffer> <expr> <C-U> g:Vimim_one_key_correction()
if s:ui.im =~ 'array'
lnoremap <silent><buffer> <expr> <CR> g:Vimim_space()
lnoremap <silent><buffer> <expr> <Space> g:Vimim_pagedown()
else
lnoremap <silent><buffer> <expr> <CR> g:Vimim_enter()
lnoremap <silent><buffer> <expr> <Space> g:Vimim_space()
endif
let key = ''
if empty(s:ctrl6)
let s:ctrl6 = 32911
let key = nr2char(30)
endif
sil!exe 'sil!return "' . key . '"'
endfunction
function! s:vimim_stop()
if has("gui_running")
lmapclear
endif
let key = nr2char(30) " i_CTRL-^
let s:ui.frontends = copy(s:frontends)
sil!call s:vimim_restore_vimrc()
sil!call s:vimim_super_reset()
sil!exe 'sil!return "' . key . '"'
endfunction
function! s:vimim_save_vimrc()
let s:omnifunc = &omnifunc
let s:complete = &complete
let s:completeopt = &completeopt
let s:statusline = &statusline
let s:lazyredraw = &lazyredraw
endfunction
function! s:vimim_set_vimrc()
set title noshowmatch shellslash
set completeopt=menuone
set complete=.
set nolazyredraw
set omnifunc=VimIM
endfunction
function! s:vimim_restore_vimrc()
let &omnifunc = s:omnifunc
let &complete = s:complete
let &completeopt = s:completeopt
let &statusline = s:statusline
let &lazyredraw = s:lazyredraw
let &titlestring = s:titlestring
let &pumheight = s:pumheights.saved
endfunction
function! s:vimim_super_reset()
sil!call s:vimim_reset_before_anything()
sil!call s:vimim_reset_before_omni()
sil!call s:vimim_reset_after_insert()
endfunction
function! s:vimim_reset_before_anything()
let s:mode = s:windowless
let s:keyboard = ""
let s:omni = 0
let s:ctrl6 = 0
let s:switch = 0
let s:toggle_im = 0
let s:smart_enter = 0
let s:popup_list = []
endfunction
function! s:vimim_reset_before_omni()
let s:english.line = ""
let s:touch_me_not = 0
let s:show_extra_menu = 0
let s:cursor_at_windowless = 0
endfunction
function! s:vimim_reset_after_insert()
let s:match_list = []
let s:pageup_pagedown = 0
let s:pattern_not_found = 0
let s:hjkl = "" " reset for nothing
let s:hjkl__ = 0 " toggle simplified/traditional
let s:hjkl_h = 0 " toggle cjk property
let s:hjkl_l = 0 " toggle label length
let s:hjkl_m = 0 " toggle cjjp/c'j'j'p
endfunction
" ============================================= }}}
let s:VimIM += [" ==== core engine ==== {{{"]
" =================================================
function! VimIM(start, keyboard)
let valid_keyboard = s:valid_keyboard
if a:start
let cursor_positions = getpos(".")
let start_row = cursor_positions[1]
let start_column = cursor_positions[2]-1
let current_line = getline(start_row)
let before = current_line[start_column-1]
let seamless_column = s:vimim_get_seamless(cursor_positions)
if seamless_column < 0
let s:seamless_positions = []
let last_seen_bslash_column = copy(start_column)
let last_seen_nonsense_column = copy(start_column)
let all_digit = 1
while start_column
if before =~# valid_keyboard
let start_column -= 1
if before !~# "[0-9']" || s:ui.im =~ 'phonetic'
let last_seen_nonsense_column = start_column
let all_digit = all_digit ? 0 : all_digit
endif
elseif before == '\' " do nothing if leading bslash found
let s:pattern_not_found = 1
return last_seen_bslash_column
else
break
endif
let before = current_line[start_column-1]
endwhile
if all_digit < 1 && current_line[start_column] =~ '\d'
let start_column = last_seen_nonsense_column
endif
else
let start_column = seamless_column
endif
let len = cursor_positions[2]-1 - start_column
let keyboard = strpart(current_line, start_column, len)
if s:keyboard !~ '\S\s\S'
let s:keyboard = keyboard
endif
let s:starts.column = start_column
return start_column
else
if s:omni < 0 " one_key_correction
return [s:space]
endif
let results = s:vimim_cache()
if empty(results)
sil!call s:vimim_reset_before_omni()
else
return s:vimim_popupmenu_list(results)
endif
let keyboard = a:keyboard
if !empty(str2nr(keyboard)) " for digit input: 23554022100080204420
let keyboard = get(split(s:keyboard),0)
endif
if empty(keyboard) || keyboard !~ valid_keyboard
return []
else " [english] first check if it is english or not
let s:english.line = s:vimim_get_english(keyboard)
endif
if s:mode.windowless
let results = s:vimim_get_hjkl_game(keyboard)
if empty(results) && s:vimim_cjk()
let head = s:vimim_get_no_quote_head(keyboard)
let head = s:vimim_get_cjk_head(head)
let results = !empty(head) ? s:vimim_cjk_match(head) : []
endif
if len(results)
return s:vimim_popupmenu_list(results)
elseif len(s:hjkl) && s:keyboard !~ "'"
let keyboard = get(split(keyboard,'\d'),0) " mali74
endif
endif
if empty(results)
let results = s:vimim_embedded_backend_engine(keyboard)
endif
if len(s:english.line)
let s:keyboard = s:keyboard !~ "'" ? keyboard : s:keyboard
let results = s:vimim_make_pairs(s:english.line) + results
endif
if empty(results) " [the_last_resort] force shoupin
if s:mode.windowless
if len(keyboard) > 1
let shoupin = s:vimim_get_no_quote_head(keyboard."'''")
let results = s:vimim_cjk_match(shoupin)
else
let results = [keyboard == 'i' ? "我" : s:space]
endif
endif
endif
return s:vimim_popupmenu_list(results)
endif
endfunction
function! s:vimim_popupmenu_list(lines)
let s:match_list = a:lines
let keyboards = split(s:keyboard) " mmmm => ['m',"m'm'm"]
let keyboard = join(keyboards,"")
let tail = len(keyboards) < 2 ? "" : get(keyboards,1)
if empty(a:lines) || type(a:lines) != type([])
return []
elseif s:vimim_cjk() && len(s:hjkl)
let results = [] " use 1234567890 as filter for windowless
for chinese in a:lines
if s:vimim_cjk_in_4corner(chinese,0)
call add(results, chinese)
endif
endfor
if empty(results)
let s:hjkl = "" " make digits recyclable
else " gi ma space 7777777777
let s:match_list = results
endif
endif
let label = 1
let one_list = []
let s:popup_list = []
for chinese in s:match_list
let complete_items = {}
if s:vimim_cjk() && s:hjkl__ && s:hjkl__%2
let simplified_traditional = ""
for char in split(chinese, '\zs')
let simplified_traditional .= s:vimim_1to1(char)
endfor
let chinese = simplified_traditional
endif
let titleline = s:vimim_get_label(label)
if empty(s:touch_me_not)
let menu = ""
let pairs = split(chinese)
let pair_left = get(pairs,0)
if len(pairs) > 1 && pair_left !~ '[^\x00-\xff]'
let chinese = get(pairs,1)
let menu = s:show_extra_menu ? pair_left : menu
endif
if s:hjkl_h && s:hjkl_h % 2
let char = get(split(chinese,'\zs'),0)
let menu = s:vimim_cjk_property(char)
endif
let label2 = s:english.line =~ chinese ? '*' : ' '
let titleline = printf('%3s ', label2 . titleline)
let chinese .= empty(tail) || tail == "'" ? '' : tail
let complete_items["abbr"] = titleline . chinese
let complete_items["menu"] = menu
endif
if s:mode.windowless
if s:vimim_cjk() " display sexy english and dynamic 4corner
let star = substitute(titleline,'[0-9a-z_ ]','','g')
let digit = s:vimim_cjk_in_4corner(chinese,1) " ma7 712
let titleline = star . digit[len(s:hjkl) : 3]
elseif label < 11 " 234567890 for windowless selection
let titleline = label == 10 ? "0" : label
endif
call add(one_list, titleline . chinese)
endif
let label += 1
let complete_items["dup"] = 1
let complete_items["word"] = empty(chinese) ? s:space : chinese
call add(s:popup_list, complete_items)
endfor
if s:mode.windowless
let s:windowless_title = 'VimIM ' . keyboard .' '. join(one_list)
call s:vimim_windowless_titlestring(1)
endif
call s:vimim_set_pumheight()
" Debug s:match_list[:1]
return s:popup_list
endfunction
function! s:vimim_embedded_backend_engine(keyboard)
let keyboard = a:keyboard
if empty(s:ui.im) || empty(s:ui.root)
return []
endif
let head = 0
let results = []
let backend = s:backend[s:ui.root][s:ui.im]
if backend.name =~ "quote" && keyboard !~ "[']" " has apostrophe
let keyboard = s:vimim_quanpin_transform(keyboard)
endif
if s:ui.root =~# "datafile"
if empty(backend.lines)
let backend.lines = s:vimim_read_txt(backend.name)
endif
let head = s:vimim_sentence_datafile(keyboard)
let results = s:vimim_get_from_datafile(head)
endif
if s:keyboard !~ '\S\s\S'
if empty(head)
let s:keyboard = keyboard
elseif len(head) < len(keyboard)
let tail = strpart(keyboard,len(head))
let s:keyboard = head . " " . tail
endif
endif
return results
endfunction
function! g:Vimim()
let s:omni = s:omni < 0 ? -1 : 0 " one_key_correction
let s:keyboard = empty(s:pageup_pagedown) ? "" : s:keyboard
let key = s:vimim_left() ? '\<C-X>\<C-O>\<C-R>=g:Omni()\<CR>' : ""
sil!exe 'sil!return "' . key . '"'
endfunction
function! g:Omni()
let s:omni = s:omni < 0 ? 0 : 1 " as if omni completion pattern found
let key = pumvisible() ? '\<C-P>\<Down>' : ""
sil!exe 'sil!return "' . key . '"'
endfunction
" ============================================= }}}
let s:VimIM += [" ==== core driver ==== {{{"]
" =================================================
function! s:vimim_plug_and_play()
inoremap <silent> <C-^> <C-R>=g:Vimim_tab()<CR>
xnoremap <silent> <C-^> y:call g:Vimim_visual()<CR>
" nnoremap <silent> n :call g:Vimim_search()<CR>n
com! -range=% ViMiM <line1>,<line2>call s:vimim_chinese_rotation()
com! -range=% VimIM <line1>,<line2>call s:vimim_chinese_transfer()
endfunction
sil!call s:vimim_initialize_global()
sil!call s:vimim_initialize_backdoor()
sil!call s:vimim_dictionary_statusline()
sil!call s:vimim_dictionary_punctuations()
sil!call s:vimim_dictionary_numbers()
sil!call s:vimim_dictionary_keycodes()
sil!call s:vimim_super_reset()
sil!call s:vimim_set_backend_embedded()
sil!call s:vimim_set_im_toggle_list()
sil!call s:vimim_plug_and_play()
let g:Vimim_profile = reltime(g:Vimim_profile)
sil!call s:vimim_debug(s:vimim_egg_vimim())
" ============================================= }}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment