저번 포스트 에서 Emacs 버젼을 24 로 업그레이드 한 후에 가장 큰 문제가 생겼습니다. ClojureCommon Lisp 개발환경이 동시에 안되는 문제가 발생했습니다. 

몇번의 노력끝에 결국 Emacs 에서도 편하게 설치하는 쪽을 받아들이게 됐습니다. 기존에는 "이맥스 유저는 이래야 해!!" 라는 말도 안되는 자존심으로 수동으로 이거 저거 설치하는 쪽이였으나 이제 대세를 받아들이기로 했습니다. 

클로져 (Clojure) 개발 환경 설정 


예전 포스트 에서 쉽게 설치하는 방법을 소개한 적이 있었습니다.  그러나 swank-js 를 만들었던 당사자가 더 훌륭한 솔루션이 나왔다고 GG 를 쳐버렸습니다. -0- (당신을 믿고 포스팅을 했었다고!!! ㅜ.ㅜ ) 

nRepl 을 설치해줍니다.  

nrepl.el is an Emacs client for nREPL, the Clojure networked REPL server. It's a great alternative to the now deprecated combination of SLIME + swank-clojure.


설치법은 간단합니다. Emacs 24 버젼부터는 Package 관리가 기본으로 포함되어 버렸습니다. 대세는 게을러지기 아니겠습니까? 
.emacs 파일에 다음과 같은 내용을 추가합니다. 


(require 'package)
(add-to-list 'package-archives
    '("marmalade" . "http://marmalade-repo.org/packages/"))
(package-initialize)


그리고 재 시작후 , M-x list-packages 로 출력해서 nrepl 을 찾아서 설치해 주거나 , 설명 페이지에서 추천하는 대로 

M-x package-install [RET] nrepl [RET]



로 설치해주시면 됩니다. 추가로 편리하게 사용하기 위해서 세팅 몇가지만 해주시면 됩니다. 

(add-hook 'nrepl-mode-hook
     (defun clojure-mode-slime-font-lock ()
         (let (font-lock-mode)
             (clojure-mode-font-lock-setup))))


이제 클로져 관련 파일을 열고나서 M-x nrepl-jack-in  를 입력하시면 익숙한 REPL 버퍼가 보일 것입니다. (속도도 Swank-js 보다 빨라졌습니다)


Common Lisp 개발 환경 설정 (SLIME 설정)
 
이제 이것 설치도 쉽게 하는 방법이 있습니다. SBCL 은 이미 설치되어 있다고 가정합니다. (참조사이트 : http://www.mohiji.org/2011/01/modern-common-lisp-on-linux/

일단 quicklisp 파일을 다운 받아야 합니다. http://beta.quicklisp.org/quicklisp.lisp 에서 받아줍니다. 적당한 곳에 옮겨주시고요. 

$ sbcl


sbcl 을 실행시켜줍니다.

user> (load "/path/to/quicklisp.lisp")


sbcl 상에서 위와 같이 quicklisp 파일이 받아진 것을 읽어들입니다.  

user> (quicklisp-quickstart:install)
user> (ql:add-to-init-file)
user> (ql:quickload "quicklisp-slime-helper") 


그리고 위와 같이 연속으로 실행시켜줍니다.  이러면 자연스럽게 SLIME 까지 설치가 됩니다. 이제 Emacs 에게 위치를 알려주는 일만 해주면 됩니다. 

(setq inferior-lisp-program "sbcl")
(load (expand-file-name "~/quicklisp/slime-helper.el"))

이제 M-x slime 을 입력하면 자연스럽게 SLIME REPL 이 뜨게 됩니다.  

May The Source Be With You !!!
 
Slime 이 무엇인지 Emacs 를 사용하시는 분들은 대충 아시리라 봅니다. REPL (Read Eval Print Loop)형태를 지원하는 언어에 대한 최적의 개발 환경이라고 보시면 됩니다. (물론 부정하는 분들도 많습니다) 

저는 Common Lisp , Clojure 등을 Slime 을 이용해서 개발환경을 구축해 두었습니다. 이번에 프로젝트를 Node.js 로 진행하게 되어서 (Node.js 또한 REPL 을 지원합니다) Emacs + Slime 으로 환경을 구축할려고 알아보았습니다. 

역시나 괜찮은 솔루션이 하나 등장하더군요. https://github.com/swank-js/swank-js

Slime 은 Swank 라는 방식으로 각기 언어별로 소켓 접속이 가능한 방식으로 서버를 띄우면 Emacs 에서 slime-connect 를 이용하여 서버에 붙어서 정보를 가져오고 전달하는 방식으로 구동됩니다. 이러한 점 때문에 원격에 swank 서버를 띄워도 마치 local 에 붙는 것처럼 붙어서 동작할 수가 있습니다. 

설치하는 방법 (OSX - Mountain Lion 기준 입니다)

1. Node.JS 와 npm 을 설치합니다. (Ubuntu 설치는 예전 포스트 참조 )

     

 $ sudo port install nodejs 
 $ sudo port install npm 


2. swank-js 설치 합니다. 
       

 $ sudo npm install -g swank-js 


swank-js 는 node.js 로 만들어진 swank 모듈입니다. 위에서 잠깐 언급한 slime 이 접속할 수 있는 서버를 띄워주는 모듈입니다. npm install 시에 -g 옵션을 주면 전역으로 설치하라는  명령입니다. 이제 어디서나 swank-js 명령으로 swank 서버를 띄워줄 수가 있습니다. 

3. SLIME 을 설치해야 할 시간입니다.

$ cd ~/.emacs.d/
$ cvs -d :pserver:anonymous:anonymous@common-lisp.net:/project/slime/cvsroot co slime


위와 같은 방식으로 다운 받는 것이 속도가 가장 빠르더군요. git 사이트는 생각보다 많이 느립니다. 


4. js2-mode 를 받아야 합니다. 

http://code.google.com/p/js2-mode/ 에서 js2-20090723b.el 을 다운 받아서 js2-mode.el 로 이름 변경해서 적당한 곳 (저는  ~/.emacs.d/ 밑에다 가져다 뒀습니다) 에 옮겨두고 byte-compile-file 을 해줍니다. 

Emacs 를 실행하고 
       

M-x byte-compile-file 


로 js2-mode.el 을 지정하면 됩니다. 이때 꼭 명심해야 할 사항은 절대 js2-mode.el 을 버퍼에 올려둔 상태로 컴파일 진행하면 안된다는 것입니다. (올려둔 상태로 컴파일 하면 에러가 발생함)

.emacs 파일을 열고 다음과 같은 내용을 추가해 줍니다. 

       (autoload 'js2-mode "js2-mode" nil t)
       (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))



5. 적당한 곳에 swank-js 프로젝트를 다운 받습니다. 
       
     

 $ cd ~/work
 $ git clone git://github.com/swank-js/swank-js.git



6. slime-js.el 의 심볼릭-링크 를 만들어 줍니다. 

$ cd ~/.emacs.d/slime/contrib
$ ln -s ~/work/swank-js/slime-js.el slime-js.el
$ cd ~/.emacs.d/
$ ln -s ~/work/swank-js/slime-js.el slime-js.el


7. .emacs 에 slime-js.el 을 require 해주고, 몇가지 추가 설정을 더 해줍니다. 

       (require 'slime-js)
       
       (add-hook 'js2-mode-hook
          (lambda ()
            (slime-js-minor-mode 1)))
       
       (add-hook 'css-mode-hook
          (lambda ()
            (define-key css-mode-map "\M-\C-x" 'slime-js-refresh-css)
            (define-key css-mode-map "\C-c\C-r" 'slime-js-embed-css)))



8. Emacs 를 다시 띄우고 Terminal.app 를 실행하시고 node.js 프로젝트 만들려고 마음 먹은 곳 위치에서 

$ cd ~/work
$ mkdir node-projects
$ cd node-projects
$ swank-js


이렇게 해주면 swank-js 서버가 구동됩니다. swank-js 명령만 쳐도 되는 것은 'sudo npm install -g swank-js' 해 줬기 때문입니다. 

Emacs 에서 

M-x slime-connect


해 주고 기본적으로 127.0.0.1 과 4005 번 포트로 접속 하는 것을 선택해 주시면 됩니다. (Enter x 2 번)

추가로 어떤 기능이 되는지는 https://github.com/swank-js/swank-js 사이트 참조하시면 됩니다.  
저번 포스트 에서 Clojure 와 Slime 을 연결해봤습니다. 그런데 REPL 에서 색이 안 이쁘더군요. 간단하게 색을 집어넣는 방법을 설명하겠습니다.

.emacs 파일을 열어서 맨 아래쪽에 다음 과 같은 내용을 추가해 줍니다.

(add-hook 'slime-repl-mode-hook (defun clojure-mode-slime-font-lock () (let (font-lock-mode) (clojure-mode-font-lock-setup))))

끝!!


드디어 올것이 오고 말았군요.
clojure 를 emacs 에서 slime 과 연결시키는 방법에 관한 것입니다. 물론 제가 쓰고 있는 osx snow leopard 에서 말이죠. 기존에 제가 쓰고 있던 환경은 emacs 에 slime 을 clbuild 버젼으로 연결시켜서 쓰고 있었습니다. 나름 편해서 애용하고 있었는데 이번에 clojure 를 연결 시켜야 해서 살짝 골치가 아프군요.

참고로 clbuild 를 쓰게 되면 slime 관련 설정 부분입니다. (.emacs 에 있음)

(setq load-path (cons "/Users/crazia/work/clbuild/source/slime" load-path))
(setq load-path (cons "/Users/crazia/work/clbuild/source/slime/contrib" load-path))
(setq slime-backend "/Users/crazia/work/clbuild/.swank-loader.lisp")
(setq inhibit-splash-screen t)
(load "/Users/crazia/work/clbuild/source/slime/slime")
(setq inferior-lisp-program "/Users/crazia/work/clbuild/clbuild lisp")
(setq slime-use-autodoc-mode nil)
(slime-setup '(slime-fancy slime-tramp slime-asdf))
(slime-require :swank-listener-hooks)

복잡하지요? 그래서 자동화 방법을 애용하기로 하겠습니다.

ELPA 라는 것이 있습니다. Emacs Lisp Package Archive 의 약자입니다. 말 그대로 Emacs 에서 쓰기 편하게
여러가지들을 제공하는 패키지 시스템이라고 할 수 있습니다.

http://tromey.com/elpa/install.html  여기에서 제공하는 방식으로 하면 인터페이스 버퍼가 뜹니다.

 
(let ((buffer (url-retrieve-synchronously
           "http://tromey.com/elpa/package-install.el")))
  (save-excursion
    (set-buffer buffer)
    (goto-char (point-min))
    (re-search-forward "^$" nil 'move)
    (eval-region (point) (point-max))
    (kill-buffer (current-buffer))))


이 내용을 *scratch* 버퍼에 가져다 두고 C-j 를 입력하면 된다고 쓰여져 있는데, AquaEmacs 의
경우에는 *scratch* 버퍼가 lisp-interaction-mode 로 설정되어 있지 않습니다.  따라서

M-x lisp-interaction-mode


바꾸시고 위의 내용을 복사해서 넣고 C-j 를 입력하세요. 반응이 만약 없다면 C-xC-e 로도 되는것 같더군요. 어찌 됐건 위의 코드를 실행하면 명령을 하나 쓸수가 있습니다.
M-x package-list-packages


를 입력하면 조금 시간이 걸리지만 설치할 수 있는 목록 리스트가 주르륵 나옵니다. 그중에서 swank-clojure 를 찾아서 'i' 를 눌러서 체크를 하시고 'x' 를 눌러서 설치가 됩니다.
그러면 .emacs 파일 아래쪽에 다음과 같은 코드가 자동으로 추가됩니다.

 (when
     (load
      (expand-file-name "~/.emacs.d/elpa/package.el"))
   (package-initialize))


package-initialize 가 실행된다면 기존에 설정되어 있는 slime 설정하고 충돌이 일어납니다. 멋지게 해결할 수 있는 방법이 없으니.. 귀찮지만 clbuild 로 웹 개발할 때와 클로져 공부 할 때를 구분시키는 방법으로 잠시동안 머물러야 겠습니다. 위에 있는 코드를 삭제하고 맨 위에 있는 clbuild 용 slime 설정 코드도 삭제해 줍니다.

(defun select-lisp-program (n)
  (interactive "n1:clbuild 2:clojure : (enter number)  ")
  (cond ((= n 1) (progn
                   (setq load-path (cons "/Users/crazia/work/clbuild/source/slime" load-path))
                   (setq load-path (cons "/Users/crazia/work/clbuild/source/slime/contrib" load-path))
                   (setq slime-backend "/Users/crazia/work/clbuild/.swank-loader.lisp")
                   (setq inhibit-splash-screen t)
                   (load "/Users/crazia/work/clbuild/source/slime/slime")
                   (setq inferior-lisp-program "/Users/crazia/work/clbuild/clbuild lisp")
                   ;;(setq inferior-lisp-program "clj")
                   (setq slime-use-autodoc-mode nil)
                   (slime-setup '(slime-fancy slime-tramp slime-asdf))
                   (slime-require :swank-listener-hooks)
                   (add-hook 'lisp-mode-hook (lambda () (slime-mode t)))
                   (add-hook 'slime-repl-mode-hook (lambda () (slime-mode t)))
                   (add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode t)))

                   (define-key slime-mode-map (kbd "C-,") 'forward-sexp)
                   (define-key slime-mode-map (kbd "C-.") 'backward-sexp)
                   (define-key slime-mode-map (kbd "TAB") 'slime-indent-and-complete-symbol)
                   (define-key slime-mode-map (kbd "RET") 'paredit-newline)
                   (define-key slime-mode-map (kbd "<return>") 'paredit-newline)

                   (setq slime-complete-symbol-function 'slime-fuzzy-complete-symbol)
                   ))
        ((= n 2)
         (when
             (load (expand-file-name "~/.emacs.d/elpa/package.el"))
           (package-initialize))))
  )


그리고 두가지를 한 함수로 합쳐서 제공합니다. 위의 내용을 .emacs 에 추가하시면 다음 emacs 를 실행시키고 상황에 따라서

M-x select-lisp-program


명령으로 1 (clbuild) 나 2 (clojure) 로 개발 모드를 바꿔가면서 사용하실 수 있습니다. 물론 이렇게 귀찮게 안하고 lisp 을 clbuild 가 아닌 독자적으로 설치해서 적용하면 되지만 귀찮은걸 어쩌겠습니까 -0- clbuild 가 너무 편한걸..




드디어 저를 괴롭히던 가장 큰 문제가 해결 됐습니다. -0-
Weblocks 를 쓰면서 대체 이걸 어떻게 하는 걸까? 하고 고민 했던 것이 /pub/images 말고 딴곳에 있는 image 파일 access 하는 방법이였습니다.

예를 들면 /pub/images/photos/bassist.jpg 를 화면에 출력하고 싶을 때, 대체 어떻게 하는지 모르는 것이였습니다. 워낙 쉬운거라 Example 이나 Tutorial 에 없는 것이겠지요? 개발되어지고 있는 소스 자체를 뒤져서 알아냈습니다. 핵심은

make-webapp-public-file-uri 라는 이름의 함수였습니다.

(defun make-photo-page ()
  (make-widget
   (lambda ()
     (with-html
       (:p :id "index" "첫화면 이라능..")
       (:img :src (make-webapp-public-file-uri "images/photos/bassist.jpg") :alt "This site has valid XHTML 1.1.")))))


이런식으로 직접적으로 표현해 주는 방식이였습니다. 소스를 더 뒤져봐야 알겠지만 이런 간단한 내용을 찾기 위해서 한참을 고생한 것을 생각하면 ㅜ.ㅜ

암튼 해결해서 기쁘군요 ㅎㅎ


역시나 친절하게 상단 헬프에서 알려주는 것을 한참 찾았네요. -ㅅ- 이런건 구글신이 잘 안 알려주는것 같습니다.

'C-q' 입력하시고 ( 입력하시면 ( ) <-- 이렇게 쌍으로 생기지 않고 문자 그대로 ( 로만 입력됩니다. 동영상 보다가 생각이 안나서 한참을 찾았네요.


clbuild 로 lisp 과 slime 을 연동해서 사용하고 있습니다. 어차피 프로젝트 로딩할때 slime 을 거치지 않는 적이 없으니 개발시 편하게 하기 위해서 slime 로더 부분에 프로젝트 설정 부분을 추가 하려고 합니다.

(defun project-setup ()
(mapcar #'(lambda (path)
(push path asdf:*central-registry*))
'(
#p"/home/bc/proj/weblocks-dev-aggieben/"
#p"/home/bc/proj/simple-blog/"
)))
(project-setup)


위와 같은 내용을 clbuild 가 설치되어 있는 디렉토리에 있는 .swank-loader.lisp 에 추가해 줍니다.  다음부터 slime 로딩시 자동으로 프로젝트 파일들에 대한 패스가 추가 됩니다.




+ Recent posts