围绕枢轴交换选择

时间:2012-02-26 22:55:36

标签: vim

(不是Swap text around equal sign的可能重复:)

我经常发现自己在交换东西。这是屁股的痛苦。

我写完这段代码之后就说吧

tmp = realloc (words, sizeof (char **) * (*count + 1));

我注意到连续的星号太多,不喜欢它,并希望在乘法星号周围交换这两个因子。

或者,我写了

#if !defined(_CONSOLE_H_) && defined (__MINGW32__)

但我突然意识到defined (__MINGW32__)必须先出于某种原因。

我认为如果能做到这样的话会很酷:

(在一个字符x上,[x]表示光标位置。<S>代表这种假设的“交换”命令)

#if [!]defined(_CONSOLE_H_) && defined (__MINGW32__)

命令:vf&<S>$ =&gt;选择从光标到枢轴(单词&&),并将选择与文本交换到行尾。

或者,对于前一个例子:

tmp = realloc (words, [s]izeof (char **) * (*count + 1));

命令:v3f*<S>f) =&gt;从此处选择第三个*,将文字转发至)

对我来说,它会非常有用。有没有这样的东西,或者我必须编写自己的插件?

谢谢!

编辑 -

作为@ib。在他的回答的评论中说,我需要更具体地说明什么是支点。

枢轴也可以是一个角色,例如:

static char ** tokenize_input (char * input, PDWORD count);

我可能想要围绕","交换两个参数。更确切地说,", "

所以也许我需要两个命令:

<s> - char-wise - the pivot is the last character of the selection;
<S> - word-wise - the pivot is the last word of the selection.

谢谢! (ps。最后的 Word ?:)

4 个答案:

答案 0 :(得分:5)

这似乎在这里工作,让我知道它是如何做的:

function! Swap(...) "{{{
  let start_v = col("'<")
  let end_v = col("'>")
  let mv = ''
  let isMv = 0
  while !isMv
    let char = s:GetChar()
    if char == '<Esc>'
      return ''
    endif
    let mv .= char
    let isMv = s:IsMovement(mv)
    echon mv."\r"
  endwhile
  if isMv == 2
    return ''
  endif
  exec "normal! ".end_v.'|'.mv
  let lhs = '\%'.start_v.'c\(.\{-}\S\)'
  if !a:0
    let pivot = '\(\s*\%'.(end_v).'c.\s*\)'
  else
    let pivot = '\(\s*'.a:1.'*\%'.(end_v).'c'.a:1.'\+\s*\)'
  endif
  let rhs = '\(.*\%#.\)'
  exec 's/'.lhs.pivot.rhs.'/\3\2\1/'
endfunction "Swap }}}

function! s:GetChar() "{{{
  let char = getchar()
  if type(char) == type(0) && char < 33
    return '<Esc>'
  elseif char
    let char = nr2char(char)
  endif
  return char
endfunction "GetChar }}}

function! s:IsMovement(mv) "{{{
  let ft = a:mv =~ '^\C\d*[fFtT].$'
  let ft_partial = a:mv =~ '^\C\d*\%([fFtT].\?\)\?$'
  let right = a:mv =~ '^\d*[l$|;,]\|g[m$]$'
  let right_partial = a:mv =~ '^\d*\%([l$|;,]\|g[m$]\?\)\?$'
  if !right_partial && !ft_partial
    return 2
  endif
  return ft || right
endfunction "IsMovement2Right }}}

" Use last char as pivot. e.g.: the comma in the given example.
vmap <silent> <leader>s1 :<C-U>call Swap()<CR>
" Use \S\+ (WORD) as pivot. e.g.: &&
vmap <silent> <leader>ss :<C-U>call Swap('\S')<CR>
" Use \w\+ as pivot.
vmap <silent> <leader>sw :<C-U>call Swap('\w')<CR>

无需按Enter即可指定移动。 'pivot'总是包含任何周围的空格,它可以使用单个字符类定义,作为映射中Swap()的参数。

如果要突出显示,请检查https://gist.github.com/1921196

答案 1 :(得分:1)

让我提出以下映射作为假设的实现 <S>命令。

vnoremap <silent> <leader>m xm':<c-u>set opfunc=PasteAfter<cr>g@
function! PasteAfter(type)
    let [sl, sc] = getpos("'[")[1:2]
    let [cl, cc] = getpos("''")[1:2]
    let back = sl < cl || (sl == cl && sc < cc)
    undojoin | exe 'norm!' ['`]p`[', '`[P`]'][back]
endfunction

此实现不仅适用于单个字符的字符选择 line,但也用于行选择和块选择。

答案 2 :(得分:1)

我使用受到vim提示启发的following plugin

首先我删除(一次性 - diw也算作一个,而xx没有)我要交换的第一部分。然后我在视觉上选择第二部分。最后我点击g"

Etvoilà!这两个文本已被交换。

当然,这并不像选择枢轴那么简单。这是正常的,因为它不仅仅是关于一个支点:我们必须指定交换开始和结束的两个文本的时间,以及转轴为零长度(编辑?)的情况。

答案 3 :(得分:1)

我想出了一个有点不同工作流程的解决方案。您以可视模式选择文本,然后指示要转动的字符/文本。在大多数情况下,我想要考虑空白,因此,默认情况下,数据透视文本周围的空白作为实际数据透视的一部分包含在内。我将它映射到像\ a这样的序列,以绕过逗号(使用',',';','。'和空格的显式映射)和\ aa提示透视文本,这样你就可以使用\ aaand围绕“和”一词转动。

这是vimscript:

vmap <silent> <leader>aa :call SwapAround()<CR>
vmap <silent> <leader>a, :call SwapAround(',')<CR>
vmap <silent> <leader>a. :call SwapAround('\.')<CR>
vmap <silent> <leader>a; :call SwapAround(';')<CR>
vmap <silent> <leader>a<Space> :call SwapAround("[ \t\n]*")<CR>

function! SwapAround(...) range
  if 1 == a:0
    let exp = a:1
  else
    call inputsave()
    let exp = input('pivot:')
    call inputrestore()
  endif
  if exp !~ '[ \t\n]' 
    let exp = '[ \t\n]*'.exp.'[ \t\n]*'
  endif
  call s:SwapAroundBase(exp, getpos("'<"), getpos("'>"))
endfunction

function! s:SwapAroundBase(sepExp, start, end) range
    let save_a = @a
    try
      let originalText = s:getText(a:start, a:end)
      let sepStart = match(originalText, a:sepExp)
      let sepEnd = matchend(originalText, a:sepExp)
      let firstOne = strpart(originalText, 0, sepStart)
      let sep = strpart(originalText, sepStart, sepEnd - sepStart)
      let secondOne = strpart(originalText, sepEnd)
      let @a = secondOne.sep.firstOne
      let posStatus = setpos(".", a:start)
      normal! v
      let posStatus = setpos(".", a:end)
      normal "ap
    finally
      let @a = save_a
    endtry
endfunction

function! s:getText(start, end)
  let lines = getline(a:start[1], a:end[1])
  let lines[-1] = lines[-1][: a:end[2] - 1]
  let lines[0] = lines[0][a:start[2] - 1:]
  return join(lines, "\n")
endfunction

这适用于单行交换,但我认为需要清理多行情况。