콘텐츠로 건너뛰기
Home » vim에서 컴파일 결과를 바로 보기

vim에서 컴파일 결과를 바로 보기

typescript나 scss 처럼 다른 언어로 컴파일하는 스크립트를 작성하고, 이 결과를 별도의 창에서 확인하는 기능을 vim에서 구현하는 방법을 알아보자. 기본적으로 vim에서는 :r 명령을 사용하면 쉘을 통해 실행한 외부 명령의 출력을 현재 버퍼로 가져오는 것을 수행할 수 있다. 그 외에도 job을 이용한 비동기 방식의 처리도 가능하고 아예 vim 내에 터미널 창을 만들어서 실행하는 방법등 여러 방법이 있다. 오늘은 이러한 방법을 사용해서 vim에서 scss를 컴파일한 결과를 보여주는 방법에 대해서 살펴보겠다.

오늘의 예제는 scss 파일을 css로 컴파일하는 예를 들었다. typescript 나 livescript를 js 파일로 컴파일하는 것도 같은 방식으로 처리할 수 있다. 우선 scss를 컴파일하는 컴파일러를 설치할 필요가 있다. 만약 파이썬이 설치돼 있다면 libsass의 파이썬 구현체를 간단하게 설치할 수 있다.

pip install libsass

성공적으로 설치가 됐다면, pysassc 라는 실행 가능한 파일이 함께 설치되어 사용할 수 있다.

컴파일해볼 원본 소스는 간단히 아래와 같다.

.-code {
	font-family: "Cascade Code", monospace;
}
.-as-inline-code {
	@extend .-code;
}

p, li {
	code {
		@extend .-as-inline-code;
	}
}
pre {
	background-color: #999;
	code {
		@extend .-as-inline-code;
	}
}

:r 명령을 사용하기

가장 간단한 방법은 앞서 소개했듯이 :r[ead] !{cmd} 명령을 사용하는 것이다. 이 명령은 외부명령인 {cmd}를 실행하고 해당 명령의 출력을 가져와서 현재 위치에 덧붙이게 된다. 따라서 새 버퍼창을 만들고 몇 가지 설정을 해준 다음, 해당 버퍼에서 이를 실행하면 된다. 참고로 외부 명령에 % 를 사용하면 현재 버퍼의 파일의 경로를 넘겨주는 것인데, # 를 대신 사용하면 바로 직전 버퍼(vim에서는 alternative file이라 부른다.)의 파일을 전달한다.

belowright new 
setfiletype css
r !pysassc #
set nomodifiable

위 명령은 다음과 같은 순서대로 실행한다.

  1. 아래 혹은 오른쪽으로 분할창을 생성하고 새 버퍼를 만든다. 이 시점에 커서는 새 윈도로 이동한다.
  2. 파일 타입을 css로 변경한다.
  3. pysassc 명령에 이전 버퍼의 파일을 이름을 넘겨서 결과를 가져온다.
  4. 파일을 수정할 수 없게 만든다.

플러그인 형식으로 다듬기

위 순서대로 명령만 나열해도 어느 정도 작동하는데, 이건 ‘최선의 시나리오’를 가정하고 만들었던 것이라 어느 정도 쓸만하게 만들려면 약간의 노력이 더 들어가야 한다. 우선 전체 과정을 vimscript 함수로 작성해서 키 맵으로 호출할 수 있도록 해야 편하게 쓸 수 있다. 또 열렸던 실행창은 쉽게 닫을 수 있으면 좋겠고, 무엇보다 실행 시에 그 전에 열어놨던 결과창이 있다면 미리 닫고 시작하도록 해야겠다.

사실 이 아이디어는 파이썬 스크립트를 vim 내에서 실행하는 방법을 소개하는 글에서 소개했던 방법인데, 조금 새로운 방법을 찾아내어 깔끔하게 적용해 보았다. 그 외에는 :r !{cmd} 방식이 아니라 job_start() 를 사용해서 비동기 작업을 수행하도록 했다.

function! s:compile() 
	if &l:filetype != 'scss' | return | endif
	if exists('b:outbufnr') && winbufnr(b:outbufnr) > -1
		execute winbufnr(b:outbufnr) .. 'hide'
	endif
	let commands = ['pysassc', expand('%:p')->fnameescape()]
	let temp = bufnr()
	let b:outbufnr = bufadd('')
	execute 'belowright sbuffer ' .. b:outbufnr
	let b:srcbufnr = temp
	setlocal buftype=nofile nobuflisted noswapfile bufhidden=wipe
	setfiletype css
	nnoremap <buffer><silent> <Esc> <Cmd>hide<CR>
	let jobid = job_start(commands, #{
		\out_io: 'buffer',
		\out_buf: bufnr(),
		\exit_cb: {_, s -> popup_dialog((s == 0 ? 'Done' : 'Failed!'), 
                            \#{time:1000})},
	        \})
endfunction

nnoremap <Plug>(compile_scss) <Cmd>call <SID>compile()<CR>
nmap <F7> <Plug>(compile_scss)
  1. 실행시 소스 버퍼에 버퍼-로컬 변수 b:outbufnr 를 만들고, 출력용 버퍼의 번호를 담아둘 것이다. 따라서 이 변수가 이미 정의돼 있다면 이전에 실행했다는 의미이므로, 출력용 버퍼를 표시하고 있는 창이 있을 때 이를 닫아야 한다.
  2. belowright new 를 하면 창을 생성한 즉시 새 창으로 이동해버린다. 따라서 bufadd('') 를 사용해서 빈 버퍼를 우선 만들고 그 결과를 b:outbufnr 에 저장해둔다. 그리고 출력창을 표시하려 할 때, 이미 있는 버퍼를 분할창에 표시하려면 :sbuffer 명령을 사용하면 된다. 창을 분할하여 버퍼를 표시하면 커서가 곧장 새 창으로 이동하고, “현재 버퍼”가 변경된다.
  3. buftype=nofile noswapfile nobuflised bufhidden=wipe 옵션은 결과 버퍼를 임시창처럼 사용하게 한다. (자세한 내용은 vim 도움말을 참고하라)
  4. job을 사용해서 결과를 실행한다. 컴파일러가 느리거나 오래 걸리는 작업이라도 그 사이에 vim 작업이 중단되지 않는다. 또한 컴파일러에서 line-by-line 으로 출력되는 것이 있으면 그때 마다 버퍼의 내용이 갱신될 수 있다. job을 생성할 때 콜백을 사용해서 완료 메시지 팝업이 1초간 뜨도록 했다.

일단 위 코드를 .vimrc에 삽입해 두는 것만으로도 작동은 할 것이다. .vimrc 뿐만 아니라 다른 vim 파일로 저장해두고 필요한 시점에 :so 명령을 사용해서 로드해두면된다.

흥미로운 것은 위에서 구현해 놓은 코드는 사실 결과를 출력하기 위한 외부 명령만 정해지면 그것이 무엇이든간에 결과를 새로운 결과창으로 표시할 수 있는 기능을 만들어놓은 것이라는 점이다. 따라서 버퍼에 따라서 자신을 처리할 수 있는 명령을 알고만 있다면 그걸 실행해서 출력창에서 내용을 확인할 수 있게 된다. 어떤 식으로 좀 더 일반적인 경우에 사용할 수 있도록 활용할 수 있는지 다음에 (꼭) 알아보도록 하자.

0 Comments

No Comment.

%d 블로거가 이것을 좋아합니다: