tools/vim

Learn Vimscript The Hard Way - 32. Case Study: Grep Operator, Part One - 2/2

seul chan 2020. 4. 10. 00:15

Case Study: Grep Operator, Part One

해당 장은 case study part one - 1/2에서 이어지는 글이다.

Escaping Shell Command Arguments

앞 장에서 사용한 방법 (작은따옴표로 quoting하는 방법)에도 문제가 있다. 검색하려는 string에 작은따옴표가 포함된 경우이다. that's에 커서를 두고 매핑된 grep을 실행시켜보자.

만약 새로운 window라면 :nnoremap <leader>g :grep -R '<cWORD>' .<cr> 명령어로 매핑을 추가하고 예시를 진행해보자.

that's

이를 해결하기 위해서 shellescape 함수를 사용할 수 있다. :help escape():help shellescape()를 읽어서 어떻게 동작하는지 살펴보자. (꽤 쉽다)

shellescape() 명령어는 vim string에서 작동하기 때문에 명령어를 execute를 사용하여 동적으로 빌드해 주어야 한다. 우선 :grep 매핑을 :execute "..." 형태로 변경해보자.

:nnoremap <leader>g :execute "grep -R '<cWORD>' ."<cr>

위 명령어가 이전과 동일하게 작동하는지 확인해보자.

그리고 shellescape를 사용하게 명령어를 수정해보자.

:nnoremap <leader>g :execute "grep -R " . shellescape("<cWORD>") . " ."<cr>

해당 명령어가 아까와 동일하게 작동하는지 foo와 같은 일반 단어에 적용해보자.

잘 작동한다면 that's에 적용해보자. 여전히 작동하지 않는 것을 볼 수 있다. 왜 그런것일까?

그 이유는 vim이 <cWORD>같은 special string을 해석하기 전에 shellescape() 함수를 호출해서이다. 그래서 shellescape는 커서 아래 있는 단어가 아니라 "<cWORD>"를 문자 그대로 해석한다.

아래 명령어로 이 동작을 실제로 확인해볼 수 있다.

:echom shellescape("<cWORD>")
'<cWORD>'

이를 해결하기 위해 expand() 함수를 사용하여 shellescape 함수가 실행되기 이전에 <cWORD>를 커서 아래에 있는 스트링으로 해석하게 할 것이다.

that's 에 커서를 올리고 아래 명령어를 실행해보자

:echom expand("<cWORD>")
that's

이를 shellescape에 추가해보자.

:echom shellescape(expand("<cWORD>"))
'that'\''s'

'that'\''s'가 반환되는 것을 볼 수 있다. 조금 이상해 보이고 해석하기 어렵지만, 일단 vim이 이를 제대로 escape 했다고 믿어보자.

이제 <leader>g 매핑에 이를 적용해보자.

:nnoremap <leader>g :execute "grep -R " . shellescape(expand("<cWORD>")) . " ."<cr>

이제 that's에 커서를 올리고 <leader>g를 실행시키면 잘 작동하는 것을 볼 수 있다!

Cleanup

매핑을 마무리하기 전에 몇가지 살펴보아야 할 것이 남았다. 지금은 처음 검색 결과로 바로 넘어가버리는데, 이를 방지하기 위해 grep 대신 grep!을 사용하면 된다.

:nnoremap <leader>g :execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>

vim은 quickfix window를 채우지만, 이를 열지는 않는다. quickfix window를 열게 명령어를 수정해보자.

:nnoremap <leader>g :execute "grep! -R " . shellescape(expand("<cWORD")) . " ."<cr>:copen<cr>

이제 quickfix window가 열리는 것을 볼 수 있다!

이제 마지막으로 grep output이 나오는 것을 없애고 바로 quickfix window가 뜨게 해보자. silent 명령어는 해당 명령어를 실행시켜서 나오는 메세지를 숨겨주는 역할을 한다.

:nnoremap <leader>g :silent execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>:copen<cr>

Exercise

  • Add the mapping we just created to your ~/.vimrc file.

  • Read :help :grep if you didn't read it before.

  • Read :help cword.

<cword>    is replaced with the word under the cursor (like |star|)
<cWORD>    is replaced with the WORD under the cursor (see |WORD|)
  • Read :help cnext and :help cprevious. Try them out after using your new grep mapping.

  • Set up mappings for :cnext and :cprevious to make it easier to quickly run through matches.

나는 딱히 추가하지는 않았다. :cn, :cp(:cN)로 사용 가능하기 때문. 아래와 같이 추가하면 된다.

nnoremap <leader>cn :cnext<cr>
nnoremap <leader>cp :cprevious<cr>
  • Read :help expand.
    (읽어도 잘 모르겠다..)

  • Read :help copen.

  • Add a height to the :copen command in the mapping we created to make sure the quickfix window is opened to whatever height you prefer.

  • Read :help silent.