2012-08-11 117 views
2

我有一个MoveToFile将所选文本追加到文件然后删除它的功能。Vim E139:解决方法

command! -nargs=* -complete=file -range=% -bang -bar MoveToFile 
\ :<line1>,<line2>call MoveToFile(<q-args>, <bang>0) 
function! MoveToFile(fname, overwrite) range 
    let r = a:firstline . ',' . a:lastline 
    exe r 'w>>' . ' !'[a:overwrite] . fnameescape(a:fname) 
    exe r 'd' 
endfunction 

当我试图追加到的文件已经在Vim中打开时出现问题。我怎样才能解决这个问题?

+0

又见【答案】(http://stackoverflow.com/a/7723380/254635)(问题“[删除并重定向Vim中的行到另一个文件](http://stackoverflow.com/q/7720520/254635)”)该功能已被复制。 – 2012-08-12 02:08:35

+0

修改了'MoveToFile()'后,您引入了一个错误以附加到文件而不是覆盖它。函数的第二行应该是'exe r'w'。 '!'[a:覆盖]。 '>>'。 fnameescape(一个:FNAME)'。 – 2012-08-12 03:25:36

回答

2

你可以赶上E139: File is loaded in another buffer。如果你真的需要 来处理这个角落的情况下,抽出的内容,通过:buffer {fname}打开现有的缓冲区,并将其粘贴:

try 
    exe r 'w>>' . ' !'[a:overwrite] . fnameescape(a:fname) 
catch /^Vim\%((\a\+)\)\=:E139/ 
    exe r 'yank' 
    exe 'sbuffer' fnameescape(a:fname) 
    $put 
    hide 
endtry 
0

您可以使用writefile()(注意,这将覆盖文件,因此必须首先获取当前内容,因此无法用于路数):

function MoveToFile(fname, _) range abort 
    let lines=readfile(a:fname, 'b') 
    if !empty(lines) && empty(lines[-1]) 
     call remove(lines, -1) 
    endif 
    let [first, last]=((a:firstline>a:lastline)?([a:lastline, a:firstline]):([a:firstline, a:lastline])) 
    let lines+=getline(first, last)+[''] 
    call writefile(lines, a:fname, 'b') 
    execute first.','.last.'delete _' 
endfunction 

注:获得相同的编码与:w>>需要更换线

let lines+=getline(first, last)+[''] 

let lines+=map(getline(first, last), 'iconv(v:val, &enc, &fenc)')+[''] 

。为了也尊重'dos'文件格式:

let lines+=map(getline(first, last), 'iconv(v:val, &enc, &fenc)'.((&ff is# 'dos')?('."\r"'):('')))+[(&ff is# 'dos')?("\r"):('')] 

(尊重'mac'文件格式是麻烦)。

+2

当您处理多种编码时,您还必须处理必要的转换; 'writefile()'不适合你; ':w'确实。 – 2012-08-11 18:17:47

+0

@IngoKarkat False。追加写入时不关心目标文件编码,而是关心'&fenc'。因此,当使用原始解决方案并从具有多种编码的文件追加时,您将获得具有混合编码的文件。在使用我的解决方案时,您将使用'&enc'编码文件。 getline()会输出已经重新编码的行,因此不需要关心源文件的编码。当然,如果你需要'&enc'之外的东西,你需要运行'iconv()'。 – ZyX 2012-08-11 18:37:52

+1

我假设追加只是一个特殊情况,当从同一个缓冲区多次调用该命令时的便利。否则,可能会混合使用编码,正如您已经指出的那样。尽管如此,我认为拿起'&fenc'更符合默认行为,而不是使用'&enc',但没有明确的对与错。 – 2012-08-11 18:47:17