SCSS 파일을 자동으로 컴파일하게 하기 - vim
scss 파일을 저장할 때 자동으로 컴파일 해주는 기능을 만들어보자. 이런 종류의 기능은 보통 vim의 autocmd나 키맵 등을 설정하여 만들 수 있다. 오토 커맨드로 등록하는 경우, 특정한 패턴의 파일을 열거나, 파일을 새로 만들거나, 저장하는 전후 등의 시점에 자동으로 수행될 수 있다.
SCSS 컴파일은 외부 컴파일러에 의존하고 있다. 따라서 vim 내에서 실행하면 해당 프로그램이 실행되는 동안 vim은 해당 프로세스가 종료되기를 기다리면서 동작을 멈추게 된다. 비록 짧은 시간이기는 하지만 이 과정이 제법 신경쓰일 수 있다.
그런데 vim8부터는 비동기로 이런 작업을 처리할 수 있는 기능이 제공된다. (따라서 vim7 이하버전에서는 실행되지 않는데, 이를 위한 처리를 통합했다.) 여기서 컴파일은 pysassc
에 의존하며 이는 파이썬 pip를 이용해서 libsass
를 설치하면 얻을 수 있다.
이제 vim 내에서 어떤식으로 비동기 명령을 실행하는지 알아보자.
job_start()
함수를 사용하면 특정한 외부 명령을 비동기로 실행할 수 있다. 이 함수가 실행되면 자식 프로세스로 주어진 명령이 시작되고, 해당 명령과 연결되는job
객체가 생긴다.- vim 과 해당 프로세스는 채널을 통해 연결되고 job 은 시작시의
job_start()
의 옵션으로 몇 가지 이벤트에 대한 핸들러함수를 지정받을 수 있다. "close_cb"
옵션으로 지정한 함수는 해당 job의 채널을 인자로 받게된다. 따라서 채널을 통해 외부 프로세스의 표준 출력 혹은 표준 에러를 읽어올 수 있다.
먼저 SCSSCompile1
이라는 함수를 작성한다. 이 함수는 비동기 작업이 지원될 때 호출될 함수이다. 그런 다음 SCSSCompile0
함수는 비동기 지원이 되지 않는 상황에 호출될 함수로 작성한다.
SCSSCompile1
함수에서는 pysassc 를 호출하여 현재 파일을 css 파일로 컴파일하도록 한다. 그리고 채널이 닫힐 때 SCSSCompileHandler
함수가 호출되도록 한다. 이 콜백 전달은 job_start()
함수에 두 번째 인자로 사전 형식으로 지정한다. close_cb
가 채널이 닫힐 때 호출되는 콜백이다.
function! SCSSCompile1()
echom 'Compiling: ' . expand('%')
let l:commands = ['pysassc', expand('%'), expand('%<') . '.css']
let job = job_start(l:commands, {'close_cb': 'SCSSCompileHandler'})
endfunction
function! SCSSCompile0()
echo 'Compiling...'
let cname = expand('%')
let oname = expand('%<') . '.css'
normal! ':!sassc ' . cname . ' ' . 'oname'
endfunction
핸들러 함수는 채널을 인자로 받으며, 채널의 상태를 확인하여 표준 출력 부분의 데이터가 남아있으면 이를 읽어서 메시지로 출력한다. 이 때 ch_status()
함수와 ch_read()
함수를 사용한다. 이는 각각 한 줄씩만 읽어들이므로 반복하여 사용해야 한다.
function! SCSSCompileHandler(ch)
echo 'Compiliation Completed'
while ch_status(a:ch, {'part': 'out'})
let output = ch_read(a:ch, {'timeout': 1})
echom output
endwhile
endfunction
이제 두 함수중 하나를 읽어들일 명령인 BuildSCSS
를 정의한다. 이 명령은 SCSSCompile{ }
로 중괄호를 포함하는 함수를 호출하는데, 중괄호 이름은 내부 표현식의 평가 결과에 의한다. 즉 has('job')
이 있으면 1, 없으면 0이기 때문에 그 때마다 적당한 명령이 실행될 것이다.
command! -nargs=0 BuildSCSS call SCSSCompile{has('job')}()
최종적으로 *.scss, *.sass 파일을 저장할 때마다 이 명령이 실행되도록 autocmd를 등록한다.
augroup PYSASS
au!
au BufWritePost *.sass,*.scss BuildSCSS
augroup END
이상으로 scss 파일을 편집하고 저장하면 자동으로 css 파일로 컴파일하는 과정을 구현해보았다. 아래는 전체 코드이다.
function! SCSSCompile1()
let l:commands = ['pysassc', expand('%'), expand('%<') . '.css']
let job = job_start(l:commands, {'close_cb': 'SCSSCompileHandler'})
endfunction
function! SCSSCompile0()
echo 'Compiling...'
let cname = expand('%')
let oname = expand('%<') . '.css'
normal! ':!sassc ' . cname . ' ' . 'oname'
endfunction
function! SCSSCompileHandler(ch)
echo 'Compiliation Completed'
while ch_status(a:ch, {'part': 'out'})
let output = ch_read(a:ch, {'timeout': 1})
echom output
endwhile
endfunction
function! SCSSCompile1()
echom 'Compiling: ' . expand('%')
let l:commands = ['pysassc', expand('%'), expand('%<') . '.css']
let job = job_start(l:commands, {'callback': 'SCSSCompileHandler'})
endfunction
function! SCSSCompile0()
echo 'Compiling...'
let cname = expand('%')
let oname = expand('%<') . '.css'
normal! ':!sassc ' . cname . ' ' . 'oname'
endfunction
command! -nargs=0 BuildSCSS call SCSSCompile{has('job')}()
augroup PYSASS
au!
au BufWritePost *.sass,*.scss BuildSCSS
augroup END