Як я можу переформатувати багаторядковий рядок у 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_успіх

1
@ 200_success, це чудова порада, дякую. Я взагалі не знав про цю особливість Python. Здається, це працює, в основному - хоча всі параметри функції поновлюються, що не ідеально. Я думаю, що моє запитання все ще справедливо для типу рядка, який я маю, і, звичайно, для інших мов.
Ендрю Фер’є

2
Зауважте, що багаторядковий рядок додасть символи пробілів, що може бути проблемою, якщо пробіл має значення в рядку.
Метт Боем

Дуже пов’язане питання: vi.stackexchange.com/questions/2135/… ...
Martin Tournoij

Відповіді:


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>ви хочете вставити буквальне втечу, ввівши 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 Ярмарок; Я міг би скласти присягу, що побачив, що це переформатують струни, коли я тестував це на днях, але я також не можу змусити його працювати: - / Вгадайте, я був розгублений.
Martin Tournoij

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.