diff --git a/README.md b/README.md index e6599da..9ec8d4d 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,14 @@ Like `cx`, but use the current line. Clear any {motion} pending for exchange. -### Notes about the mappings +### Some notes * `X` can be used from visual mode, which is sometimes easier than coming up with the right {motion} * If you're using the same motion again (e.g. exchanging two words using `cxiw`), you can use `.` the second time. +* If one region is fully contained within the other, it will replace the + containing region. Example ------- diff --git a/doc/exchange.txt b/doc/exchange.txt index 200ffdc..9bdf657 100644 --- a/doc/exchange.txt +++ b/doc/exchange.txt @@ -8,9 +8,10 @@ This plugin is only available if 'compatible' is not set. INTRODUCTION *exchange* This plugin provides |operators| for exchanging text in two places. The main -operator is |cx|, which is used in pairs. Each time it is used, it defines -a region of text to to be exchanged; on the second use, the two defined regions -are exchanged. +operator is |cx|, which is used in pairs. Each time it is used, it defines a +region of text to to be exchanged; on the second use, the two defined regions +are exchanged. If one region is fully contained within the other, it replaces +the containing region. MAPPINGS *exchange-mappings* diff --git a/plugin/exchange.vim b/plugin/exchange.vim index 1aa6c94..d552717 100644 --- a/plugin/exchange.vim +++ b/plugin/exchange.vim @@ -1,4 +1,4 @@ -function! s:exchange(x, y, reverse) +function! s:exchange(x, y, reverse, expand) let reg_z = getreg('z') let reg_z_mode = getregtype('z') let reg_unnamed = getreg('"') @@ -11,10 +11,12 @@ function! s:exchange(x, y, reverse) call setreg('z', a:x[0], a:x[1]) silent exe "normal! `[" . a:y[1] . "`]\"zp" - call setpos("'[", a:x[2]) - call setpos("']", a:x[3]) - call setreg('z', a:y[0], a:y[1]) - silent exe "normal! `[" . a:x[1] . "`]\"zp" + if !a:expand + call setpos("'[", a:x[2]) + call setpos("']", a:x[3]) + call setreg('z', a:y[0], a:y[1]) + silent exe "normal! `[" . a:x[1] . "`]\"zp" + endif if a:reverse call cursor(a:x[2][1], a:x[2][2]) @@ -63,17 +65,23 @@ function! s:exchange_set(type, ...) let exchange1 = b:exchange let exchange2 = s:exchange_get(a:type, a:0) let reverse = 0 + let expand = 0 let cmp = s:compare(exchange1, exchange2) if cmp == 'overlap' echohl WarningMsg | echo "Exchange aborted: overlapping text" | echohl None return s:exchange_clear() + elseif cmp == 'outer' + let [expand, reverse] = [1, 1] + let [exchange1, exchange2] = [exchange2, exchange1] + elseif cmp == 'inner' + let expand = 1 elseif cmp == 'gt' let reverse = 1 let [exchange1, exchange2] = [exchange2, exchange1] endif - call s:exchange(exchange1, exchange2, reverse) + call s:exchange(exchange1, exchange2, reverse, expand) call s:exchange_clear() endif endfunction @@ -143,7 +151,11 @@ function! s:compare(x, y) " When the characterwise region spans only one line, it is like blockwise. " Compare two linewise or characterwise regions. - if (s:compare_pos(xs, ye) <= 0 && s:compare_pos(ys, xe) <= 0) || (s:compare_pos(ys, xe) <= 0 && s:compare_pos(xs, ye) <= 0) + if s:compare_pos(xs, ys) <= 0 && s:compare_pos(xe, ye) >= 0 + return 'outer' + elseif s:compare_pos(ys, xs) <= 0 && s:compare_pos(ye, xe) >= 0 + return 'inner' + elseif (s:compare_pos(xs, ye) <= 0 && s:compare_pos(ys, xe) <= 0) || (s:compare_pos(ys, xe) <= 0 && s:compare_pos(xs, ye) <= 0) " x and y overlap in buffer. return 'overlap' endif