Vim一键修改光标所在单词为相反或关联的词

写代码或文字时,经常会需要修改当前词(或选中区域)为相反相关的词,比如

A B
up down
left right
show hide
from to
encode decode
get set
yes no
on off
down up
left right
top bottom
this base
read write
row column
rows columns
RowHeight ColumnWidth
focus blur
var const
lower upper
odd even
before after
max min
prev next
true false
enable disable
enabled disabled
permit deny
smtp imap
width height
horizontal vertical
user pwd
username password
SendMessage PostMessage
水平 垂直
成功 失败
显示 隐藏
github.com github.com.cnpmjs.org

于是就有了以下 map 和相关函数
切换后仍会保留原大小写格式
核心见hy_string#modify#toggleWord函数

NOTE:比如设置了getset的转化后,那么以下情况也会自动有效

getValue setValue
get_value set_value

原理getValue如果未匹配,则会分别判断getValue是否被定义

补充:在函数一开始还额外定义了.prop["prop"] 的转化(不需要删除即可)

nnoremap <silent> <M-t> ciw<C-r>=hy_string#modify#toggleWord(@")<cr><esc>
xnoremap <silent> <M-t> s<C-r>=hy_string#modify#toggleWord(@")<cr><esc>

"true/false, up/down切换
"NOTE lis大小写或首字母大写,全用小写,其他情况保留原大小写
function! hy_string#modify#toggleWord(word)
    " .prop ⇄ ["prop"]
    if (a:word =~ '^\v\.\w+$') | return '["' .strpart(a:word,1). '"]' | endif
    if (a:word =~ '^\v\["\w+"\]$') | return '.' .strpart(a:word,2,len(a:word)-4) | endif
    let lis = [
                \ ['!', '!'],
                \ [',', ','],
                \ ['.', '。'],
                \ ['<^', 'LCtrl & '],
                \ ['>^', 'RCtrl & '],
                \ ['<+', 'LShift & '],
                \ ['>+', 'RShift & '],
                \ ['<!', 'LAlt & '],
                \ ['>!', 'RAlt & '],
                \ ['FireShot', 'mcbpblocgmgfnpjjppndjkmgjaogfceg'],
                \ ['Surfingkeys', 'gfbliohnnapiefjpjlpjnehglfpaknnc'],
                \ ['SwitchyOmega', 'padekgcemlokbadohgkifijomclgjgif'],
                \ ['Tampermonkey', 'dhdgffkkebhmkfjojejmpbldmpobfkfo'],
                \ ['show', 'hide'],
                \ ['from', 'to'],
                \ ['encode', 'decode'],
                \ ['get', 'set'],
                \ ['yes', 'no'],
                \ ['on', 'off'],
                \ ['down', 'up'],
                \ ['left', 'right'],
                \ ['top', 'bottom'],
                \ ['this', 'base'],
                \ ['read', 'write'],
                \ ['row', 'column'],
                \ ['rows', 'columns'],
                \ ['RowHeight', "ColumnWidth"],
                \ ['focus', 'blur'],
                \ ['lower', 'upper'],
                \ ['odd', 'even'],
                \ ['before', 'after'],
                \ ['max', 'min'],
                \ ['prev', 'next'],
                \ ['true', 'false'],
                \ ['enable', 'disable'],
                \ ['enabled', 'disabled'],
                \ ['permit', 'deny'],
                \ ['user', 'pwd'],
                \ ['username', 'password'],
                \ ['smtp', 'imap'],
                \ ['width', 'height'],
                \ ['horizontal', 'vertical'],
                \ ['var', 'const'],
                \ ['absolute', 'relative'],
                \ ['hkcr', 'HKEY_CLASSES_ROOT'],
                \ ['hkcu', 'HKEY_CURRENT_USER'],
                \ ['hklm', 'HKEY_LOCAL_MACHINE'],
                \ ['hku', 'HKEY_USERS'],
                \ ['hkcc', 'HKEY_CURRENT_CONFIG'],
                \ ['ActiveCell', 'selection'],
                \ ['WinActive', 'WinActivate'],
                \ ['SendMessage', 'PostMessage'],
                \ ['setTimeout', 'setInterval'],
                \ ['screen', 'window'],
                \ ['左', '右'],
                \ ['上', '下'],
                \ ['水平', '垂直'],
                \ ['成功', '失败'],
                \ ['显示', '隐藏'],
                \ ['jshint', 'eslint'],
                \ ['scanf', 'printf'],
                \ ['WinGetClientPos', 'WinGetPos'],
                \ ['cells', 'range'],
                \ ['MergeArea', 'MergeCells'],
                \ ['ComObjActive', 'ComObject'],
                \ ['chr', 'ord'],
                \ ['FindFirst', 'FindAll'],
                \ ['FileMove', 'FileCopy'],
                \ ['FileDelete', 'FileRecycle'],
                \ ['font', 'interior'],
                \ ['querySelector', 'querySelectorAll'],
                \ ['innerHTML', 'innerText'],
                \ ['LCtrl', 'RCtrl'],
                \ ['LShift', 'RShift'],
                \ ['LAlt', 'RAlt'],
                \ ['run', 'RunWait'],
                \ ['msgbox', 'tooltip'],
                \ ['PgDn', 'PgUp'],
                \ ['RegExReplace', 'RegExMatch'],
                \ ['access', 'trunk'],
                \ ['waitForPackage', 'waitForActivity'],
                \ ['textStartsWith', 'textMatches'],
                \ ['clickByWindow', 'clickStayByWindow'],
                \ ['toastLog', 'toastInfo'],
                \ ['0x111', 'WM_COMMAND:=0x111'],
                \ ['WM_COMMAND', 'WM_COMMAND:=0x111'],
                \ ['0x112', 'WM_SYSCOMMAND:=0x112'],
                \ ['WM_SYSCOMMAND', 'WM_SYSCOMMAND:=0x112'],
                \ ['currentPackage', 'currentActivity'],
                \ ['github.com', 'github.com.cnpmjs.org'],
                \ ]
    let word = a:word
    "获取 word 前后内容(用来 setline)
    let sLine = getline('.')
    let idx0 = stridx(sLine, word, col('.')-strlen(word))
    let strBefore = strpart(sLine, 0, idx0)
    let strAfter = strpart(sLine, idx0+strlen(word))
    "echom strBefore .'--'. strAfter .'--'. word
    "lPair 转成 dic(相互为key,方便判断)
    let dic = {}
    for lPair in lis
        let dic[lPair[0]] = lPair[1]
        let dic[lPair[1]] = lPair[0]
    endfor
    "NOTE dic 额外增加单向的内容
    let dic['int'] = 'integer'
    let dic['integer'] = '^\d+$'
    "处理单词大小写
    let upCase = hy_string#get#upperCase(word)
    let wordFixed = upCase > 0 ? tolower(word) : word "wordFixed 用来调整大小写
    "echom word .' '. wordFixed
    if !has_key(dic,wordFixed) "不在定义列表内
        "echom 'not in dic'
        "aUp → aDown
        if word =~# '[A-Z]'
            let char = ''
            let l = hy_string#split#byUpper(word)
        else
            let char = matchstr(word, '\c[^a-z]')
            let l = split(word, '\c[^a-z]')
        endif
        for i in range(len(l))
            let upCase = hy_string#get#upperCase(l[i])
            let wordFixed = upCase > 0 ? tolower(l[i]) : word "wordFixed 用来调整大小写
            if has_key(dic, wordFixed) "找到匹配
                let res = dic[wordFixed]
                "恢复大小写
                if upCase == 1
                    let res = tolower(res)
                elseif upCase == 2
                    let res = toupper(res)
                elseif upCase == 3
                    let res = substitute(res, '.*', '\L\u&', '')
                endif
                "修改 l
                let l[i] = res
                return join(l, char)
            endif
        endfor
        return word
    else
        let res = dic[wordFixed]
        if upCase == 1
            let res = tolower(res)
        elseif upCase == 2
            let res = toupper(res)
        elseif upCase == 3
            let res = substitute(res, '.*', '\L\u&', '')
        endif
    endif
    return res
    "    execute "normal! ciw" . res
    "call setline(line('.'), strBefore . res . strAfter)
endfunction

"获取字符串的大小写情况
"1为小写
"2为大写
"3为首字母大写
"0为其他情况(strUpper)
function! hy_string#get#upperCase(str) abort
    if a:str !~ '\a' "没字母
        return 0
    elseif a:str ==# tolower(a:str)
        return 1
    elseif a:str ==# toupper(a:str)
        return 2
    elseif a:str =~# '\v^\u\l*$'
        return 3
    else
        return 0
    endif
endfunction

"abcUp转成 ['abc', 'Up']
function! hy_string#split#byUpper(str) abort
    let char = '!'
    let s = substitute(a:str, '\A', char.'&', 'g') "转换非字母
    let s = substitute(s, '\v\C[A-Z\W]', char.'&', 'g') "大写字母前增加符号用来 split
    if strcharpart(s, 0, 1) == char | let s = strcharpart(s, 1) | endif
    return split(s, char)
endfunction
posted @ 2021-08-28 15:10  火冷  阅读(139)  评论(0编辑  收藏  举报