Tarides에서 Emacs용 OCaml LSP 클라이언트인 `ocaml-eglot`을 소개하고, LSP와 Merlin, Emacs 통합, 설계 배경과 기능, 설치 방법을 설명합니다.
ocaml-eglot으로 OCaml LSP 서버에 Emacs 지원 추가하기Tarides에서 에디터 및 에디터 지원을 담당하는 팀은 ocaml-eglot 출시 소식을 전하게 되어 매우 기쁩니다! 이 프로젝트는 다양한 플랫폼과 워크플로에서의 OCaml 개발 경험을 개선하려는 Tarides의 노력의 일환이며, 이는 커뮤니티의 피드백과 함께 지속적으로 발전하고 있는 최우선 과제입니다.
OCaml의 LSP 서버에 Emacs 통합을 제공하는 것은 사용자와 유지관리자 모두에게 이득이 됩니다. Emacs를 사용하면서 이제 막 OCaml을 사용해 보려 하거나, 더 단순한 설정으로 전환하고 싶다면 GitHub에 있는 ocaml-eglot 저장소를 확인하여 새로운 Emacs 마이너 모드를 직접 사용해 보세요.
이 글에서는 새 도구의 개발 배경, LSP의 장점과 한계, 그리고 ocaml-eglot의 기능에 대해 살펴보겠습니다. 그럼 시작해 볼까요?
ocaml-eglot 프로젝트의 목표는 엔지니어들이 에디터 번아웃(editor burnout) 이라고 이름 붙인 문제를 해결하는 것이었습니다. 개발자는 워크플로를 단순화하기 위해 에디터에 의존하고, 수년에 걸쳐 점점 더 많은 에디터 기능이 추가되면서 에디터는 정교하고 기능이 풍부한 개발 환경으로 변모했습니다. 하지만 이 모든 기능은 각 에디터마다 추가되고 유지관리되어야 합니다. 다양한 에디터 전반에 걸쳐 수많은 기능을 유지하고, 언어 서버 쪽에 변화가 생길 때마다 그 지원을 갱신하는 일은 금세 감당하기 어려워질 수 있습니다. ‘에디터 번아웃’은 이런 압박이 유지관리자에게 가해지는 상황을 가리킵니다.
OCaml에서는 에디터에 독립적인 서버인 Merlin이 IDE와 유사한 서비스를 제공합니다. Merlin은 코드에 대한 문맥 정보를 제공함으로써, 개발자가 단순한 텍스트 에디터로도 OCaml을 작성하면서 일반적으로 완전한 IDE에서 제공하는 기능을 누릴 수 있게 해 줍니다. 하지만 Merlin 역시 각 코드 에디터마다 고유한 통합 계층이 필요했기 때문에 높은 유지보수 비용을 갖고 있었습니다.
그렇다면 문제를 이해한 지금, 해결책은 무엇일까요?
LSP, 즉 _Language Server Protocol_은 에디터와 IDE 서비스를 제공하는 서버 간 상호작용을 표준화한, 폭넓게 문서화된 공개 프로토콜입니다. LSP는 여러 프로그래밍 언어에 공통적인 표준 기능 모음을 정의하고 있으며, 이 점이 널리 채택되는 데 기여했습니다. 이 채택 덕분에 LSP는 Visual Studio Code, Vim, Emacs 등 많은 에디터에서 표준 프로토콜로 자리 잡았습니다.
OCaml에서 LSP를 구현하는 언어 서버는 ocaml-lsp입니다. 이 서버는 Merlin을 라이브러리로 사용합니다. 원래는 vscode-ocaml-platform 플러그인과 함께 사용할 때 Visual Studio Code와 통합되도록 설계되었습니다. 에디터 호환성에 대해서는 LSP의 기본값에 의존하고, OCaml 고유 기능에 대해서만 지원을 제공함으로써 유지보수 부담을 상당히 줄일 수 있습니다. 이는 유지관리자뿐 아니라 사용자에게도 이로운데, 플러그인이 성능, 호환성, 유지관리성, 최신 상태를 유지하도록 돕기 때문입니다.
LSP는 가능한 한 많은 언어와 호환되도록 설계되었기 때문에, 언어가 어떻게 구성되고 동작하는지에 대해 몇 가지 가정을 둡니다. 하지만 필연적으로 이런 가정만으로 모든 언어의 모든 기능을 포괄할 수는 없습니다. 이는 OCaml에도 해당되며, OCaml의 편집 경험은 LSP의 범위를 벗어나는 맞춤 기능에 크게 의존합니다.
이 불일치를 해결하는 방법은, 에디터의 표준 LSP 지원이 다루지 않는 부분을 보완하는 클라이언트 측 확장(client-side extension) 을 만드는 것입니다. 이렇게 하면 기본적인 LSP 호환성은 유지하면서도, OCaml 고유 기능을 지원하는 확장을 추가로 갖게 됩니다. 앞에서 암시했듯이, 이는 표준 LSP 처리는 일반적인 LSP 플러그인에 위임하고, 에디터 쪽의 유지관리 작업량을 줄인다는 부가적인 이점도 있습니다.
이러한 OCaml 전용 에디터 기능에는 type-enclosing, hole 생성 및 hole 간 내비게이션, destruct, 타입으로 검색 등이 포함됩니다.
OCaml 커뮤니티에서 인기가 높은 에디터인 Emacs와 OCaml이 어떻게 함께 동작하는지 간단히 살펴보겠습니다. Emacs에서는 개발자가 하나의 "버퍼"/파일을 메이저 모드에 연결하여 OCaml 같은 언어의 특정 기능(예: 구문 강조)을 처리하도록 할 수 있습니다. 하나의 파일은 항상 정확히 하나의 메이저 모드에만 연결됩니다.
OCaml에는 네 가지 메이저 모드가 있습니다:
caml-mode: 원조 모드tuareg: caml-mode를 완전히 재구현한 것으로, 사용자가 가장 많이 선택하는 모드ocaml-ts-mode: tree-sitter 문법을 기반으로 한 caml-mode의 실험적 버전neocaml: tree-sitter 문법을 기반으로 tuareg를 완전히 재구현한 실험적 버전이제 파일에는 하나 이상의 minor-mode를 추가로 연결할 수도 있고, 바로 여기서 ocaml-eglot이 등장합니다. 예를 들어, 메이저 모드(일반적으로 Tuareg를 권장합니다)를 사용하고, 그에 ocaml-eglot을 마이너 모드로 연결하면, Tuareg가 활성화된 모든 파일에 LSP 기능을 부여할 수 있습니다.
Eglot은 Emacs에 기본 번들로 포함된 LSP 클라이언트이며, ocaml-eglot은 Merlin 통합의 대안으로 Emacs에서 완전한 OCaml 언어 지원을 제공합니다. (덧붙여, ocaml-eglot 클라이언트는 LSP의 기본값을 그대로 사용하기 때문에, 코드 크기가 전통적인 OCaml Emacs 모드보다 훨씬 작습니다. 이는 유지보수도 더 쉽다는 의미입니다!).
ocaml-eglot의 이상적인 사용자는 이미 Emacs를 적극 사용하고 있고, 최소한의 초기 설정으로 OCaml을 사용해 보고 싶은 사람입니다. 단순화된 설정, 자동화된 셋업, 다양한 에디터와 언어 전반에 걸친 일관성은 OCaml 초보자뿐 아니라 여러 에디터를 사용하는 숙련된 사용자에게도 워크플로 향상 측면에서 큰 도움이 됩니다. 이 플러그인은 Emacs에서 Merlin을 통합하는 merlin.el이 제공하는 모든 기능을 지원하므로, 새 시스템으로 옮겨도 기능이 줄어들지 않습니다. ocaml-eglot 프로젝트는 적극적으로 유지관리되고 있으며, 앞으로도 정기적인 업데이트와 시대에 맞춰 발전하는 도구를 기대할 수 있습니다.
이제 ocaml-eglot 개발 뒷이야기를 조금 들여다보겠습니다. 서버 언어를 구현하는 개발자들이 LSP 밖의 기능을 추가할 때 흔히 사용하는 두 가지 접근 방식이 있습니다. 바로 Code Actions과 Custom Requests입니다:
OCaml-eglot의 설계 과정은 본질적으로, LSP로는 커버되지 않는 merlin.el의 모든 기능을 식별한 다음, 그것을 Code Action 또는 Custom Request 중 하나를 사용해 추가하는 작업이었습니다. 이 과정에서 개발자들은 다음 두 가지 질문을 던지며 어떤 방식을 사용할지 결정했습니다:
물론 실제로는 여기서 설명한 것보다 훨씬 복잡했지만, 팀이 개발 과정에서 어떤 종류의 기술적 결정을 내렸는지 이해하는 데는 이 정도로도 충분할 것입니다.
ocaml-eglot은 GitHub 저장소를 클론한 뒤 안내를 따라 설치할 수 있습니다. 프로젝트에서 충분히 사용해 본 뒤에는, OCaml Discuss에 경험을 공유해 주시면 다른 사용자들이 무엇을 기대해야 할지 알 수 있고, 유지관리자들이 무엇을 개선해야 할지 파악하는 데도 큰 도움이 됩니다!
ocaml-eglot 설치는 일반적인 Emacs 패키지 설치와 동일합니다. Melpa에 등록되어 있으며, GNU의 use-package 등 여러 방식으로 설치할 수 있습니다. ocaml-eglot의 권장 설정을 포함해 더 자세한 안내는 저장소의 readme에 나와 있습니다.
ocaml-eglot이 제공하는 기능 가운데 일부는 다음과 같습니다:
let, module, 함수, match 같은 언어 구성 요소 사이를 이동하고, 구문(phrase)과 패턴 case를 오갈 수 있습니다.ocaml-eglot이 제공하는 전체 명령 목록은 프로젝트의 readme에서 확인해 보세요. 새 모드는 ‘agile’하게 설계되어, toplevel에서 추출 리팩터링 같은 새로운 기능도 빠르게 실험하고 도입할 수 있습니다.
이 글보다 더 자세한 배경지식을 원하신다면 Xavier van de Woestyne, Sonja Heinze, Ulysse Gérard, Muluh Godson이 쓴 논문 “A New Era of OCaml Editing Powered by Merlin, Delivered by LSP”를 읽어 보시길 권합니다.
Bluesky, Mastodon, Threads, LinkedIn에서 저희와 소통하시거나, 메일링 리스트에 가입해 최신 프로젝트 소식을 받아보세요. 여러분의 목소리를 기다리겠습니다!