Vim中跟Emacs中ALt-T(M-t)一样交换单词

Vim、Emacs配置和使用
回复
头像
Fermat618
帖子: 728
注册时间: 2008-12-28 16:01

Vim中跟Emacs中ALt-T(M-t)一样交换单词

#1

帖子 Fermat618 » 2011-07-06 21:25

这里再发一遍吧

Vim 中像在 Emacs 中 Alt-t (M-t)那样交换单词。

网上找过一些办法,基本一点的就是通过一系列 normal 命令来做,如 dawbhP, 这样的
坏处是一件工作分成了多步,撤消不便,并且按键多,完成后光标位置也移动了。对于
a = b 这种情况,也不能方便地交换 a 和 b

另一种是映射到一行正则表达式来匹配替换,也有如下不满意的地方:

1. 在执行命令前光标位置限制太严,如一行中打完了 foo bar |, 光标在最末尾的地
方,如|所示处,按 Alt-t 应该能交换前面两个词,而不用移动到前面的那个词去。
2. 执行完命令后光标位置不理想,Bash 或是 Emacs 中是位于后面那个单词尾部之后,
这样连续按 Alt-t 就能不断地把一个单词往后面推。
3. 撤消后光标不能回位,这是 :s 命令的副作用。
4. 命令行 (Ex 模式或是按/后) 下不能使用。
5. 破坏了搜索历史。在对搜索模式高亮的表况下可能搞得屏幕花花绿绿。

这个插件模拟 Bash 下 Alt-t 的作用,并能避免以上问题。Emacs 下 M-t 跟 Bash 下
略有些不同,个人喜欢 Bash M-t.

使用:
在 insert, normal, 和 cmd-line 下都可以按 <ALt-t> 来使用,/或者?开启的搜索行也可以使用。前面还可以加数字参数。如 8<M-t>.
在有 repeat.vim (vimscript #2136)存在的情况下,还可以重复。

#关于键映射
在 gvim 中,如果 <Alt-t> 打开了菜单,可以用

代码: 全选

 :set winaltkeys=no
来禁用,
在终端下,如果<Alt-t>不起作用,可以

代码: 全选

:exec "set <M-t>=\<Esc>t"
如果终端下<Alt-t>打开了终端菜单,这可以在终端的配置里面禁用,模拟终端一般都会给这个选项的。

或者把这个功能定义到其它键

代码: 全选

:nmap <Leader>t <Plug>Transposewords
:imap <Leader>t <Plug>Transposewords
:cmap <Leader>t <Plug>Transposewords 
<Leader>一般是反斜杠 \ , 按 \t 来代替 <Alt-t>
vim.org 上的链接 http://www.vim.org/scripts/script.php?script_id=3656
--
上次由 Fermat618 在 2012-04-05 21:12,总共编辑 4 次。
爱因斯坦会弹钢琴
爱因斯坦会拉小提琴
爱因斯坦会骑自行车
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#2

帖子 lilydjwg » 2011-07-06 21:38

Fermat618 写了:个人喜欢 Bash M-t.
个人喜欢 Python 版的 :em02
头像
Fermat618
帖子: 728
注册时间: 2008-12-28 16:01

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#3

帖子 Fermat618 » 2011-07-06 21:50

纯vimscript的话会可以给更多人用。

python刚开始实现的那个,1Mbyte长的行,光标在行尾,从开头用正一直匹配下去,都可以在我可以接受的时间内完成两个词的交换!
vimscript实现的时候,同样的方法,同样的情况,好多分钟都不反应。于是才想到最多从前面列前面某一位置开始搜索,这样在长行时不至于死掉。python的re效率还是很高啊。
爱因斯坦会弹钢琴
爱因斯坦会拉小提琴
爱因斯坦会骑自行车
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#4

帖子 lilydjwg » 2011-07-06 22:25

Fermat618 写了:纯vimscript的话会可以给更多人用。

python刚开始实现的那个,1Mbyte长的行,光标在行尾,从开头用正一直匹配下去,都可以在我可以接受的时间内完成两个词的交换!
vimscript实现的时候,同样的方法,同样的情况,好多分钟都不反应。于是才想到最多从前面列前面某一位置开始搜索,这样在长行时不至于死掉。python的re效率还是很高啊。
你可以上传两个版本的啊,然后注明下区别。

python 向来注重效率,不像 vim,慢死。

PS: 我想到这样个办法:把当前行的字符串从当前词开始到开头做个反转,然后再寻找。或者,用 Vim 的正则来限定匹配中包含光标的位置试试。
头像
acer4740
帖子: 1405
注册时间: 2010-09-13 19:04
来自: 0xFF00EE

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#5

帖子 acer4740 » 2011-07-06 22:53

gvim下alt + t会打开菜单
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#6

帖子 lilydjwg » 2011-07-06 23:34

acer4740 写了:gvim下alt + t会打开菜单

代码: 全选

set go-=m
" or
set winaltkeys=no
头像
fanhe
帖子: 2357
注册时间: 2007-03-24 23:45

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#7

帖子 fanhe » 2011-07-06 23:37

能用 vim script 搞定就别用其他了, 除非用其他的能带来明显的效率上升, 而你又在意这个效率
要知道在windows下装个python运行时是多么奢侈的事
另外关于python
Python开发人员尽量避开不成熟或者不重要的优化。一些针对非重要部位的加快运行速度的补丁通常不会被合并到Python内。所以很多认为Python很慢。不过,根据二八定律,大多数程序对速度要求不高。在某些对运行速度要求很高的情况,Python程序员倾向于使用JIT技术,或者用使用C/C++语言改写这部分程序。目前可用的JIT技术是Pysco。
我现在都有把我项目某部分用c/c++重写的冲动
头像
Fermat618
帖子: 728
注册时间: 2008-12-28 16:01

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#8

帖子 Fermat618 » 2011-07-07 16:53

lilydjwg 写了:
Fermat618 写了:纯vimscript的话会可以给更多人用。

python刚开始实现的那个,1Mbyte长的行,光标在行尾,从开头用正一直匹配下去,都可以在我可以接受的时间内完成两个词的交换!
vimscript实现的时候,同样的方法,同样的情况,好多分钟都不反应。于是才想到最多从前面列前面某一位置开始搜索,这样在长行时不至于死掉。python的re效率还是很高啊。
你可以上传两个版本的啊,然后注明下区别。

python 向来注重效率,不像 vim,慢死。

PS: 我想到这样个办法:把当前行的字符串从当前词开始到开头做个反转,然后再寻找。或者,用 Vim 的正则来限定匹配中包含光标的位置试试。
匹配光标位置只对当前buffer有效,但我已经getline把那一行拿出来了。
爱因斯坦会弹钢琴
爱因斯坦会拉小提琴
爱因斯坦会骑自行车
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#9

帖子 eexpress » 2011-07-07 21:18

啥情况下,有交换的需要。
似乎没印象。
● 鸣学
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#10

帖子 lilydjwg » 2011-07-07 21:42

eexpress 写了:啥情况下,有交换的需要。
似乎没印象。

代码: 全选

thelist = [xxx, yyy, zzz, ...]
# Oops, zzz should come before xxx
头像
fanhe
帖子: 2357
注册时间: 2007-03-24 23:45

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#11

帖子 fanhe » 2011-07-07 22:09

eexpress 写了:啥情况下,有交换的需要。
似乎没印象。
同无必要
一般就删了再粘贴
头像
Fermat618
帖子: 728
注册时间: 2008-12-28 16:01

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#12

帖子 Fermat618 » 2011-07-08 15:14

fanhe 写了:
eexpress 写了:啥情况下,有交换的需要。
似乎没印象。
同无必要
一般就删了再粘贴
主要是处理 list, 还有编辑命令行时。

复制粘贴得把一个目标很明确的操作分成好多步来完成,很不直观。当然,如果用得少,复制粘贴也是可以的。
爱因斯坦会弹钢琴
爱因斯坦会拉小提琴
爱因斯坦会骑自行车
yangxinxiu
帖子: 29
注册时间: 2010-01-01 14:11

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#13

帖子 yangxinxiu » 2012-02-25 8:09

谢谢楼主。
为什么我的在交换的时候光标会后退一个位置呢?就像

代码: 全选

abc def|   我M-t 123 M-t 456以后就是ab123c de456f 
但是如果我在def 的后面加一个空格再M-t 的话才能回到正常的位置,谢谢楼主。
头像
Fermat618
帖子: 728
注册时间: 2008-12-28 16:01

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#14

帖子 Fermat618 » 2012-02-25 22:35

yangxinxiu 写了:谢谢楼主。
为什么我的在交换的时候光标会后退一个位置呢?就像

代码: 全选

abc def|   我M-t 123 M-t 456以后就是ab123c de456f 
但是如果我在def 的后面加一个空格再M-t 的话才能回到正常的位置,谢谢楼主。
嗯,是有这个问题。刚刚查出来是因为我想加入对repeat插件的支持,结果那个造成的问题。忘了vim.org上的密码,现在上传不了,你先用这个吧。
[vim]
" transwrd.vim: Swap two words as M-t (transpose-words) function in Emacs (Bash)
" This version of the script act more likely to M-t in Bash
" rather than in emacs.
" Last Change: 2012-02-25
" Maintainer: Fermat <[email protected]>
" Licence: This script is released under the Vim License.
" Install:
" Put this file in ~/.vim/plugin
" Mappings:
" <Alt-t> (<Meta-t>) in any mode except command-line with '=' prompt.
" transpose words. Same as press <Alt-t> (<Meta-t>) in Emacs or
" Bash(default mode)
" count can also be used, e.g. 8<Alt-t>
" repeat.vim (vimscript#2136) is supported. When repeat.vim present,
" you can use dot (.) to repeat.
" Variable:
" g:transwrd_wordpattern
" b:transwrd_wordpattern
" When b:transwrd_wordpattern is set, wordpattern is set to it, otherwise,
" g:transwrd_wordpattern, otherwise, '\k\+'

if exists("g:loaded_transwrd")
finish
endif
let g:loaded_transwrd = 1
let s:save_cpo = &cpo
set cpo&vim

let s:wordpattern = '\k\+'

" Functions
let s:largest_offset = 1024 - 1
function s:transpose_word_inline(cline, col)
if exists("b:transwrd_wordpattern")
let wordpattern = b:transwrd_wordpattern
elseif exists("g:transwrd_wordpattern")
let wordpattern = g:transwrd_wordpattern
else
let wordpattern = s:wordpattern
endif

if a:col > s:largest_offset
let m_start0 = a:col - s:largest_offset
else
let m_start0 = 0
endif
let m_start = m_start0
let prev = {}
let this = {}
let m_start_new = match(a:cline, wordpattern, m_start)
if m_start_new == -1
return [a:cline, a:col]
else
let prev.start = m_start_new
let prev.end = matchend(a:cline, wordpattern, m_start)
if prev.end - prev.start == 0
return [a:cline, a:col]
endif
let prev.str = matchstr(a:cline, wordpattern, m_start)
let m_start = prev.end
endif
let m_start_new = match(a:cline, wordpattern, m_start)
if m_start_new == -1
return [a:cline, a:col]
else
let this.start = m_start_new
let this.end = matchend(a:cline, wordpattern, m_start)
if this.end - this.start == 0
return [a:cline, a:col]
endif
let this.str = matchstr(a:cline, wordpattern, m_start)
let m_start = this.end
endif

if prev.end > a:col - 1
return [a:cline, a:col]
elseif this.end > a:col - 1
else
let m_start_new = match(a:cline, wordpattern, m_start)
while m_start_new != -1
let m_end = matchend(a:cline, wordpattern, m_start)
if m_end - m_start_new == 0
return [a:cline, a:col]
endif
let prev = deepcopy(this)
let this.start = m_start_new
let this.end = m_end
let this.str = matchstr(a:cline, wordpattern, m_start)
let m_start = this.end
let m_start_new = match(a:cline, wordpattern, m_start)
if this.end > a:col - 1
break
endif
endwhile
endif
if m_start0 != 0 && prev.start == m_start0
echohl WarningMsg
echomsg "transwrd.vim: Too long word"
\ "or too many non-word charactors before cursor!"
echohl None
return [a:cline, a:col]
endif
let cline = strpart(a:cline, 0, prev.start) . this.str .
\ strpart(a:cline, prev.end, this.start - prev.end) .
\ prev.str . strpart(a:cline, this.end)
return [cline, this.end + 1]
endfunction

function s:transpose_word()
if mode() == 'i'
let counts = 1
elseif exists("s:last_mode_is_insert")
let counts = 1
elseif v:count < 1
let counts = 1
else
let counts = v:count
endif
if mode() == 'i'
let s:last_mode_is_insert = 1
else
unlet! s:last_mode_is_insert
endif

let cline = getline(".")
let col = col(".")
let i = 1
let [cline_out, col_out] = s:transpose_word_inline(cline, col)
while i < counts
let i += 1
let [cline_out, col_out] = s:transpose_word_inline(cline_out, col_out)
endwhile
if [cline_out, col_out] ==# [cline, col]
return ''
else
let lnum = line(".")
call setline(lnum, cline_out)
if col_out != col
call setpos(".", [0, lnum, col_out, 0])
endif
endif
if mode() == 'n'
silent! call repeat#set("\<Plug>Transposewords", v:count)
" In insert mode this cause problem when the cursor in in the end of a
" line.
endif
return ''
endfunction

function s:transpose_word_cmdline()
let cline = getcmdline()
let col = getcmdpos()
let [cline_out, col_out] = s:transpose_word_inline(cline, col)
if [cline_out, col_out] !=# [cline, col]
call setcmdpos(col_out)
endif
return cline_out
endfunction

" Mappings
nnoremap <unique> <silent> <Plug>Transposewords
\ :<C-u>call <SID>transpose_word()<CR>
inoremap <unique> <silent> <Plug>Transposewords <C-g>u<C-R>=<SID>transpose_word()<CR>
cnoremap <unique> <Plug>Transposewords <C-\>e<SID>transpose_word_cmdline()<CR>

if !hasmapto('<Plug>Transposewords')
nmap <unique> <M-t> <Plug>Transposewords
imap <unique> <M-t> <Plug>Transposewords
cmap <unique> <M-t> <Plug>Transposewords
endif

let &cpo = s:save_cpo

" vim:set ft=vim expandtab sw=4 tw=79:
[/vim]
爱因斯坦会弹钢琴
爱因斯坦会拉小提琴
爱因斯坦会骑自行车
yangxinxiu
帖子: 29
注册时间: 2010-01-01 14:11

Re: Vim中跟Emacs中ALt-T(M-t)一样交换单词

#15

帖子 yangxinxiu » 2012-02-26 8:57

哦 好的,谢谢楼主,期待新版本 以及对repeat的支持,那这个插件就成了我的必备了 ,经常想修改前一个单词不好使,恩 谢谢楼主了。
回复