콘텐츠로 건너뛰기
Home » vim에서 작성중인 코드를 바로 실행하기

vim에서 작성중인 코드를 바로 실행하기

vim에서 파이썬이나 자바스크립트 코드를 작성하면서 실행 결과를 보고 싶을 때에는 보통 :!python % 명령을 실행해서 현재 파일을 실행하는 쉘로 잠시 넘어가서 결과를 볼 수 있습니다. 이 방법은 쉽게 실행해볼 수 있다는 장점이 있지만, 실행되는 동안 vim 화면을 볼 수 없고, 실행을 마치고 vim으로 돌아가면 출력된 결과를 다시 확인하기가 어렵다는 것입니다. VSCode 처럼 별도의 창에서 소스를 실행해보고 그 결과를 계속 확인할 수 있으면 참 좋을 것 같습니다. 이런 일을 도와주는 플러그인이 있을 것 같은데, 그냥 직접 만들어보기로 했습니다. 참고로 vim9 스크립트로 작성하였습니다.

플러그인 구조

아주 간단하기 때문에 완전히 독립적인 구조를 갖춘 플러그인으로 만들 생각은 없습니다만, 간단하게 런타임 패스의 각 디렉토리를 용도에 맞게 활용해 보는 것은 의미가 있을 거라 생각됩니다. 그래서 보통 많이 사용되는 사용자 계정 아래에 있는 설정 디렉토리에 파일들을 만듭니다. %HOMEPATH%\vimfiles\ 아래에 “autoload” 및 “ftplugin“, “plugin” 폴더를 만들고 여기에 필요한 스크립트를 작성합니다. 먼저 “autoload/builder.vim” 파일을 만듭니다. 이 파일에는 작성 중인 스크립트를 실행하는 함수인 RunInTerminal() 을 정의합니다. 이 함수는 새로운 터미널 버퍼를 만들어서 편집 중이던 스크립트를 실행하게 합니다. 실행하는 명령은 파일 타입에 따라 달라질 것이므로, ftplugin 폴더에 각 파일 타입별로 실행할 명령을 list<string> 타입으로 정의해 주는 파일 타입별 플러그인 파일을 나중에 추가할 것입니다.

vim9script
# autoload/builder.vim

export def RunInTerminal()
  # 터미널 창이나 결과 창에서 호출되었다면 바로 리턴합니다.
  if &l:buftype =~ 'term' || exists('b:srcbufnr')
    return
  endif

  # 버퍼에 정의된 "b:cmd_run" 변수가 없다면 실행하지 않습니다.
  if !(exists('b:cmd_run'))
    echo "No command is defined."
    return
  endif

  # 이미 열려진 터미널이 있다면 닫기
  # hide 만 해주는 것으로 버퍼가 제거되도록하는 설정을 나중에 할 거에요.
  if exists('b:outbufnr') && bufwinnr(b:outbufnr) > -1
    execute ':' .. bufwinnr(b:outbufnr) .. 'hide'
  endif

  var temp = bufnr()
  term_start(b:cmd_run)
  # 새 터미널을 시작하면 현재 버퍼가 터미널 버퍼가 됨
  # 터미널버퍼에 소스버퍼를 기록하고, 다시 터미널 버퍼번호를 얻음
  b:srcbufnr = temp
  temp = bufnr()

  # 터미널 버퍼 설정. 버퍼가 hide 될 때 제거되도록 한다.
  setlocal nobuflisted bufhidden=delete noswapfile
  nnoremap <buffer> <Esc> <Cmd>hide<CR>
  tnoremap <buffer><silent> <Esc> <C-\><C-n>
  # 소스 버퍼로 돌아가서 outbufnr을 기록해주고 되돌아옴
  execute ':' .. bufwinnr(b:srcbufnr) .. 'wincmd w'
  b:outbufnr = temp
  execute ':' .. bufwinnr(temp) .. 'wincmd w'
enddef

이렇게 작성한 함수는 편집 중인 파일 종류를 가리지 않고 실행할 명령(b:cmd_run 으로 정의된)만 있으면 터미널에서 실행할 수 있게 됩니다. 만약 파이썬 코드를 작성한 후 실행하려면 파이썬 파일 타입에 대해서 b:cmd_run 명령을 정의해주면 됩니다. 아마 시스템에 따라서는 편집 중인 파일이름을 제외하면 같은 명령을 사용하겠죠. 이 명령들은 각 파일을 편집하려는 시점에 버퍼 범위 변수로 설정할 것이기 때문에 ftplugin 폴더 아래에 각 파일 타입을 이름으로 하는 vim 스크립트를 작성해주면 됩니다. 파이썬의 경우 “ftplugin/python.vim” 파일을 만들어주고 내용은 다음과 같이 작성합니다.

vim9script
# ftplugin/python.vim

b:filepath = expand('%:p')->fnameescape()
b:cmd_run = ['python', b:filepath]

원한다면 자바스크립트 파일을 실행할 수 있는 명령도 정의할 수 있습니다. 원하는 파일 타입에 대해서 콘솔에서 실행할 수 있는 해석기가 있다면 같은 방식으로 얼마든지 만들 수 있습니다.

vim9script
# ftplugin/javascript.vim

b:filepath = expand('%:p')->fnameescape()
b:cmd_run = ['node', b:filepath]

이제 이들을 조합할 명령을 정의합니다. “plugin/” 폴더 안에 있는 스크립트는 vim이 시작될 때 자동으로 로드됩니다. 여기에 플러그인 키 맵을 정의하는 작은 플러그인 하나를 만들어 놓습니다.

vim9script
# plugin/buider.vim
import autoload "builder.vim"
noremap <script><nowait><silent> <Plug>(run-in-terminal)
           \ <ScriptCmd>builder.RunInTerminal()<CR>

끝으로 vimrc 파일에 다음 한 줄을 추가하여 <F8> 키를 누르면 작동하도록 다음 라인을 추가해줍니다. 저는 습관이 돼서 F8로 하고 있지만 원하는 키 시퀀스를 넣으면 되겠네요.

# in vimrc

nmap <F8> <Plug>(run-in-terminal)

이제 vim을 재시작한 다음 파이썬이나 자바스크립트 파일을 편집하거나 새로 작성하고 저장한 후에 <F8> 키를 누르면 화면 아래에 터미널 창이 새로 생기면서 결과가 출력됩니다. <Esc> 키를 누르면 터미널 모드에서 노멀 모드로 빠져나오고, 한 번 더 누르면 터미널 창이 닫히게 됩니다.