vim 围绕轴交换所选内容

vq8itlhq  于 2023-06-23  发布在  其他
关注(0)|答案(5)|浏览(119)

(NOT Swap text around equal sign的可能副本:)
我经常发现自己在交换东西。这是一个痛苦的屁股。
让我们说,就在我写完这段代码之后

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

我注意到一行中有太多的星号,我不喜欢这样,我想交换乘法星号周围的两个因子。
或者,我写

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

但我突然意识到,出于某种原因,defined (__MINGW32__)必须先出现。
我想如果我能做这样的事情会很酷:
(On字符x[x]表示光标位置。<S>代表这个假设的“交换”命令)

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

command:vf&<S>$ => select from cursor to pivot(单词&&),并将选中的内容与文本交换,直到行尾。
或者,对于前一个示例:

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

command:v3f*<S>f) => select from here to third *,swap with text forward to ).
对我来说,这将是非常有用的。有没有类似的东西,或者我必须编写自己的插件?
谢谢!

    • 编辑**-

正如@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.

谢谢!最后一句话呢:)

agxfikkp

agxfikkp1#

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

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'总是包含任何周围的空格,并且可以使用作为Map中Swap()的参数的单个字符类来定义它。
如果您想看到它突出显示,请选中https://gist.github.com/1921196

uurity8g

uurity8g2#

我使用following plugin,它的灵感来自于一个vim提示。
首先,我删除(一次性删除--diw也算作一个,而xx不算作一个)我想交换的第一部分。然后我在视觉上选择第二部分。最后我点击了g"

  • 瞧!* 两个文本被交换了。

当然,这并不像选择旋转点那么简单。这是正常的,因为它不仅是关于一个支点:我们必须在一个时间或另一个时间指定要交换的两个文本的开始和结束位置,以及当主元是零长度(艾德?).

2nc8po8w

2nc8po8w3#

让我提出以下Map作为假设的<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

此实现不仅适用于单行上的字符选择,而且适用于行选择和块选择。

olqngx59

olqngx594#

我想出了一个解决方案,它的工作流程有些不同。您可以在视觉模式下选择文本,然后指示要围绕其旋转的字符/文本。在大多数情况下,我希望考虑空格,因此,默认情况下,数据透视文本周围的空格作为实际数据透视的一部分。我将itMap到\a这样的序列,以逗号为中心(使用',','的显式Map;'、'.'和空格)和\aa提示输入透视文本,因此您可以使用\aaand围绕单词“and”进行透视。
下面是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

这对于单线交换很有效,但我认为多线的情况需要清理。

wh6knrhe

wh6knrhe5#

选择要交换的区域。按<C-s>。让Vim做剩下的事情。任何非单词字符都将是主元。

vnoremap  <C-s> :s/\%V\(\w\+\)\(\W\+\)\(\w\+\)/\3\2\1<cr>:noh<cr>

相关问题