레이블이 Emacs인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Emacs인 게시물을 표시합니다. 모든 게시물 표시

2010년 10월 18일 월요일

[Clojure] Emacs, SLIME, swank-clojure, clojure-mode 조합의 문제 해결하기

Clojure로 뭔가를 할 때 Emacs, SLIME, swank-clojure, clojure-mode 조합을 사용하려면 Clojure Box가 가장 이상적인 환경이라고 할 수 있을 것입니다. 그러나, 이미 자신만의 Emacs 환경을 가지고 있다면(아마 처음 Emacs를 접한 분이 아니라면 대부분 자신만의 환경을 가지고 있을 겁니다. Emacs란 그런 물건이니까요.) Clojure Box를 별도로 설치해서 사용하기보다는 자신의 Emacs 환경에 통합하기를 더 좋아할 겁니다.

저는 SLIME과 swank-clojure, clojure-mode 각각을 고유 저장소에서 직접 내려 받아 사용하고 있습니다. 그런데, SLIME이 변경되는 속도는 swank-clojure가 그것을 따라잡는 속도보다 조금 더 빠르고, Clojure의 여러 가지 파격적(?) 문법이 함수형 언어에 '달아' Common Lisp과 '서르  사맛디 아니'하다는 점 때문에 약간의 문제가 생기곤 합니다. 그래서, 지금까지 저장소 버전을 사용하면서 겪었던 문제에 대해 그 해결 방법을 정리해보았습니다.


1. SLIME REPL 버퍼가 멈추는 문제

제일 처음 겪은 심각한 문제는 SLIME의 REPL 버퍼가 멈추는 것이었습니다. 도무지 원인을 알 수가 없었지요. 이리저리 마구잡이로 설정을 변경해가며 테스트 해보다가 결국 알아낸 것이, slime-autodoc-mode가 활성화되어 있을 때 문제가 발생한다는 것이었습니다.

이 문제를 해결하기 위한 방법은 간단합니다. SLIME을 시작하기 전에 slime-autodoc-mode를 비활성화해주면 됩니다.
(setq slime-use-autodoc-mode nil)
Common Lisp에선 slime-autodoc-mode가 문제 없이 잘 동작하므로, Clojure와 Common Lisp을 같이 사용하는 경우라면 별도의 함수를 만들어서 상황에 따라 slime-use-autodoc-mode 변수값을 적절히 바꿔주면 됩니다.

그리고, SLIME이 clojure-mode와 연동되기 때문에 clojure-mode에서 slime-autodoc-mode가 활성화될 경우 마찬가지로 SLIME REPL 버퍼가 멈추게 됩니다. 이 문제를 해결하기 위해서는 clojure-mode에 대해 slime-autodoc-mode를 비활성화하는 hook을 추가해줍니다.
(eval-after-load "clojure-mode"
  '(progn
     (add-hook 'clojure-mode-hook
               (lambda ()
                 (slime-autodoc-mode 0)))))

또 한 가지, desktop-save-mode를 설정해서 사용하고 있고, Emacs 실행 시 자동으로 다시 열리는 파일 중 clojure 소스 파일이 있다면 여전히 SLIME REPL 버퍼와 clojure 소스 버퍼가 멈추는 문제가 발생합니다. 그러므로, slime-mode에 대해 다음과 같이 hook을 추가해줄 필요가 있습니다. (clojure-mode일 경우에 slime-autodoc-mode를 비활성화하고 그 외의 경우에는 활성화합니다.)
(eval-after-load "slime"
  '(progn
     (add-hook
      'slime-mode-hook
      (lambda ()
        (if (eq major-mode 'clojure-mode)
            (slime-autodoc-mode 0)
          (slime-autodoc-mode 1))))
     (add-hook
      'slime-connected-hook
      (lambda ()
        (if (string=
             (slime-lisp-implementation-type)
             "Clojure")
            (setq slime-use-autodoc-mode nil)
          (setq slime-use-autodoc-mode t))))))

(eval-after-load "slime-repl"
  '(progn
     (add-hook
      'slime-repl-mode-hook
      (lambda ()
        (if (string=
             (slime-lisp-implementation-type)
             "Clojure")
            (progn (setq slime-use-autodoc-mode nil)
                   (slime-autodoc-mode 0))
          (progn (setq slime-use-autodoc-mode t)
                 (slime-autodoc-mode 1)))))))

2. Evaluation abort 상황에서 오류 발생하는 문제

SLIME REPL 상에서 일반적인 에러가 발생하면 sldb 버퍼가 뜨는데, 여기서 'Quit to the SLIME top level'을 선택하면 아래와 같은 에러 메시지를 보게 됩니다.
error in process filter: Wrong number of arguments: nil, 0
위 상황 외에도 다른 몇몇 상황에서 역시 동일한 에러 메시지를 보게 되는데, 이 문제는 저장소 상의 최신 SLIME 소스에서 swank abort 메시지 인터페이스가 변경되었기 때문에 발생하게 된 것입니다. 변경된 swank abort 메시지 인터페이스는 condition 인자를 하나 필요로 하지만, swank-clojure에선 아무런 인자 없이 abort 메시지만 전달하기 때문에 에러가 발생하는 것이죠. 이 문제를 해결하기 위해선 swank-clojure 쪽 소스를 살짝 손봐야 합니다.

[swank-clojure 폴더]/src/swank/core.clj 파일에서 아래 부분을 모두 찾아,
(:abort)
다음과 같이 수정해줍니다. (물론 이것은 공식적인 해결 방법은 아닙니다. 에러 없이 동작할 수 있도록 임시로 수정해주는 것이죠.)
(:abort ~(thread-name (current-thread)))
이 글을 작성하고 있는 시점에서 수정해야 할 부분은 총 5 곳인데, 모두 eval-for-emacs 함수 내부에 있습니다.

수정 후 다시 swank-clojure를 구동한 다음 sldb에서 확인해보면 'Quit to the SLIME top level'을 선택했을 때 REPL 상에서 정상적으로 아래와 같은 메시지를 볼 수 있습니다.
; Evaluation aborted on Swank REPL Thread.

2010년 7월 12일 월요일

Emacs 나눔로또 API & Module

아래 내용은 초기 버전에 대한 것으로 업데이트된 최신 내용은 프로젝트 위키 페이지에서 확인하실 수 있습니다. -- 2011-04-19
LINK: lotto-check-el/wiki/EmacsLottoApi



로또 이야기가 계속 이어지네요. 이 정도 정성이면 로또 1 등 내려주실 법도 한데, 5 등 한번 당첨되기도 쉽지 않으니 하늘이 무심(?)하십니다.

이번에는 Emacs에서 사용할 수 있는, 나눔로또 정보 및 당첨 여부 확인 모듈을 만들었습니다. Emacs Lisp 공부도 좀 하고 앞서 만들었던 로또 당첨 정보 Web API도 써먹어 볼 겸 만들어 본 것입니다. 그리고, 이번에 만든 것은 무려 소스까지도 공개합니다. 부끄러운 소스지만, 어쨌거나 GPL version 3를 채택해서 공개해봅니다.

공개된 소스의 저장소 URL은 다음과 같습니다.
LINK: http://bitbucket.org/kaisyu/lotto-check/
LINK: https://code.google.com/p/lotto-check-el/
LINK: https://github.com/kaisyu/lotto-check
LINK: https://gitlab.com/kaisyu/lotto-check

1. 소개 및 특징

로또 당첨 번호와 내가 구매한 로또의 당첨 여부를 Emacs에서 간편하게 확인할 수 있는 모듈입니다. 이 모듈은 다음과 같은 특징을 가지고 있습니다.

1) 인터넷을 통해 로또 정보를 수집하는 방법을 하나 이상 지원합니다.
로또 당첨 번호 정보는 인터넷을 통해 수집하게 되는데, 기본으로 @Lotto_K 계정에 게시되는 것과 동일한 정보를 사용하는 lotto.kaisyu.com 사이트의 Web API를 사용합니다. 그리고, 혹시라도 이 사이트에 문제가 생겼을 경우를 대비해 네이버, 다음, 나눔로또 공식 홈페이지 등의 대체 방법도 제공합니다.

2) Hashtable을 활용한 local cache를 유지합니다.
이로 인해 한번 가져온 로또 정보는 추가 인터넷 연결 없이 매우 빠르게 그 결과를 확인할 수 있습니다. 이 local cache는 lotto-check 모듈이 로드되거나 평가될 때 파일로부터 자동으로 읽혀져 초기화 되고, Emacs가 종료될 때 자동으로 파일에 저장됩니다.

3) 간단하게 즉시 사용할 수 있는 interactive 함수를 제공합니다.
M-x 함수명 형식으로 사용할 수 있는 함수들을 제공합니다. 로또 당첨 번호 정보를 보여주고, 사용자가 제공한 번호의 당첨 여부도 확인해주는 함수들로, 그 결과가 새로운 전용 buffer에 출력되거나 message 형태로 보여집니다. 자세한 것은 아래에 다시 소개하겠습니다.

4) 다른 모듈에서 간편하게 사용할 수 있는 API 함수를 제공합니다.
위에서 소개한 interactive 함수들과 동일한 역할을 하는 API 함수가 존재하는데, interactive 함수들과 다른 점은 반환값이 lisp object 형태로 되어 있어 재가공하거나 변환하여 사용하기 편리하다는 점입니다.


2. 설치 및 설정

1) 설치
다운로드한 소스를 load path에 추가해줍니다.
(add-to-list 'load-path "[lotto-check 모듈이 있는 경로]")
(require 'lotto-check)

2) 설정
Emacs의 Customize 기능(M-x customize)을 사용해서 Applications 그룹 아래의 Lotto 그룹으로 가면 간편하게 설정할 수 있는 UI가 제공되지만, 아래와 같이 직접 startup script 파일에 설정을 추가하는 것도 가능합니다.
;; 로또 당첨 정보를 인터넷으로부터 수집하는 함수를 지정합니다.
;; 기본값은 lotto-retrieve-numbers-from-lotto-k 함수이며,
;; 네이버, 다음, 나눔로또 공식 홈페이지, 사용자 정의 방법 등을 제공합니다.
;; 네이버: lotto-retrieve-numbers-from-naver
;; 다음: lotto-retrieve-numbers-from-daum
;; 나눔로또 공식 홈페이지: lotto-retrieve-numbers-from-645lotto
;; 사용자 정의 함수: lotto-info-retrieve-func-custom
;; * 사용자 정의 함수 방식을 사용할 경우 lotto-info-retrieve-func-custom 변수에
;;   사용자 정의 함수 이름을 지정합니다.
;;   예) (setq lotto-info-retrieve-func-custom 'my-retrieve-func-1)
(setq lotto-info-retrieve-func 'lotto-retrieve-numbers-from-lotto-k)
;; 로또 당첨 정보를 저장할 파일을 지정합니다.
(setq lotto-database-file "~/.lotto-database")
;; interactive function 실행 시 결과를 별도의 buffer에 보여주도록 설정합니다.
(setq lotto-use-buffer-for-message t)


3. 사용

1) interactive 함수 사용하기
  • M-x lotto-retrieve-numbers-i특정 회차의 당첨 번호 정보를 보여줍니다.
    실행하면 mini-buffer에 game no: 프롬프트가 뜨는데, 가져올 로또 회차 번호를 입력합니다.
    예) game no: 397
  • M-x lotto-check-numbers-list-i특정 회차에 사용자가 지정한 번호의 당첨 여부를 확인하여 결과를 보여줍니다.
    실행하면 minu-buffer에 game no: 프롬프트와 your numbers: 프롬프트가 뜨는데, 각각 비교할 로또 회차 번호와 확인할 번호 list를 입력합니다.
    확인할 번호 list 형식은 일반적인 lisp object와 동일합니다.
    예) your numbers: ((1 14 16 25 33 42) (2 10 17 26 34 43))
  • M-x lotto-save-db-to-file-ilocal cache에 저장된 로또 당첨 번호 정보를 파일에 저장합니다. 사용자가 수동으로 저장하지 않아도 Emacs 종료 시 자동으로 저장됩니다.
  • M-x lotto-load-db-to-file-i파일에 저장된 로또 당첨 번호 정보를 불러옵니다. 사용자가 수동으로 불러오지 않아도 lotto-check 모듈을 불러올 때 자동으로 local cache도 함께 불러옵니다.
[lotto-check 모듈 실행 결과]

2) API 함수 사용하기
(lotto-retrieve-numbers GNO)

로또 당첨 번호를 반환합니다.
GNO: 가져올 로또 회차 번호
반환값: ((당첨_번호_list) 보너스_번호)

예) (lotto-retrieve-numbers 395)
=> ((11 15 20 26 31 35) 7)
(lotto-check-numbers-list GNO MY-NUM-LIST)

주어진 번호의 당첨 여부를 반환합니다.
GNO: 비교할 로또 회차 번호
MY-NUM-LIST: 확인할 번호들의 list
반환값: ((등급 (일치한_번호_list)) ...)

예) (lotto-check-numbers-list 395 '((1 2 3 4 5 6) (11 15 20 28 32 36)))
=> ((0 nil) (5 (11 15 20)))

2010년 5월 29일 토요일

Emacs에서 Twitter 사용하기

Emacs에서 사용할 수 있는 Twitter client는 몇 가지가 있습니다. 그 중에서도 twittering-mode가 가장 잘 구현되었다고 생각되는데, Windows 환경에서 제대로 설정하고 사용하기까지 약간의 문제가 있었던 지라 글로 남겨 봅니다.

1. twittering-mode 소스 내려받기
먼저, 소스를 받아옵니다. git를 사용할 수 있다면 아래와 같이 repository로부터 직접 clone 하는 것이 가장 좋습니다.
git clone git://github.com/hayamiz/twittering-mode.git
그렇지 않다면, github 사이트에서 최신 소스를 내려 받은 후 압축을 풉니다.
Linkhttp://github.com/hayamiz/twittering-mode/archives/master

2. twittering-mode 설치하기
.emacs와 같은 설정 파일에 아래 내용을 추가하면 바로 사용할 수 있다고 알려져(?) 있습니다. (그러나, Windows 환경에서는 조금 더 손을 봐야 합니다.)
(load "~/.emacs.d/twittering-mode/twittering-mode.el") ;; twittering-mode 소스 경로
(require 'twittering-mode)
(setq twittering-username "사용자ID") ;; Twitter ID
(setq twittering-password nil) ;; 패스워드를 설정하지 않으면 prompt를 통해 물어보기 때문에 설정하지 않아도 상관 없음
그리고, Emacs 22 이상 버전을 사용하는 경우에는 소스 경로에서 아래의 두 폴더를 삭제해주는 것이 좋습니다. (twittering-mode 소스를 site-lisp처럼 sub-directory를 자동으로 검색하는 곳에 넣으면 emacs 원래 소스와 충돌을 일으킵니다.)
emacs21
url-emacs21

3. OAuth 인증 방식 적용하기
twittering-mode는 기본적으로 basic authentication 방식을 사용합니다. 그러나, Twitter API에서 2010년 6월부터 더 이상 이 방식을 제공하지 않기로 했기 때문에 OAuth 방식을 사용하도록 설정해줄 필요가 있습니다.
2010년 6월 5일자로 twittering-mode 1.0 버전이 릴리즈 되면서 OAuth 방식이 기본으로 사용되기 시작했습니다. 그리고, 개발자가 Twitter OAuth client에 등록한 twmode의 Consumer Key/Secret 또한 포함하고 있기 때문에 별도로 OAuth client를 등록할 필요가 없어졌습니다. 그러므로, 아래 내용 중 1) 번 내용은 더 이상 필요하지 않습니다. 바로 2) 번으로 진행하면 됩니다. (2010.06.07)

1) Twitter에 OAuth client 등록하기 (1.0 버전 이후 불필요)
아래 그림과 같이 OAuth client 등록 페이지로 가서 나만의 twittering-mode client를 등록합니다. Application NameOrganization에는 원하는 이름 아무 것이나 사용해도 되지만, 'twitter'라는 단어가 들어갈 수 없다고 나오더군요. 그리고, Application Name은 이미 다른 사람이 등록한 것과 동일할 수 없기 때문에 이미 등록된 것이라고 나올 경우 적절히 재조정이 필요합니다.

[새로운 OAuth client 등록 화면]

등록이 완료되면 아래 그림과 같이 등록된 client에 대한 정보를 보여주는데, 여기서 Consumer keyConsumer Secret 값을 복사해둡니다.
[등록된 twittering-mode client 정보 확인]

2) twittering-mode에서 OAuth 방식 사용하도록 설정하기
설정 파일에 아래 내용을 더 추가합니다. 이것으로 기본적인 사용이 가능하게 됩니다. 그러나, 매번 twittering-mode 실행할 때마다 새로 인증 과정을 거치기 때문에 조금 불편합니다.
twittering-mode 1.0 버전 이후부터는 별도로 Consumer Key와 Secret을 지정해줄 필요가 없으므로 twittering-oauth-invoke-browser 정도만 설정해주면 됩니다. (2010.06.07)
(setq twittering-auth-method 'oauth)
(setq twittering-oauth-use-ssl t)
(setq twittering-oauth-invoke-browser t)
(setq twittering-oauth-consumer-key "Consumer key 입력")
(setq twittering-oauth-consumer-secret "Consumer secret 입력")
어쨌거나 여기까지 추가하고 M-x twit 이라고 실행하면 아래와 같이 access token 발급을 위한 승인 및 PIN 확인 절차를 거치게 되는데, 브라우저에 나타난 PIN 정보를 Emacs에 입력해주면 최종적으로 Timeline 내용이 보이게 됩니다. 혹시 브라우저가 자동으로 뜨지 않을 경우 수동으로 브라우저를 실행하고 Emacs 화면에 나온 주소를 입력해주면 됩니다.
[M-x twit 실행]
[승인]
[PIN 발급]
[Timeline이 뜬다!]

3) 한번 발급된 access token 계속 사용하기
Twitter 정책 상 한번 발급된 access token은 사용자가 명시적으로 Twitter 홈페이지 Settings -> Connections 페이지에서 revoke 처리하기 전까지는 계속 저장된 채로 유지됩니다. 그리고, 매번 로그인할 때마다 PIN 입력하고 새로운 access token을 발급받는 것은 꽤 번거로운 일이지요. 그래서, 한번 발급된 access token을 계속 사용하도록 설정을 해두면 여러 모로 편리합니다.
[Access token 발급 후 Connections 페이지에 등록된 모습]
일단, access token이 성공적으로 발급되면 twittering-oauth-access-token-alist 변수에 그 내용이 저장됩니다. 그리고, twittering-account-authorization 변수값이 'authorized 로 변경됩니다. 그러니까, *scratch* 버퍼나 ielm 상에서 twittering-oauth-access-token-alist 변수값을 가져온 후 아래와 같이 그대로 설정 파일에 추가해주면 됩니다.
(setq twittering-oauth-access-token-alist '(PIN 입력 후 생성된 access token 값 입력))
(setq twittering-account-authorization 'authorized)
[ielm 상에서 twittering-oauth-access-token-alist 변수값 확인]
그러면 이제부터 더 이상 PIN 입력하는 과정 없이 바로 Timeline이 뜨게 됩니다.

4) 기타 설정
지금까지 추가한 설정 내용 외에 편의를 위해 추가해주면 좋은 내용들이 조금 더 있습니다.
(setq twittering-use-native-retweet t) ;; Twitter에서 제공하는 Retweet 방식 사용
(twittering-icon-mode t) ;; 기본으로 트윗 항목 앞에 프로필 이미지를 표시
(setq twittering-timer-interval 180) ;; 각 timeline을 새로 고치는 주기(단위는 초)

4. Windows 환경에서 sha1sum 관련 문제
Emacs lisp의 sha1 함수는 내부적으로 처리할 수 있는 문자열의 길이에 제한(500 자)을 두고 있습니다. 그리고, 그 길이 제한을 넘게 되면 외부의 sha1sum 프로그램을 사용해 hash 값을 구해오는 방식으로 동작합니다. 그런데, Windows 환경에서는 sha1sum 같은 유틸리티가 기본으로 제공되지 않습니다. 그래서, 한글이 포함된 글을 posting 시도할 경우 url encoding을 거치면서 hash 처리해야 할 문자열 길이가 몇 배로 길어지기 때문에 에러를 만나게 될 수도 있습니다.
이 문제를 해결하기 위해서는 Windows 용으로 빌드된 sha1sum.exe 파일이 필요한데, Cygwin이나 MinGW32가 설치되어 있다면 그 안에 포함된 것을 사용하면 되고, 그렇지 않다면 다음 주소에서 받아서 사용하면 됩니다.
Downloadhttp://www.nfllab.com/sums/sums611.zip
출처: http://blog.nfllab.com/archives/152-Win32-native-md5sum,-sha1sum,-sha256sum-etc..html
제 경우, Cygwin이 설치되어 있기 때문에 Cygwin에 포함된 파일로 경로를 설정했습니다.
(setq sha1-program "c:/cygwin/bin/sha1sum.exe") ;; sha1sum.exe 파일의 절대 경로를 지정

5. 단축키
이제 설정도 다 끝나고 잘 사용하는 일만 남았네요. 잘 사용하려면 단축키를 알아야겠죠. 주로 사용하게 되는 단축키는 아래와 같습니다.
C-c C-r   replies timeline 보기
C-c C-u   user timeline 보기
C-c C-d   direct messages timeline 보기
L         list timeline 보기
C-c C-q   Twitter의 search 결과 보기
g         현재 timeline 내용을 새로 고침
C-c C-s   트윗 작성
u         트윗 작성
C-c D     트윗 삭제
C-c C-m   retweet
d         direct message 작성
C-m       상황에 따라 적절한 행동(링크 열기, reply 작성하기 등)
<enter>   상황에 따라 적절한 행동(링크 열기, reply 작성하기 등)
j         다음 트윗 항목으로 이동
k         이전 트윗 항목으로 이동
q         현재 timeline 닫기
i         트윗 항목 앞에 프로필 이미지 보이기 모드 토글
더 상세한 내용은 다음과 같습니다만, 한번 쯤 눌러보면 대강 짐작할 수 있는 것들이라 번역은 생략합니다. ;)
C-c C-f      friends timeline
C-c C-r      replies timeline
C-c C-g      public timeline
C-c C-u      user timeline
C-c C-d      direct messages timeline
C-c C-s      update status interactive
C-c C-e      erase old statuses
C-c C-m      retweet
C-c C-h      set-current-hashtag
C-m          reply or open link
C-c C-l      update lambda
<mouse-1>    click
C-c C-v      view user page
C-c D        delete status
a            toggle activate buffer
g            refresh current timeline
u            update status interactive
d            direct message
v            other user timeline
V            visit timeline
L            other user list interactive
f            switch to next timeline
b            switch to previous timeline
j            goto next status
k            goto previous status
l            forward char
h            backward char
0            beginning of line
^            beginning of line text
$            end of line
n            goto next status of user
p            goto previous status of user
C-i          goto next thing
M-C-i        goto previous thing
<backtab>    goto previous thing
<backspace>  scroll down
M-v          scroll down
SPC          scroll up
C-v          scroll up
G            end of buffer
H            goto first status
i            icon mode
r            toggle show replied statuses
s            scroll mode
t            toggle proxy
C-c C-p      toggle proxy
q            kill buffer
C-c C-q      search