Emacs Document

From 흡혈양파의 인터넷工房
Jump to: navigation, search

Emacs = Editor MACros

Test & Usage

mediawiki.el
설명 Mediawiki interface and markup mode
Author Jerry et al
Maintainer Mark A. Hershberger
소스 https://code.launchpad.net/~hexmode/mediawiki-el/trunk
Part of Emacs no


Mediawiki.el 코드는 이맥스에서 미디어위키 페이지를 fetch/submit 할 수 있도록 해준다.

(add-to-list 'load-path "~/.emacs.d/")
(require 'mediawiki)
(setq mediawiki-site-alist
      (append '(("Onionmixer-WS" "http://workspace.onionmixer.net/mediawiki/"
                 "username" "password" "Emacs Document")
                ("EXAMPLE" "http://en.wikipedia.org/w/"
                 "username" "password" "Main Page"))))
(setq mediawiki-site-default "Onionmixer-WS")

OSX, Cocoa Emacs 24 버전 사용자의 경우 S-SPC가 먹히질 않아, 입력기 전환은 C-\키로 할 것이다. 그런데 mediawiki.el에는 C-\에 별도의 바인딩을 설정해두어서, 입력기 전환에 불편을 겪을 것이다. 따라서 다음 코드도 추가해둔다.

(setq mediawiki-mode-hook (lambda ()
                            (local-unset-key (kbd "C-\\"))
                            (local-set-key (kbd "C-\\") 'toggle-input-method)))

Emacs Frame

Emacs Help System

  • C-h f : describe-function, 함수에 대한 정보를 보여준다. built-in function은 C 코드에서 구현된 함수를 가리킨다.

이맥스 함수중에는 interactive function이 있는데, interactive function은 M-x로 호출할 수 있다.

  • C-h v : describe-variable
  • C-h k : describe-key, 입력한 키가 어떤 함수에 binding 되어있는지 확인할 수 있다.
  • C-h b : describe-bindings, 현재 버퍼의 적용된 key map을 확인할 수 있다.

Emacs Lisp Evaluation

LISP의 list evaluation은 佐에서 佑 방향으로 순차적으로 진행한다. 모든 list 데이터는 cons cell 연결의 추상적인 표현일 뿐이다. 즉 LISP은 cons cell로 이루어져 있다.

+---+---+
|CAR|CDR|
+---+---+
    ^
    +----cons cell

다음 리스트 데이터 (a b c d)의 cons cell 구조를 밝혀 나타내면 다음과 같다.

(cons 'a                       ;; +---+---+  +---+---+  +---+---+  +---+-----+
      (cons 'b                 ;; |   |   |  |   |   |  |   |   |  |   |     |
            (cons 'c           ;; | a | *--->| b | *--->| c | *--->| d | nil |
                  (cons 'd     ;; |   |   |  |   |   |  |   |   |  |   |     |
                        ())))) ;; +---+---+  +---+---+  +---+---+  +---+-----+

Lisp의 expression은 한가지 타입밖에 없다--function call(함수호출).

Emacs Lisp Interaction Mode

새로운 버퍼를 생성하여 M-x lisp-interaction-mode으로 모드를 바꾸면, 해당 버퍼에서 interactive elisp coding이 가능하다. 별 다른 설정을 하지 않았다면, 이맥스가 초기 구동될 때 생성하는 *scratch* 버퍼의 모드가 lisp-interaction-mode일 것이다. C-x b *scratch*로 버퍼를 이동하여 간단한 lisp expression를 eval 해보자.

(+ 1 2 3 4)

위 코드를 버퍼에 입력해두고 s-exp의 끝 즉, 닫는 괄호의 바로 다음에 커서를 두고 C-j를 입력하면, 하나의 s-exp가 eval되고 그 결과를 return한다. Expression에서 호출된 함수가 return한 result를 value of expression이라 한다.

(+ 1 2 3 4)
10

참고로 Lisp 코드를 다룰 때, paredit-mode라는 minor-mode를 사용하고 있다면 C-jparedit-newline이라는 엉뚱한 명령에 바인딩 되어 있을 것이다. C-j가 원래의 eval-print-last-sexp에 바인딩 되도록 하려면 다음 코드를 eval한다.

(define-key paredit-mode-map [(10)] nil)

Buffer 혹은 region에 대한 evaluation은 각각 eval-buffer, eval-region 함수를 사용하면 된다.

Inferior Emacs Lisp Mode

M-x ielm를 실행하면 elisp code를 프롬프트 환경에서 interpreting 할 수 있다. 한번에 하나의 s-exp만 eval 할 수 있다.

Buffer-Local Emacs Lisp Evaluation

M-: (sexp) buffer-local elisp interpreting interface

Pattern Matching

정규식 구현에서, 괄호 ()는 보통 패턴 캡처를 지시하도록 한다. 하지만 이맥스의 정규식 규칙에서는 ()는 literal character와 match한다. 따라서 이맥스에서 패턴 캡처를 하려면 괄호를 escape한 \(pattern\)식을 사용한다. 식을 literal character로 \(pattern\) 작성한다는 의미가 아님에 주의하라. 즉, elisp 코드 상에서 패턴 캡처 식의 표현은 verbatim code "\\(pattern\\)"로 해야한다. 이 내용을 철학적인 이야기로 추상화를 해본다면, "우리가 코드를 작성하는 것은 사실 메타-프로그래밍이고, 기계(여기서는 Emacs)와의 interaction이 프로그래밍이다."

일반적으로 패턴 캡처는 greedy(maximum match)하다.

다음은 이맥스의 정규식을 정리한 표이다.

Pattern Expression Match
. any single character except a newline
* previous pattern 0 or more times
+ previous pattern 1 or more times
? previous pattern 0 or 1 time
^($) start(end) of line
\c 패턴을 의미하는 character(위에 나열한) c를 escape한다.
\<(\>) start(end) of word
\`(\') start(end) of buffer
\b(\B) (not)at word bread

*나, +는 패턴의 반복을 지시하는 강력한 식이지만, 반복의 의미를 좀 더 explicit 하려면 \{n,m\}식을 사용한다. 패턴 캡처 식과 같은 이유로 {}는 literal character와 match하기 때문에 escaped brace를 사용하는 것이다. nm에는 각각 최소, 최대, 반복 횟수(digit)를 쓴다. n=m이라면 \{n\}으로 쓸 수 있다.

*?, +?, ??는 non-greedy 패턴 식을 작성할 때 사용한다. 이는 이후에 예제를 통해 그 의미를 분명히 이해할 수 있다.

.은 거의 모든 문자, 하나와 match하는데, 이 경우 역시 match되는 문자를 explicit 하려면 []식을 사용한다. 즉 [a-z]라고 하면, 식은 오직 하나의 문자를 지시하되, [알파벳 소문자 a부터 z까지 문자]하고만 match한다. -[]안에서는 range를 지시하는 것으로 의미가 바뀜에 주의하자. 앞서와는 달리 explicit set []은 literal character와 match하지 않는다. 따라서 문자 []와 매치되는 식은 \[\]가 될 것이다.

Elisp 코드에서만 사용 가능한 표현식도 있다. "코드에서만 사용하는 식"이라는 설명이 붙는다면 literal하게 사용하라는 뜻이다.

Pattern Expression Match
\t tab
\n newline


연습

  1. 다음은 미디어위키 extension GeSHi code이다.
<syntaxhighlight lang="lisp">
(defun silly-loop (n)
       "Return the time, in seconds, to run N iterations of a loop."
       (let ((t1 (float-time)))
         (while (> (setq n (1- n)) 0))
         (- (float-time) t1)))
silly-loop
</syntaxhighlight>

<syntaxhighlight lang="lisp">
(silly-loop 50000000)
10.235304117202759
</syntaxhighlight>

<syntaxhighlight lang="lisp">
(byte-compile 'silly-loop)
#[Compiled code not shown]
</syntaxhighlight>

<syntaxhighlight lang="lisp">
(silly-loop 50000000)
3.705854892730713
</syntaxhighlight>

syntaxhighlight 태그로 wrap된 code를 TeX verbatim 환경으로 감싸보는 연습을 해본다. 먼저 query-replace 명령을 두 번 사용하는 방법이 있겠다. 즉

M-% <syntaxhighlight lang="lisp"> RET \begin{verbatim} RET

한 번, \end{verbatim} 한 번. 실제 작업 과정에서는 이와 같은 문제에 부딫히면, 대게 이런식의 방법으로 문제를 해결한다. 작업과정에서 중요한 미덕은 작업시간 단축이므로, 뭐든 빨리 할 수 있는 방법을 택하면 된다. 하지만 여기서는 연습이 목적이므로 패턴 캡처식을 써서 한번의 query-replace-regexp 명령으로 문제를 해결해보자. 아마 정규식을 경험해보지 못한 사람은 다음 패턴 캡처 식을 생각하는 것이 버거웠을 것이다. 참고로 [:ascii:]는 ascii 문자셋을 의미한다. 즉 [:ascii:]=^@-^?이다. 또한 ^J는 line feed 문자이며, 이맥스에서는 이러한 caret notation ascii code를 C-q를 prefix로 C-q C-j같이 입력한다.

<.+>^J\([[:ascii:]]+\)^J</.+>

하지만 이 식도 완전하지 못하다. 이유는 직접 시도해서, match된 결과를 보면 알 수 있다. 그렇다. 위에서도 말했다시피 패턴캡처식 \(pattern\)은 greedy하다. 그래서 이 greedy함을 제거하려고 봤더니, 위에서 "*?, +?, ??는 non-greedy 패턴 식을 작성할 때 사용한다"라고 했던 걸 상기하여 + 대신 +?를 사용하면, 원하는 match 결과를 얻을 수 있다. 다음이 문제 해결을 위한 마스터식이다.

C-M-% <.+>^J\([[:ascii:]]+?\)^J</.+> RET \\begin{verbatim}\1\\end{verbatim} RET

\1은 캡쳐된 문자열을 의미한다.

Powerful Minor Mode

  1. M-x ido-mode
  2. M-x electric-pair-mode

그 외에도 YASnippet같은 패키지는 반드시 익혀두어야 할 이맥스의 놀라운 확장이다.

Helpful Websites for Learning Emacs