2012-01-24 28 views
21

Tôi đã tìm cách lập bản đồ toán tử mới trong Vim lấy tham số bổ sung.Xác định toán tử Vim mới với tham số

Ví dụ, chúng ta biết rằng ciw sẽ "cắt từ bên trong" và sẽ đưa bạn vào chế độ chèn, những gì tôi đang tìm kiếm là có một hành động tùy chỉnh để thay thế c (ví dụ s) mà sẽ đưa các phong trào như iw nhưng đòi hỏi một tham số bổ sung.

Một ví dụ nhỏ sẽ là:

Given a line in a text file 

Và thực hiện trong chế độ bình thường (cho con trỏ trên cột đầu tiên) siw* đó sẽ bao quanh từ đầu tiên với * như vậy:

*Given* a line in a text file 

Tôi biết, đây là những gì các plugin surround.vim tuyệt vời nhất hiện. Nhưng tôi chỉ đưa ra một ví dụ ở đây, và tìm kiếm một câu trả lời như thế nào để có được ánh xạ để công việc trên.

Tôi đã thử chơi với onoremapopfunc nhưng dường như không thể khiến chúng phát theo cách tôi muốn.

Vì vậy, đây là kết hợp các chuyển động cộng với ánh xạ đang chờ của nhà điều hành.

+1

Câu hỏi thú vị :) – Rook

+1

Vì đó là những gì mà Surround làm, bạn có nhìn vào mã của Surround không? – romainl

+0

Đó là loại Surround làm, ngoại trừ nó thêm (các) chuyển động sau hành động Vim như 'y',' d' và 'c'.Một lần nữa, lưu ý rằng tôi đưa ra một ví dụ, không nói rằng tôi muốn viết lại Surround. Và vâng, tôi đã thấy nguồn cho Surround. – alfredodeza

Trả lời

12

Dưới đây là ví dụ về việc thực hiện lệnh được mô tả trong câu hỏi, cho mục đích minh họa.

nnoremap <silent> s :set opfunc=Surround<cr>[email protected] 
vnoremap <silent> s :<c-u>call Surround(visualmode(), 1)<cr> 
function! Surround(vt, ...) 
    let s = InputChar() 
    if s =~ "\<esc>" || s =~ "\<c-c>" 
     return 
    endif 
    let [sl, sc] = getpos(a:0 ? "'<" : "'[")[1:2] 
    let [el, ec] = getpos(a:0 ? "'>" : "']")[1:2] 
    if a:vt == 'line' || a:vt == 'V' 
     call append(el, s) 
     call append(sl-1, s) 
    elseif a:vt == 'block' || a:vt == "\<c-v>" 
     exe sl.','.el 's/\%'.sc.'c\|\%'.ec.'c.\zs/\=s/g|norm!``' 
    else 
     exe el 's/\%'.ec.'c.\zs/\=s/|norm!``' 
     exe sl 's/\%'.sc.'c/\=s/|norm!``' 
    endif 
endfunction 

Để có được đầu vào người sử dụng, chức năng InputChar() được sử dụng, giả định rằng đối số bắt buộc là một nhân vật duy nhất.

function! InputChar() 
    let c = getchar() 
    return type(c) == type(0) ? nr2char(c) : c 
endfunction 

Nếu nó là cần thiết để chấp nhận một đối số chuỗi, gọi input() thay vì InputChar().

7

Tiêu đề của câu hỏi có thể gây hiểu lầm. Những gì bạn muốn làm là xác định toán tử mới như y, dc, không phải chuyển động hay đối tượng văn bản, phải không? :help :map-operator mô tả cách xác định toán tử mới. Để lấy tham số như plugin surround, hãy sử dụng getchar() trong 'operatorfunc' của bạn.

Mặc dù :help :map-operator mô tả các khái niệm cơ bản, hơi rắc rối khi xử lý các đối số được chuyển đến 'operatorfunc'. Bạn có thể sử dụng vim-operator-user để đơn giản hóa việc xử lý đối số. Với plugin này, nhà điều hành vòm giống như có thể được viết như sau:

function! OperatorSurround(motion_wise) 
    let _c = getchar() 
    let c = type(_c) == type(0) ? nr2char(_c) : _c 
    if c ==# "\<Esc>" || c == "\<C-c>" 
    return 
    endif 

    let bp = getpos("'[") 
    let ep = getpos("']") 
    if a:motion_wise ==# 'char' 
    call setpos('.', ep) 
    execute "normal! \"=c\<Return>p" 
    call setpos('.', bp) 
    execute "normal! \"=c\<Return>P" 
    elseif a:motion_wise ==# 'line' 
    let indent = matchstr(getline('.'), '^\s*') 
    call append(ep[1], indent . c) 
    call append(bp[1] - 1, indent . c) 
    elseif a:motion_wise ==# 'block' 
    execute bp[1].','.ep[1].'substitute/\%'.ep[2].'c.\zs/\=c/' 
    execute bp[1].','.ep[1].'substitute/\%'.bp[2].'c\zs/\=c/' 
    call setpos('.', bp) 
    else 
    endif 
endfunction 
call operator#user#define('surround', 'OperatorSurround') 
map s <Plug>(operator-surround) 

Nếu bạn thực sự muốn xác định đối tượng văn bản của riêng bạn, hãy xem xét vim-textobj-user.

+0

Liệu ai đó có thể đưa ra một ví dụ cụ thể thực tế về công việc này như thế nào. Tôi đã thử mọi thứ. Ví dụ: lệnh nào làm gì? Cảm ơn! –

Các vấn đề liên quan