ㅈㅅㄹ

Emacs spell checker

Emacs2016. 3. 11. 10:23

Emacs를 개발용 에디터로 주로 사용하기는 하지만 지금처럼 블로그 포스팅을 적거나 개발 문서 혹은 commit 메시지, 혹은 개발을 하면서도 주석같은 걸 쓰다보면 아무래도 철자를 실수할 때가 있다. 그래서 spell-checker가 필요할 때가 많은데 다행히도 GNU Emacs에는 기본적으로 ispell로 철자 교정 기능을 지원하고 있으며, 이를 backend로 이용한 flyspell-mode을 통해 틀린 부분을 highlight 할 수도 있다. 물론 이것들만을 사용해도 철자 교정하는데 무리는 없겠지만 그래도 얘네들만으로는 불편한 점이 많다. ispell은 아래 그림처럼 버퍼 상단에 선택 가능한 아이템을 표시하며 번호를 눌러 선택하는 식이라 직관적이지 않고, flyspell-mode의 경우도 어차피 highlight 시켜 주는 기능 뿐이긴 하지만 좀 더 만져주면 쓸만해질 구석이 보인다.



  1. ac-ispell
  2. 우선은 가장 필요해 보이는 건 자동 완성 기능인데, 내 경우 자동 완성에 auto-complete를 사용하므로 거기에 ispell의 추천 단어를 dictionary backend로 붙여 주는 ac-ispell를 사용한다. 사용법은 파일 주석에도 얘기하고 있듯, ac-ispell-setup을 호출한 다음, 원하는 major mode의 hook에 ac-ispell-ac-setup을 추가하면 된다.

    (eval-after-load 'auto-complete
      '(ac-ispell-setup))
    (add-hook 'text-mode 'ac-ispell-ac-setup)
    

    이렇게 설정하고 나면, text-mode에서 파생한 major mode에서 ispell의 추천 단어들로 자동 완성을 시도하게 된다.



    내 경우는 el-get 패키지 매니저를 사용하지만 ac-ispell의 레시피가 아직 추가가 안 되어 있어서 로컬에서 레시피를 아래와 같이 작성해서 쓴다.

    (:name ac-ispell
           :description "An ispell/aspell completion source for auto-complete."
           :website "https://github.com/syohex/emacs-ac-ispell"
           :type github
           :pkgname "syohex/emacs-ac-ispell"
           :post-init (eval-after-load "auto-complete"
                        '(ac-ispell-setup)))
    


  3. flyspell-mode
  4. flyspell-mode는 Emacs에 기본 탑재 되어 있으므로 추가로 설치할 필요는 없다. 다만 좀 더 편하게 쓰기 위해선 약간의 설정이 필요한 부분이 있다. 우선 flyspell-mode는 프로그래밍에 관련한 major mode에서 주석이나 문자열에 대해서만 철자 검사를 돌려주는 flyspell-prog-mode라는 모드를 지원하고 있는데, prog-mode에서 파생된 major mode들에서는 flyspell-prog-mode을, 그 외의 경우는 flyspell-mode를 실행하게 한다면 좀 더 편할 것이다.


    또한 auto-completeflyspell-mode을 같이 쓸 경우 auto-complete가 제때 잘 돌지 않는 문제가 있는데, 이건 사실 auto-complete의 문제라기보단 flyspell-mode에서 sit-for을 쓰는게 문제라 GNU Emacs에서 차후에 이걸 고치지 않는 이상은 auto-complete쪽에서 workaround로 만들어 놓은 ac-flyspell-workaround를 실행해 줘야 flyspell-mode를 활성화 시켜놔도 auto-complete가 잘 동작한다.

    (define-minor-mode my:flyspell-mode
      "Enable flyspell-mode."
      :variable my:flyspell-mode
      (if my:flyspell-mode
          (progn
            (if (derived-mode-p 'prog-mode) (flyspell-prog-mode)
              (flyspell-mode))
            (if (called-interactively-p) (flyspell-buffer)))
        (flyspell-mode -1)))
    
    (eval-after-load 'auto-complete
      '(ac-flyspell-workaround))
    


  5. flyspell-popup
  6. 위의 그림에도 있지만 기본 ispell의 인터페이스는 딱히 유저 친화적이라고 보긴 힘들다. flyspell-popupispell의 추천 목록을 popup 형태로 출력해서 선택할 수 있게 해 주는 보다 직관적인 인터페이스를 제공해 준다.

    (eval-after-load 'flyspell
      '(progn
         (define-key flyspell-mode-map (kbd "M-$") #'flyspell-popup-correct)
         (add-hook 'flyspell-mode-hook #'flyspell-popup-auto-correct-mode)))
    

    위 코드를 적용하면 flyspell-mode가 활성화 되었을 때는, 틀린 철자의 단어에 커서를 두고 원래 ispell의 키인 M-$를 누르거나 일정 시간 대기할 때, 아래 그림처럼 추천 단어 목록의 popup을 overlay로 표시하게 된다.



    이것도 마찬가지로 el-get에 공식 레시피로 아직까지 포함이 안되어 있는데, 필요하다면 아래의 레시피를 사용하자.

    (:name flyspell-popup
           :description "Correct the misspelled word in popup menu"
           :website "https://github.com/xuchunyang/flyspell-popup"
           :type github
           :pkgname "xuchunyang/flyspell-popup"
           :post-init (eval-after-load 'flyspell
                        '(progn
                           (define-key flyspell-mode-map (kbd "M-$") #'flyspell-popup-correct)
                           (add-hook 'flyspell-mode-hook #'flyspell-popup-auto-correct-mode))))
    


  7. 문제점들
    • 한글 지원 문제
    • 일단 가장 큰 문제는 한글의 교정 지원 문제인데, 현재 기본으로 사용하는 aspell에서는 아직까지 한글을 지원하지 않는다. 대안으로는 hunspell이 있으며 ispell-program-name"/usr/bin/hunspell"로 바꾸고 ispell-change-dictionary로 사전을 ko_KR로 바꿔 주면 한글 사전을 검사 하는 데, 주의할 점은 ispell-change-dictionary를 실행하면 해당 버퍼의 사전만이 바뀐다. 처음에 이걸 몰라서 잘 안도는 것인가 하고 착각했었으니 주의하자. 물론 이게 쓸 수 있다고는 해도 frontend 측면이건 backend 측면이건 만족스러울 정도는 아니라서 아직 갈 길이 멀어서 잘 쓰지는 않게 된다.

    • 다중 언어 동시 지원 문제
    • 또 한 가지 불편한 점은 동시에 여러 언어에 대한 검사를 하지 못한다는 점이다. 사실 이 글만 해도 영문과 한글이 공존하는 글이지만 ispell에서는 한 번에 한 사전만을 사용하므로 만약 내가 위의 hunspell에서의 한글 지원이 만족스러운 수준이 되더라도 한글 교정을 위해서는 ispell-change-dictionary로 또 한글 사전으로 변환을 해서 철자법 검사를 돌려줘야 한다는 것이다. 뭐 어떻게 ispell 프로세스를 여러개 띄워서 인코딩 보고 적절한 backend 프로세스를 고르는 방식으로 하면 어찌 될 것 같기도 하지만 아직은 엄청난 필요성이 느껴지지 않아 고민하진 않고 있다. 나중에 뭐 필요하면 또 깨작거려 보겠지. -_-