Как я могу переформатировать многострочную строку в vim при использовании типа файла Python?


23

Давайте предположим, что я редактирую некоторый код Python в vim, который выглядит примерно так:

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, но в идеале этот ответ будет уместен для многих типов языков программирования, которые допускают продолжение строки.


1
Подобный вопрос здесь: vim.1045645.n5.nabble.com/…
Эндрю Ферье

3
Вы также рассматривали возможность переписать код как """multi-line string"""?
200_success

1
@ 200_success, это отличный совет, спасибо. Я вообще не знал об этой возможности Python. В основном это работает, хотя все параметры функции переформатированы, что не идеально. Я думаю, что мой вопрос все еще действителен для типа строки, которую я имею, и, конечно, для других языков.
Эндрю Ферье

2
Обратите внимание, что многострочная строка будет добавлять пробельные символы, что может быть проблемой, если пробел имеет значение в строке.
Мэтт Бём

Ответы:


6

О, это сложно. Я думаю, что лучший подход, возможно, макрос, но, скорее, плагин. Вот пример, который я взбил (мне нужно лучшее хобби). Кажется, это работает для меня, но для правильного отступа понадобится плагин для отступа Python. Попробуйте это.

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>, чтобы вставить буквальный escape, введите ctrl-v, а затем клавишу escape. Так как я отображаю jj, чтобы убежать, я обычно просто набираю jj здесь.
  7. При желании используйте J для повторного соединения первых двух / последних двух строк. Когда у меня в Python есть очень длинная строка, подобная этой, я обычно предпочитаю начинать ее со следующей строки и делать отступ только на один уровень больше, чем в предыдущей строке. Это дает больше горизонтального пространства для струны и кажется мне более естественным. В качестве альтернативы, вы можете сохранить строку в переменной где-то выше. Предполагая, что это статическая строка, вы можете даже сохранить ее в глобальной переменной, чтобы она имела гораздо более низкий уровень отступа и могла помещаться на меньшем количестве строк. Обратите внимание, что вы должны присоединиться к закрывающей части в той же строке, вы, вероятно, хотите уменьшить / увеличить текстовую ширину на 3 вместо 2.

1
Спасибо. Я только что попробовал это, но в :set tw-=2результате E487: Argument must be positive: tw-=2. Синтаксис неверен?
Эндрю Ферье

1
Проверьте текущее значение текстовой ширины с :set tw?. Я предполагаю, что у вас текстовая ширина установлена ​​в 0. Эти шаги предполагают, что текстовая ширина начинается с количества символов, которое вы хотите на строку.
Мэтт Бём

В вашем примере вы, вероятно, захотите s/2/3/добавить пробел перед закрывающей кавычкой, и ваша длинная строка не будет иметь правильного расстояния между словами.
cdosborn

1

Синтаксический анализ и форматирование кода сложны, особенно для динамических языков, таких как Python.

Вместо того, чтобы пытаться анализировать Python в Vimscript, я рекомендую вам использовать внешний форматтер, такой как yapf . С моим ответом здесь вы можете написать это автоматически при записи:

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

s:write_cmd()Функция в другой ответ - я не буду добавлять его здесь , так что я не придется обновлять его в двух местах , если я нахожу ошибку :-)

Вы можете также установить formatprgна yapfи вручную форматировать его 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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.