Pythonファイルタイプを使用している場合、vimで複数行の文字列を再フォーマットするにはどうすればよいですか?


23

vimでPythonコードを編集していて、少し似ていると仮定しましょう。

myobj.myfunc("Some string parameter that goes on and on and on and on and sometimes doesn't"
             "split very"
             "neatly over different lines so that"
             "it is formatted attractively")

私はこれを再フォーマットしたいので、textwidth設定したとおりにリフローします:

myobj.myfunc("Some string parameter that goes on and on and "
             "on and on and sometimes doesn't split very "
             "neatly over different lines so that it is "
             "formatted attractively")

これを行う簡単な方法はありますか?これが従来のテキスト段落であるgqip場合、または類似したものは有用ですが、文字列の区切りに使用される引用符は処理しません。

:ここではPythonについて具体的に質問していますが、理想的には、この回答は文字列の継続を許可する多くの種類のプログラミング言語に関連します。



3
また、コードの書き換えを検討しました"""multi-line string"""か?
200_success

1
@ 200_success、それは素晴らしいヒントです、ありがとう。Pythonのその機能についてはまったく知りませんでした。機能するように見えますが、ほとんどの場合-関数へのすべてのパラメーターはリフローされますが、理想的ではありません。私の質問は、私が持っている文字列のタイプ、そして他の言語にも当てはまると思います。
アンドリューフェリエ

2
複数行の文字列は空白文字を追加することに注意してください。空白文字が文字列内で重要な場合、これは問題になる可能性があります。
マットベーム

回答:


6

それは大変なことです。おそらく最良のアプローチはマクロですが、おそらくプラグインであると思います。ここに、私がホイップした例があります(より良い趣味が必要です)。私にはうまくいくように見えましたが、適切にインデントするにはpython indentingプラグインが必要です。やってみて。

function ReformatMultiLines()
  let brx = '^\s*"'
  let erx = '"\s*$'
  let fullrx = brx . '\(.\+\)' . erx
  let startLine = line(".")
  let endLine   = line(".")
  while getline(startLine) =~ fullrx
    let startLine -= 1
  endwhile
  if getline(endLine) =~ erx
    let endLine += 1
  endif
  while getline(endLine) =~ fullrx
    let endLine += 1
  endwhile
  if startLine != endLine
    exec endLine . ' s/' . brx . '//'
    exec startLine . ' s/' . erx . '//'
    exec startLine . ',' . endLine . ' s/' . fullrx . '/\1/'
    exec startLine . ',' . endLine . ' join'
  endif
  exec startLine
  let orig_tw = &tw
  if &tw == 0
    let &tw = &columns
    if &tw > 79
      let &tw = 79
    endif
  endif
  let &tw -= 3 " Adjust for missing quotes and space characters
  exec "normal A%-%\<Esc>gqq"
  let &tw = orig_tw
  let endLine = search("%-%$")
  exec endLine . ' s/%-%$//'
  if startLine == endLine
    return
  endif
  exec endLine
  exec 'normal I"'
  exec startLine
  exec 'normal A "'
  if endLine - startLine == 1
    return
  endif
  let startLine += 1
  while startLine != endLine
    exec startLine
    exec 'normal I"'
    exec 'normal A "'
    let startLine += 1
  endwhile
endfunction

次に:call ReformatMultiLines()、マッピングで使用したり、マッピングで使用したりできます。


6

これが定期的に発生する場合は、プラグインを探すか@Sukimaの関数を使用するのが最善です。ただし、これをオンザフライで実行していた場合、おそらく次のようになります。

  1. 文字列が別の行にあるように、開始括弧の後と終了括弧の前に改行を追加します。

    myobj.myfunc(
                 "Some string parameter that goes on and on and on and on and sometimes doesn't"
                 "split very"
                 "neatly over different lines so that"
                 "it is formatted attractively"
    )
    
  2. 文字列のある行を選択し、周囲の引用符を削除します。 :norm ^x$x

  3. テキスト幅を減らす(引用符がないことを考慮して) :set tw-=2
  4. 再選択してフォーマット: gvgq
  5. テキスト幅を修正: :set tw+=2
  6. 引用符を再追加:gv:norm I"<Esc>A"。代わりに、<Esc>ctrl-vに続いてエスケープキーを入力して、リテラルエスケープを挿入します。jjをエスケープにマップするので、通常ここにjjと入力します。
  7. オプションで、Jを使用して最初の2行または最後の2行を再結合します。このようなPythonで非常に長い文字列がある場合、通常は次の行で開始し、前の行よりも1レベルだけインデントすることを好みます。これにより、弦の水平方向のスペースが広くなり、自然に感じられます。または、文字列を上記のどこかの変数に保存することもできます。静的な文字列であると仮定すると、それをグローバル変数に保存して、インデントレベルをはるかに低くし、より少ない行に収めることができます。同じ行で閉じ括弧を再結合することに注意してください。おそらく、textwidthを2ではなく3ずつ増減します。

1
ありがとう。私はこれを試したが、:set tw-=2結果はE487: Argument must be positive: tw-=2。構文は間違っていますか?
アンドリューフェリエ

1
でtextwidthの現在の値を確認し:set tw?ます。私の推測では、textwidthを0に設定しています。これらの手順は、textwidthが行ごとに必要な文字数から始まることを前提としています。
マットBoehm

あなたの例では、おそらくs/2/3/閉じ引用符の前にスペースを追加したいでしょう、あなたの長い文字列は単語間の適切なスペースを持っていません。
cdosborn

1

特にPythonなどの動的言語では、コードの解析とフォーマットは困難です。

代わりにVimscriptでのPythonを解析しようと、私はあなたのような外部のフォーマッタを使用することができますお勧めしますyapf。ではここで私の答えあなたが書き込み時に自動的にこれを書くことができます。

augroup write_cmd
    autocmd BufWritePre *.py call s:write_cmd('yapf')
augroup end

s:write_cmd()この関数は、他の答えである-私はバグを見つけた場合2つの場所でそれを更新する必要はありませんので、私はそれをここに追加しません:-)

に設定formatprgyapfて手動でフォーマットすることもできますgq


こんにちは。役に立つ答えですが、この質問に答えているとは思わないので、私は賛成です。この質問は、具体的には複数行の文字列の再フォーマットについて尋ねていますが、そうでyapfはないようです。それにもかかわらず、私はそれが便利なツールのように見えることに同意します。
アンドリューフェリエ

@AndrewFerrierフェア; 先日これをテストしたときに文字列を再フォーマットするのを見たことがありましたが、今は動作しません:-/私は混乱していたと思います。
マーティントゥルノイ

0

次の関数と対応するマッピングにより、この問題は解決されました。

function! BreakMultlineString(quote)
let c = 100
while c == 100
    normal 100|
    let c = virtcol('.')
    if c == 100
        execute "normal ," . a:quote
    endif
endwhile
endfunction

function! JoinMultilineString()
    let c = "'"
    while c == "'" || c == '"'
        normal gj^
        let c = matchstr(getline('.'), '\%' . col('.') . 'c.')
        normal k
        if c == "'" || c == '"'
            normal ,j
        endif
    endwhile
endfunction

" break lines
nnoremap <Leader>" 100\|Bi"<CR>"<Esc>
nnoremap <Leader><Leader>" :call BreakMultlineString('"')<CR>
nnoremap <Leader>' 100\|Bi'<CR>'<Esc>
nnoremap <Leader><Leader>' :call BreakMultlineString("'")<CR>

" join lines
nmap <Leader>j Jds'ds"x
nnoremap <Leader>J :call JoinMultilineString()<CR>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.