파이썬 파일 형식을 사용할 때 vim에서 여러 줄 문자열을 다시 포맷하려면 어떻게해야합니까?


23

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이거나 이와 유사한 경우 유용하지만 문자열을 지정하는 데 사용되는 따옴표는 처리하지 않습니다.

참고 : 파이썬에 대해 특별히 묻고 있지만 이상적 으로이 대답은 문자열 연속을 허용하는 많은 유형의 프로그래밍 언어와 관련이 있습니다.


1
비슷한 질문이 여기에 : vim.1045645.n5.nabble.com/…
Andrew Ferrier

3
코드를 다시 작성하는 것을 고려 했습니까 """multi-line string"""?
200_success

1
@ 200_success, 좋은 팁입니다. 감사합니다. 나는 파이썬의 그 기능에 대해 전혀 몰랐습니다. 함수에 대한 모든 매개 변수가 리플 로우되지만 이상적이지는 않지만 대부분 작동하는 것 같습니다. 내 질문은 여전히 ​​내가 가지고있는 문자열 유형과 다른 언어에 유효하다고 생각합니다.
Andrew Ferrier

2
여러 줄 문자열은 공백 문자를 추가하므로 문자열에 공백이 중요한 경우 문제가 될 수 있습니다.
매트 Boehm

매우 관련성 높은 질문 : vi.stackexchange.com/questions/2135/… ...
Martin Tournoij

답변:


6

오 힘든 일입니다. 가장 좋은 방법은 매크로이지만 플러그인 일 가능성이 큽니다. 다음은 내가 채운 예입니다 (더 나은 취미가 필요합니다). 그것은 나를 위해 작동하는 것처럼 보이지만 제대로 들여 쓰기 위해 파이썬 들여 쓰기 플러그인이 필요합니다. 사용해보십시오.

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. 누락 된 따옴표를 설명하기 위해 textwidth를 줄입니다. :set tw-=2
  4. 다시 선택하고 형식을 지정하십시오. gvgq
  5. 텍스트 너비 수정 : :set tw+=2
  6. 따옴표를 다시 추가하십시오 gv:norm I"<Esc>A". 대신 <Esc>ctrl-v와 이스케이프 키를 입력하여 리터럴 이스케이프를 삽입하려고합니다. jj를 이스케이프하도록 매핑하기 때문에 보통 여기에 jj를 입력합니다.
  7. 선택적으로 J를 사용하여 처음 두 줄 / 마지막 두 줄을 다시 결합하십시오. 파이썬에서 매우 긴 문자열을 사용하면 일반적으로 다음 줄에서 시작하고 이전 줄보다 한 단계 만 들여 쓰기를 선호합니다. 이것은 줄에 더 많은 수평 공간을 제공하고 나에게 더 자연스러운 느낌을줍니다. 또는 문자열을 위의 어딘가에 변수에 저장할 수 있습니다. 정적 문자열이라고 가정하면 전역 변수에 저장하여 들여 쓰기 수준이 훨씬 낮고 더 적은 줄에 맞출 수 있습니다. 같은 줄에서 닫는 부분을 다시 결합해야 할 것이므로 텍스트 너비를 2 대신 3으로 줄이십시오.

1
감사. 방금 시도했지만 :set tw-=2결과는 E487: Argument must be positive: tw-=2입니다. 구문이 올바르지 않습니까?
Andrew Ferrier

1
로 textwidth의 현재 값을 확인하십시오 :set tw?. 내 생각에는 textwidth가 0으로 설정되어 있습니다.이 단계에서는 textwidth가 한 줄에 원하는 문자 수로 시작한다고 가정합니다.
Matt Boehm

귀하의 예에서 아마도 s/2/3/닫는 따옴표 앞에 공백을 추가하고 싶을 것입니다. 긴 문자열에는 단어 사이에 적절한 간격이 없습니다.
cdosborn

1

특히 파이썬과 같은 동적 언어의 경우 코드 구문 분석 및 서식 지정이 어렵습니다.

Vimscript에서 Python을 구문 분석하는 대신 yapf 와 같은 외부 포맷터를 사용할 것을 권장합니다 . 로 여기에 내 대답은 당신과 함께 쓰기에 자동으로 작성할 수 있습니다 :

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

s:write_cmd()함수는 다른 답변에 있습니다-여기에 추가하지 않으므로 버그를 발견하면 두 곳에서 업데이트 할 필요가 없습니다 :-)

로 설정 하고 수동으로 형식 formatprg을 지정할 수도 있습니다 .yapfgq


안녕. 유용한 답변이지만이 질문에 대답하지 않는다고 생각하여 다운 투표하고 있습니다.이 질문은 여러 줄 문자열을 다시 포맷하는 것에 대해 매우 구체적으로 묻습니다 yapf. 그럼에도 불구하고 나는 그것이 유용한 도구처럼 보입니다.
Andrew Ferrier

@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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.