이글랏: 이맥스 내장 LSP 서버

이글랏: 이맥스 내장 LSP 서버

2022-10-06 Note builtin eglot emacs lspmode notes
  • Related pages

애증의 Eglot 이전 기록들

마이크 교수와 리우는 Eglot 을 쓴다. 둘다 같다 심플하게 구성하고 싶어한다는 지점에서. 빌트인 기능을 최우선으로 사용하는게 또 클로저 철학과 맞다고 한다. 유니버셜 언어를 지향한다나? 둘다 프로젝트 관리에서도 Project.el 을 사용하고 있다. 그럼 그렇지. 아래 링크가 있지만 프렉티컬리 문서에는 같은 주제를 프로젝타일 LSP 로 세팅했다. 일반적인 방법이라고 할 수 있겠다. 시대는 변하고 변화에 능동적으로 다가서자는게 나의 생각이다.

Advise Eglot to Support Clojure Monorepo Setup 이 문서를 참고한다.

같은 개념은 프렉티컬리 문서에서 보았었다. Monorepo 라고 한다. 여기서는 프로젝타일 을 사용해서 모노리포를 구성했다. 아래 문서 참고. Monorepo / Nested projects · Clojure development with Spacemacs & Cider

가장 큰 문제

clojure 레이어를 넣으면… backend 로 lsp / cider 만 선택할 수가 있다. lsp 는 lsp-mode 만을 이야기하는 것이고 eglot 은 아니다. 호환이 안된다.

아예 스페이스맥스 clojure 레이어를 사용하지 않는다고 가정하고! 수동으로 다 잡아야 한다. 아무리 eglot 과 project.el 이라고 해도 이게 맞는 것인가?

  1. lsp 2) cider 3) eglot 뭐 이렇게 간단히 볼 수 있지만… 3 번은 스페이스맥스 구조에 반대되는 구성이다.

그래서 임시 결론! 22/10/06–21:42 :: 프렉티컬리 구성으로 가자!

project.el 을 제외하고 클로저 설정은 스페이스맥스 lsp 로 간다. 배움에 있어서 기본을 하고 (기본이라 함은 메뉴얼도 있고 학습이 용이한 대상)

Cider 도 물론 기본이고 corgi 를 유심히 보았기에… 근대 결국은 안쓰게 될 것이기 때문에 시간을 흘려 보내긴 아깝다. 아무튼 프렉틸컬리를 보고 가자!

새로운 생각과 대안 Eglot 가능하다! 그리고…

22/10/07–10:39 :: 떠오른 생각을 적음 eglot 레이어가 clojure 레이어랑 무슨 상관이지? 클로져는 둘다 clojure-lsp 쓰는 것일 뿐인데? 이맥스에서 lsp 레이어를 켜면, 둘이 연동이 되겠지?

clojure 레이어에서 backend lsp 했을 때 뭘하는지 보고, 혹시 lsp-mode 패키지에 의존적인 내용을 처리하고 eglot 으로 lsp 를 연동하게 해주면 지금 레이어에서도 같은 키 바인딩으로 eglot 을 지원할 수 있겠다.

  • 관건은 clojure layer 와 lsp layer 사이의 설정이다.
  • lsp layer 에서 무슨 설정을 하는가? eglot 레이어가 있다면 뭘 해야 하는가?
  • eglot 레이어를 찾고, 거기에 설정을 한다.
  • clojure 레이어에 eglot 옵션을 만들고, 활성화 시킨다. 그렇게 되면, backend 에 eglot 을 하면 끝.

논쟁이 있다. lsp 모드를 잘 쓰자! 끝!

eglot 으로 내가 대안을 만들 수 없다. 내가 메인테인할 것도 아니라면. 설득력이 없다.

Eglot 왜 어려웠나?

위의 이전 기록을 보면 뭐 자세히 읽고 싶지 않지만. 결국 Spacemacs 의 레이어 구성이 꼬인다는 걱정 때문이다. 그리고 꼭 여러가지 설정을 해야 한다는 생각을 하니까 (키 바인딩) 어렵다. 그리고 함께 알아야 하는 내용들이 여전히 많았음에도 잘 몰라서 벽이 높아 보일 수 있다.

새로운 시도는 아주 가볍게 일어났다. Company -> Corfu 로 변경을 하면서 알게 된 통찰 덕분이다. 내장 패키지를 이용하는 최근 패키지들은 의존성이 거의 없기 때문에 Spacemacs 에서 문제 되는 부분만 설치 안 한 뒤에 설치하고 핵심 키 바인딩 몇 개만 넣으면 된다. Flycheck, Flymake 도 문제 될 것이 없었다. 마이너 모드에서 동작할 뿐인데 해당 버퍼에서 끄면 된다. Eglot 은 Company 도 필요가 없기에 더욱이 그렇다. 이렇게 하고 보니 그래도 LSP 가 필요하냐는 근본적인 질문이 나오기 마련이다.

proselint-flymake, clj-kondo-flycheck 이런 방식은 오래 갈 수가 없다. 각각 efm-lang-server or megalint, clojure-lsp 라는 서버가 있지 않는가? 앞의 것은 범용 서버이고 뒤의 것은 Clojure 전용 서버일 뿐이다. 전용 서버는 해당 언어에 대한 디테일 기능을 포함하고 있다. 인터페이스는 물론 표준화가 되어 있기에 Eglot 같은 단일 엔트리 패키지가 있을 것이다. 뒤에 범용 서버는 개발 언어 뿐만 아니라 마크 업으로 작성 된 문자 텍스트도 커버 한다. 아무튼 서버 모델은 그냥 지나 칠 수가 없다. CIDER/Kondo/Refactor/Fommater 등 나뉘어 있는 기능들이 얼마나 많이 표준화 되어 처리되고 있는가? 그것도 별도의 프로세스에서 처리 되니 Emacs 는 감사해야 할 뿐이다. 이맥스는 싱글 스레드니까.

  • 2023-01-27

lsp-mode features with clojure

  • lsp-mode with clojure lsp-mode/clojure-guide.md at master · emacs-lsp/lsp-mode · GitHub

    Clojure 예제를 마주하기 위해서는 위의 페이지를 주목해야 한다. 아래 기능들을 쭉 살펴 보면서 <-> Eglot 과 1:1 매핑을 해본다. 안되는 것들은 말고 되는 기능들은 본다. 다 필요한 것도 아니다.

  • lsp-mode features

    1. Syntax check clj-kondo + flycheck 연동 된다.
    2. Find definition/references lsp-ui 패키지와 연동되는구나.
    3. Completion nil 을 하면 cider completion 을 사용한다. 아 그리고 lsp-mode 는 기본으로 company-mode 를 활용한다.
    4. Code actions
    5. Hover – conflict with CIDER
    6. Code lens lsp-lens-enable 설정하면 1 references 이런 정보 뜬다.
    7. Call hierarchy lsp-treemacs 를 사용한다고 한다. 이거 이글랏이 되겠나?
    8. Formatting cljfmt 를 이용한다.
    9. Refactoring – conflict with clj-refactor

[2023-01-27 Fri 05:54]

Eglot features

Diagnostics – Syntax check

진단 정보를 서버로부터 받아서 Flymake 를 이용해서 annotate / underline 으로 표기한다. 이 정보는 ElDoc 시스템과 공유되어 eldoc / eldoc-doc-buffer 에서 해당 문제에 대한 정보를 확인 할 수 있다. C-h . 으로 바인딩 되어 있다.

Eglot 은 Flymake 과 연동되기에 억지로 Flycheck 를 밀어 넣을 필요가 없다. 이에 더해, flymake-mode 를 미리 실행 할 필요도 없다. 자동으로 켜준다. 정확히 말하면 있던 녀석을 끄고 입맛에 맞게 설정해서 켜준다.

  • eldoc-doc-buffer ;; eglot-mode-map <normal-state> K ;; eglot-mode-map C-h .

eldoc 시스템과 연동되어 동작한다는 말이 무엇인가? CIDER 가 필요한가?

;; echo 에 정보가 보인다. 잠시만,
(defn foo [a b]
  (+ a b))

Find definition/references

Rename

Find definition – xref-find-definitions M-.

Find references – xref-find-references M.?

Completion

컴패니 또는 Corfu 에서 나열 할 수도 있지만, 이글랏은 completion-at-point 내장 함수와 연동되도록 이미 갖춰져 있다. 해당 바인딩은 C-M-i 화면에 표기 되는 방법과 나열 되는 리스트가 어떻게 다른지 궁금하다.

Snippet completion

해당 서버에서 스니펫 관련 기능을 제공한다면 연동이 가능할 것이다. 이게 서버를 사용하는 이유 아닌가? 더불어 yasnippet 도 지원한다. 앞서 완성에서 다룬 바와 마찬가지로 내장 기능 또는 자동 완성 패키지와 연동하면 된다.

Code Actions

서버가 지원하는 기능이다. 마우스가 일부 사용되는데 예제가 Clojure 였으면 좋겠다. 어디 있나? 있다. 일단 Clojure-lsp 홈페이지와 lsp-mode 홈페이지를 참고하면 된다. 코드 블록이 있으니까 해당 코드를 가지고 이글랏에서 해보면 된다.

Hover on symbol with function signature

ElDoc 을 이용한다. 관련 설정이 필요한가?

Code lens (?) – X 간단하지 않은 듯

Call hierarchy (?)

Formatting (?)

Refactoring (?)

lsp-mode.el – User-visible differences:

Single entry point – 가장 두드러진 차이는 eglot-<language>와 같은 패키지가 없다는 점이다. 엔트리

포인트는 M-x eglot 일 뿐이다.

project.el – 마찬가지로 내장 기능인 project.el 과 연동하여 프로젝트에

대한 정보를 얻는다. 별도로 해당 프로젝트를 설정하는 파일을 두지 않는다. projectile 과 대비되는 부분이다. 자연스레 내장 기능에 집중하게 된다.

Flymake – Diagnostics work out-of-the-box 라고 소개를 하는 바 Flycheck 가

필요 없다는 말이다. 이 또한 내장 기능이다.

Only Emacs – Emacs 만 있으면 된다. 다른 패키지가 필요가 없다. 하물며

Company 도 필요 없다. 위에 말한 바, 내장 completion-at-point 함수와 연동되기 때문이다.

Nothing to configure and minimalist approach – 특정 언어를 위해 설정 할 것이

없다. 성능에 집중한 단순하고 가벼운 구조.

“Eglot is considerably less code and hassle than lsp-mode.el. In most cases, there’s nothing to configure. It’s a minimalist approach focused on user experience and performance.”

(?) 기능에 대해서

이 마저도 서버에서 제공하는 기능인데 Eglot 이 처리하지 못하는 것인가? 그렇다면 clojure-lsp 설정에 일부는 lsp-mode 는 되고 eglot 은 못한다는 말인가? 예를 들어 formatting 설정이라면 어떠한가?

야! 그냥 다른 패키지로 커버하면 되잖아!라고 말한다면 그냥 그렇게 할 수는 없다. Server -> Eglot -> Packages 이렇게 라도 동작을 해야 한다. 그래야 서버에 설정한 그 무엇이라도 의미가 있다.

How to configuration

  • More performance we get! 여기에 원 개발자의 의견이 굉장히 좋아 보인다. 컴패니를 사용하며 전통적인 키 바인딩인 =C-M-i=를 사용한다고 한다. 그리고 eglot-ensure 을 사용하지 않고 프로젝트를 열면 M-x eglot 을 실행한다. 자동으로 할 필요 없으며 한번 열면 계속 작업을 하니까 번거롭지도 않다. Eglot 이 서버에 너무 많은 요청을 하지 않도록 다음과 같이 설정한다. LSP + Unsuitable Performance · Discussion #993 · joaotavora/eglot · GitHub

    그리고 (setq eldoc-area-prefer-doc-buffer t)으로 설정하는데, eldoc-box 를 사용하지 않고 버퍼에서 정보를 보는 것을 선호한다. 문제는 버퍼를 사용하면 저자의 표현에 따르면 sane with the Eldoc dance 를 막기 위한 것이다. 또한, flymake-goto-next-error/prev-error 를 M-n, M-p 로 사용한다. 이는 SLIME 을 사용할 때 부터 익숙한 바인딩 이기 때문이다.

    위 이야기를 보면서 생각을 정리하게 되었다. eldoc-box, eglot, corfu/Cape (manual), flymke 기반에 아래 설정을 넣는다. 그리고 수동으로 실행한다.

        (setq eldoc-idle-delay 0.75)
        (setq company-idle-delay 0.75)
        (setq flymake-no-changes-timeout 0.5)

Modeline information

[2023-01-27 Fri 10:38]

Advanced Topics

  • Practically clojure-lsp configuration 존의 설정 파일을 가져다가 쓰는 중이다. 이 설정 파일을 제대로 읽고 있는지 확인하고, 무슨 설정을 했는지 알아야 한다. 알고 써야 한다.

  • Tree-sitter – Emacs 29 내장 패키지를 사용하는 것이 더 빠르다는 의견이다. js2-mode (JavaScript)의 경우 성능 문제가 있으며 tree-sitter 를 사용하는 것이 가성비가 좋다고 한다.

Related-Notes

References

마지막 수정일자