Neovim 플러그인을 Haskell로 작성해보십시오.

5799 단어 neovim하스켈
Neovim은 Vim과 달리 플러그인을 작성할 때 언어별 인터페이스라는 것은 존재하지 않으며 MessagePack-RPC에서 Neovim과는 독립적으로 움직이는 플러그인과 통신하여 다양한 작업을 수행한다는 모델처럼 입니다.

그래서 Haskell에서 Neovim 플러그인을 작성해 보았습니다.

TL;DR



GitHub 에 동작하는 샘플 코드를 넣었습니다. 빌드하고 실행하면 다음과 같이 움직입니다.





설명 등



nvim-hs이라는 Neovim 플러그인 공급자를 사용하여 구현했습니다. 이 패키지에도 정중한 설명이 쓰여져 있습니다만, 나는 Neovim도 Vim도 플러그인을 쓴 적이 없기 때문에, 마음대로 모르게 상당히 집착했습니다.

첫 번째는 파일의 구성입니다.
.
├── app
│   └── Main.hs
└── src
    ├── Hello
    │   └── Plugin.hs
    └── Hello.hs

소스는 이런 느낌이 되고 있습니다. nvim-hs 설명에도 잘 쓰여졌지만 Hello.hs 와 Plugin.hs 는 Hello.hs 에서 Template Haskell 을 사용하고 있는 편의상 정리할 수 없는 것 같습니다. 그래서 구현을 Plugin.hs 에 쓰고 설정 등을 Hello.hs 에 쓰도록 합니다.

두 번째는 Neovim에서 호출되는 진입 점이되는 쉘 스크립트입니다.

쉘 스크립트는 다음과 같이 되어, 체크등을 생략하면 빌드 해 생긴 바이너리를 stack 경유로 호출하고 있을 뿐입니다.
#!/bin/bash

plugin_name=neovim-plugin-hello-haskell
plugin_dir="$(cd $(dirname $0) && pwd)"

pushd $plugin_dir > /dev/null

if [ -d "$plugin_dir/.stack-work" ]; then
  stack exec $plugin_name-exe -- "$@"
  rc=0
else
  echo "No development directories found. Have you built the project?"
  rc=2
fi

popd > /dev/null

exit $rc

nvim-hs의 원래 샘플은 stack을 통해 nvim-hs의 바이너리를 호출했기 때문에 어떤 방식으로 구현 된 코드가 실행되는지 알지 못했으며 여기에서 상당히 멀었습니다.

dein.vim으로 관리 가능



작법으로서 GitHub의 리포지토리를 다음과 같이 해 둘 필요가 있는 것 같습니다.
.
├── autoloaded
│   └── neovim-plugin-hello-haskell.vim
└── plugin
    └── neovim-plugin-hello-haskell.vim

autoloaded 는 필요한 타이밍에 로드되는 처리를 plugin 는 Neovim 시작 시 로드되는 처리로 나누는 것이 좋습니다. 이번 샘플은 함수 하나이므로 plugin 에 넣었습니다.

Vim Script의 이름은 무엇이든 괜찮은 것 같습니다. 아마 runtime! 에서 읽는 것입니다.

이 Vim Script는 열심히 Haskell로 쓰지 않고 VimL로 쓰는 것이 편하다고 생각합니다. 거의 보일러 플레이트이므로 VimL을 잘 모르더라도 한 번 만들어 버리면 이후에는 곤란하지 않습니다.
if !has('nvim')
  finish
endif

if exists("g:loaded_neovim_plugin_hello_haskell")  " ここと
  finish
endif
let g:loaded_neovim_plugin_hello_haskell = 1  " ここの変数名だけ変える

let s:save_cpo = &cpo
set cpo&vim

let s:script_dir = expand('<sfile>:p:h')
call rpcrequest(rpcstart(s:script_dir . '.sh'), "PingNvimhs")

let &cpo = s:save_cpo
unlet s:save_cpo

위의 스크립트를 조금 설명합니다.
if has('nvim')는 Neovim에서만 작동하려는 경우의 가드입니다. Haskell 플러그인은 Neovim에서만 작동하기 때문에 붙이는 것이 친절합니다.
if exixts(...) 에서 let ... 는 2회 이상 실행하지 않기 위한 가드입니다. g:loaded_ 라는 변수명으로 시작하는 것이 관습인 것 같습니다. 변수에 플러그인명을 포함하면 뱃팅하는 것 같다.

다음 let s:save_cpo = &cposet cpo&vim 는 플러그인을 로드할 때 사용자의 설정을 일시적으로 무효로 하는 거짓말입니다.

그 다음 두 줄은 플러그인 처리입니다.

마지막 let &cpo = s:save_cpounlet s:save_cpo 는, 일시적으로 무효로 한 유저의 설정을 근거로 되돌릴 수 없는 것입니다.

미래의 도전


  • 상태 저장 플러그인 만들기
  • 플러그인 관리자로 관리하는 방법
  • 좋은 웹페이지 즐겨찾기