KTUGFaq

KTUG FAQ

로그인:
비밀번호:
가입
Love is in the offing. Be affectionate to one who adores you.
FrontPage › emacs따라하기
Emacs는 매우 강력한 editor이나 항상 강력하고 좋다고 하는 것은 배우기가 어렵다는 단점이 있다. WindowXP(정확히 말하면 KTUGCollection2006)으로 이사해 오면서 다시 한번 배워보려한다.

목차

1 Emacs사용을 위해서 우선 해야 할 것들
2 꼭 외워야할 것들
3 약어모드
3.1 한 세션을 위한 약어
3.2 시작할때 약어 모드 실행하기
4 단어 및 주석 자동 입력
5 개요모드의 사용
6 정규표현식 사용하기
6.1 우선 기본적인 사용
6.2 실질적인 사용례(사용자 정의 command를 환경으로 바꾸기)
6.3 실질적인 사용례 (본 Wikipage를 LaTeX file로 만들기)
6.3.1 Q1
6.3.2 A1
6.3.3 Q2
6.3.4 A2

1 Emacs사용을 위해서 우선 해야 할 것들

Emacs가 처음 설계되었을때는 지금 현재 keyboard에서 A키 옆의 Caps Lock키 자리가 Ctrl키가 있었고, ~키 자리에 Alt키가 있었다고 한다. LaTeX를 사용하다가 보면 ~키는 가끔 쓸 일이 있지만, Caps Lock키는 거의 쓸일이 없다.(실제로 Windows를 쓰면서도 거의없다.) 그래서 http://youlsa.com/2005/09/08/51/ 옆의 site에 가면 파일을 down받아서 설치하면 간단히 Caps Lock키와 Ctrl키를 바꿔줄수 있다. 아무래도 이쪽이 휠씬 더 편하게 작업할 수 있다. 그런데 WindowXP system자체를 바꾸지 말고, Emacs내부에서만 바꿀수도 있을듯 한데, 아직까지는 잘 모르겠습니다.

2 꼭 외워야할 것들

* 아래의 키 입력은 http://wiki.kldp.org/wiki.php/EmacsGdbEtagsCscope 에서 가져온 것입니다. 신성국님께 감사드립니다.
C-x C-f 	control key를 누른 상태에서, `x'를 누르고 (control key를 떼지 않고) `f'를 누른다.
C-x o 	control key를 누른 상태에서, `x'를 누르고 (control key를 떼고) `o'를 누른다.
C-_ 	control key를 누른 상태에서 `_'(밑줄)을 누른다. 
M-x compile<RET> 	meta key를 누르고 `x'를 누른 다음 (meta key를 떼고) `compile'을 치고 <RET>을 누른다.

자 이제 여기까지 배웠으면, Emacs를 실행시키고, "C-h t"를 눌러 tutorial을 열고 읽어보기 바란다. 위 tutorial을 읽을 때, 아래 키 목록은 반드시 외워서 익숙하게 쓸 줄 알아야 하는 키들이므로 꼭 외워 쓰기 바란다:

-
C-x C-c 	Emacs 종료
C-v 	다음 페이지
M-v 	이전 페이지
C-l 	현재 줄을 창의 가운데 부분으로 보여줌
C-p 	커서 up
C-n 	커서 down
C-f 	커서 right
C-b 	커서 left
C-a 	커서를 줄의 맨 처음으로
C-e 	커서를 줄의 맨 마지막으로
M-f 	다음 단어로
M-b 	이전 단어로
C-d 	한 글자 지우기
M-d 	한 단어 지우기
C-k 	현재 커서 위치에서 줄 끝까지 지우기
C-<SPC> 	현재 커서 위치 마크(mark)하기
M-w 	마크에서 현재 커서 위치까지 블럭 지정(copy)
C-w 	마크에서 현재 커서 위치까지 지우고 블럭 지정(cut)
C-y 	붙여 넣기(paste)
C-_ 	undo
C-g 	명령 입력 취소 (undo 아님)
C-x C-s 	파일 저장하기(save)
C-x C-w 	다른 이름으로 파일 저장하기(save as...)
C-x C-f 	파일 불러오기(load)
C-x C-k 	버퍼 지우기(kill)
C-x b 	다음 버퍼로 전환
C-x C-b 	버퍼 목록 보여주기
C-x 2 	창을 두개로 나누기
C-x 1 	현재 창을 제외한 다른 창 닫기
C-x o 	다른 창으로 커서 이동

3 약어모드

약어모드는 특별한 단어나 문구에 대한 약어를 정의해서 사용할 수 있도록 한다. 또한 약어모드에는 습관적으로 틀린 말이나 단어가 있는 경우에는 오자를 정확한 단어로 바꾸어 주는 기능도 가지고 있다. 단점으로는 약어를 정의할때 단어자체가 어떤 의미를 포함하거나 확장되기를 원하지 않는 단어는 사용하지 말아야 한다. 예를 들면 World Association for Replicant Technology를 위하여 wart를 사용하지 않는 것이 좋다. 물론 wart자체의 의미로 사용하기위해서는 M-x unexpand-abbrev RETRUN을이용해서 약어를 취소할 수는 있다.

3.1 한 세션을 위한 약어

  • Esc x abbrev-mode RETURN(M-x abbrev-mode RETURN)을 입력해서 약어모드로 들어간다. 모드라인에 Abbrev가 표시된다.
  • 전역약어를 위해서 원하는 약어를 적고, C-x aig(add-inverse-global)를 입력한다(지역약어의 경우는 C-x ail를 넣는다). 가령 우리가 \LaTeX명령을 집어 넣는다고 할때 shift키가 없는 latex로 쓰고자 하면 latex를 입력하고 C-x aig를 집어 넣으면 사용자에게 확장할 때 쓸 내용을 요청한다. 여기에 LaTeX로 집어 넣으면 앞으로 본문을 쓸때 latex만 쓰고 난후에 보면 어느새 LaTeX로 바뀌어 있는 것을 보게된다.
    • 전역약어란 모든 모드에서 적용되는 약어이고, 지역약어란 특정한 mode에서만 적용되는 약어이다. 예를 들면 PDFLaTeX mode에서만 적용되는 약어)
  • 이러한 약어모드가 마음에 든다고 하면 시작할 때 자동으로 시작하도록 추가할 수 있다.

3.2 시작할때 약어 모드 실행하기

  • .emacs 파일에 다음과 같은 내용을 적는다.
     (setq-default abbrev-mode t)
     (read-abbrev-file "~/.abbrev_defs")
     (setq save-abbrevs t) 

4 단어 및 주석 자동 입력

다음의 내용은 http://wiki.kldp.org/wiki.php/EmacsDynamicAbbrevExpand 에서 가지고 왔습니다. 좀더 자세한 내용은 위의 site를 확인하세요. Emacs는 어떤 버퍼의 내용을 편집할 때, 이 버퍼에 쓰인 모든 단어의 내용을, 그 단어의 첫 일부분만 입력해도 자동으로 입력해주는 기능이 있습니다. 실제로 코딩할 때 매우 유용한 기능 중의 하나입니다. M-x dabbrev-expand로 실행할 수 있으며, 대부분의 경우 M-/로 실행할 수 있습니다. 명령문을 하나 집어넣고 난후에 다음에 필요한 글짜 일부를 typing후에 M-/를 해 보세요. 오타 없이 빠르게 text를 입력할 수 있습니다.

5 개요모드의 사용

책, 긴 메모, 기술적인 내용 등을 작성하면서 전체구조를 파악하기란 어려운 일이다. 따라서 개요를 장문으로 부드럽게 전개하거나, 진행하면서 내용을 재구성하는 데 어려움을 느끼니다. 즉 나무에 가려서 숲을 볼 수 없다는 의미이다. 이때 개요 모드에서는 해결책을 제시한다. 이 글은 KTUGCollection2006의 emacs설치에 따른 것입니다. 부모드로 설치된 경우에 사용방법이다.
C-c @ C-t (hide body) 텍스트 본문 없이 제목만 볼수 있다.
C-c @ C-a (show all) 본문이든 제목이든 파일의 숨겨진 내용을 표시한다.
C-c @ C-d (hide subtree) 제목(section or subsection)에 딸린본문의 일부가 생략부호 (...) 대체됨
C-c @ C-s (show subtree) 생략부호의 내용이 나타난다.
  • 나머지는 pop-up menu에서 쓰면 될것 같음

6 정규표현식 사용하기

6.1 우선 기본적인 사용

^   줄의 처음을 찾는다
$   줄의 끝을 찾는다
?   앞의 문자나 그룹을 0 또는 1회 반복한다.
.   임의의 한 글자를 찾는다
.*  길이가 0이상인 임의의 문자열을 찾는다
\<  단어의 처음을 찾는다
\>  단어의 끝을 찾는다
[]  대괄호 내에 정의된 문자예를 들어, [a-z]는 임의의 알파벳 소문자를 의미한다
\\( 그룹의 시작
\\) 그룹의 끝
\\| \\|의 앞이나 뒤의 표현식에 대응한다.
일반적인 egrep과 가장 큰 차이점은
  • *연산자 이다. egrep에서는 *연산자가 임의의 문자열을 의미하지만 emacs에서는 .*으로 써야한다
  • 그룹연산자인 ()에 역슬래시가 두개 들어간다는 점이다. 이렇게 역슬래시가 많이 들어가는 이유는 기본적인 정규표현식 연산자 이외에 특수 문자가 많아지는 것을 방지하기 위해 역슬래시를 포함한다고 한다.(?)

6.2 실질적인 사용례(사용자 정의 command를 환경으로 바꾸기)

예가 적절한지를 모르겠지만, 만약 사용자 정의 command를 생각이 바뀌어서 환경으로 바꾸고 싶다고 하자. 이것을 그냥 simple한 search & replace로 바꾸기는 쉽지가 않다. 예를 들어서 \mycommand{text}를 \begin{myenv} text \end{myenv}로 해야 하는 상황이 있다면 어떻게 고칠것인가?
  • 쉬운것 부터 생각해보자. command에 딸려 있는 인자가 하나이고 그안에 또 다른 command가 없는 경우이다. 그야 말로 text일 뿐인 경우이다. C-M-% 를 입력하거나, Emacs의 메뉴에서 Edit->Replace->Replace Regexp 를 선택해서 먼저 mycommand부분을 집어 넣고, 그 이후에 myenv부분을 집어 넣는다.
     \\\mycommand{\(.*?\)} -> \\begin{myenv} \1 \\end{myenv}
    
    • 위에서 주목할 점은 정규표현식의 연산자로 사용되는 문자를 나타내기 위해서는 역슬래시 두개를 앞에 두어야 한다.즉 \\\mycommand에서 앞의 두개의 역슬래시는 3번째 역슬래시가 정규표현식의 연산자가 아니라는 것을 나타낸것이다. 두번째로 \1의 인자로 받을 문자 grouping하는 연산자 \(.*?\) 이다. 여기의 KTUG Wiki 정규식 에서도 언급된 내용이지만 느스한 연산자를 써서 matching을 시도 한것이다. 그렇다면 replacement string에서는 왜 두개의 역슬래시만 쓴 이유는 Replacement string은 LISP 인터프리터가 해석을 안한다고 합니다. (무슨 말인지 잘 모르겠지만....) 그래도 작동은 하니깐요? 해석좀...
  • 좀더 어려운 경우는 인자가 2개 이상이고 앞에 다른 명령문이 쓰인 경우

6.3 실질적인 사용례 (본 Wikipage를 LaTeX file로 만들기)

물론 최근에 wikipage를 어떻게 해서 LaTeX로 변형하였다는 소문은 듣기는 했지만, 여기서는 간단히 위의 source를 받아서 어떻게 tex로 바꾸는지에 대해서 생각해 보겠다.
  • 먼저 source의 분석(?)이다. 여기 wiki page는 간단히게 되어 있어서 들어가 있는 것들은 인사말, tableofcontents,제목과 부제목, 강조된글꼴, 글짜그대도 보기모드, 본문, 본문중 latex에서 그대로 쓰기 금지된 글짜(\,?, %), hypertarget등이 들어 있는 것이 전부이다.
    • 위에서 인사말은 abstract로, tableofcontents는 tableofcontents로 제목과 부제목은 section과 subsection으로, 강조된 글꼴은 emph로 글짜그대로 보기는 boxedverbatim으로 본문중 latex에서 쓰기 금지된글짜등은 적당한 것으로 hypertarget은 \url로 바꾸면 될것 같다.
  • Emacs에서 할일로는 그냥 emacs의 명령행에서 하는 것은 조금 어려울듯 싶고 해서 LISP program으로 해보려고 한다.
    • 정식으로 LISP program을 만들기 보다는 간단한 함수 몇개를 정의해서 돌리면 되므로 Lisp Interaction mode에서 작업하기로한다. <빈 파일에서 M-x lisp-interaction mode 주모드를 하고 난후에 아래의 code를 집어 넣고 나서 마지막에 C-j를 입력하면 등록이 됩니다. 그리고 편집을 하려고 하는 text 화일에서 M-x 함수명 하면 됩니다.>
       (defun mod-wiki ()
       (interactive)
       (save-excursion
        ( replace-regexp "===\\(.*?\\)===" "\\\\subsection(\\1)") 
        ( replace-regexp "==\\(.*?\\)==" "\\\\section{\\1}")))
      
  • 다음은 wiki의 목록 선택자인 *를 \item으로 바꾸고 난후에 처음 나온 \item에 \begin{itemize}을 덧붙이는 code입니다. 매우 신기합니다. 이렇게 text화일에 어느 일정 부분에 특정한 부분을 집어 넣을수 있다는 것이요!! 재미있습니다. ^^ 정말로 재미있네요. conditional까지 붙였습니다. 만약 목록이 세개 이상 들어간 경우에는 if문을 하나 더 써야 하겠지요!.
       (defun mod-listofwiki ()
     (interactive)
     (save-excursion
       (goto-char (point-min))
       (while (< (point) (point-max))
         (let ((count (re-search-forward "^\\\\item")))
         (backward-word)
         (backward-char)  
         (goto-char (point))
         (insert "\\begin{itemize}\n")
         (forward-line 1)
         (goto-char(point))
         (while (looking-at "^\\\\item") 
          ( if (looking-at "^\\\\item2") 
          	(progn
    		(insert "\\begin{itemize}\n")
    		(forward-line 1)
    		(while (looking-at "^\\\\item2") (forward-line 1))
    		(insert "\\end{itemize)\n"))
    	(forward-line 1))) 	
         (insert "\\end{itemize}\n")))))
     
  • 만약 wiki에서 \command나 \begin{env}문 등을 ㅤ 썼을때는 어떻게 해야 하나요 대한 고민입니다. 그냥 간단히 생각하기로는 \command나 \begin{env}를 \verb로 치환하여 그 안에 집어 넣으면 될것 같지만, 그것이 그리 단순하지는 않습니다. 왜냐하면 우리는 이전에 text 문을 boxedverbatim환경으로 바꾼다고 했고, 그렇다면 이 안에 들어 있는 것도 그렇게 바뀌어 버릴것 같습니다. 그러면 안되기 때문에 쓴 것이 narrow-to-region이라는 ELISP 함수입니다. 그런데 꼭 이것도 두번을 실행해야 제대로된 결과가 나옵니다. 왜 일까요? 그리고 중간중간에 보면 \을 시작되는 것은 다 이런식으로 바꾸는 것을 볼수는 있습니다만, 이것이 그리 크게 문제되지 않을것 같아서 그냥 두었습니다.
    (defun mod-wikitotex ()
     (interactive)
     (save-excursion
       ( replace-regexp "{{{" "\\\\begin{boxedverbatim}" )
       ( replace-regexp "위의 반대기호" "\\\\end{boxedverbatim}" )
       ( point-min )
       ( while (< (point) (point-max)) 
    	 ( narrow-to-region (point) (progn 
    				      (search-forward "\\begin{boxedverbatim}")
    				      (backward-word)
    				      (backward-word) 
    				      (backward-char)
    				      (point)))
    	 ( goto-char (point-min))
    	 ( replace-regexp "\\(\\\\[a-zA-Z{}]*\\)" "\\\\verb{\\1}")
    	 ( widen )
    	 ( search-forward "\\end{boxedverbatim}")
    	 ( narrow-to-region (point)( progn 
    				      (search-forward "\\begin{boxedverbatim}")
    				      (backward-word)
    				      (backward-word) 
    				      (backward-char)
    				      (point)))
    	 ( goto-char (point-min))
    	 ( replace-regexp "\\(\\\\[a-zA-Z{}]*\\)" "\\\\verb{\\1}")
    	 ( widen ))))
    
  • 이제 위의 함수를 적당히 이용하면 될것 같습니다. 혹시 필요하신분이 있으면 한번 해보겠습니다.

6.3.1 Q1

맛배기로 LISP program을 만들고 있는데, 두 가지 문제가 있다. 첫째는 Emacs가 죽는 경우가 가끔씩 있다는 것이다.(정말 이럴때는 다시 linux로 돌아가고 싶다) 두번째는 file의 cursor가 처음에 가 있어야 한다는 것이다.(?) 그리고 정말로 모르겠는것이 백스래시 사용방법이다. 대체로 어떻게 백슬래시를 써야 제대로 된 방법인지 알수가 없다. 조금 조언을 해 주실분은 안 계신가요?

6.3.2 A1

어떤 경우에 죽는지요? file의 cursor가 처음에 가 있어야 한다는 말의 의미가 무엇인지요? lisp의 regular expression은 백슬래쉬가 2개씩 필요하다고 보시면 됩니다.(그누 이맥스 시작하기 "한빛미디어" p412쯤에 보시면 자세히 나와 있습니다.
정규 표현식의 연산자로 사용되는 문자를 나타내기 위해서는 역슬래시 두개를 앞에 두어야 한다. 즉 별표를 나타내려면 \\*를 사용한다. 왜 역슬래시를 두개 사용하는가? 그 이유는 이맥스 LISP가 문자열을 읽고 해석하는 방법과 관련된다. 이맥스에서 LISP 프로그램의 문자열을 읽을 때 역슬래시 하나를 이스케이프 문자로 해석하기 때문에 두개의 역슬래시를 하나의 역슬래시로 인힉한다. 만약 정규 표현식으로 사용하던 문자열이라면(즉 정규 표현식의 인자를 입력받는 함수로 넘겨진다면) 역슬래시 하나를 정규 표현식 구문의 일부로 사용한다. 예를 들어, 다음과 같은 LISP 코드가 있다고 하자.
(replace-regexp "fred\\*" "bob*")

LISP 인터프리터는 fred\\*를 fred\*로 해석해서 replace-regexp 명령의 인자로 넘긴다. 그러면 replace-regexp 명령은 fred\*를 fred 뒤에 별표가 표시된 형태로 인식한다. 하지만 replace-regexp의 두번째 인자는 정규 표현식이 아니므로 bob*에서는 역슬래시를 이용한 이스케이프 코드가 필요없다. 또한 위의 내용을 사용자 명령으로 직접 입력해서 실행한다면 두 개의 역슬래시를 사용하지 않는다. 즉 ESC x replace-regexp RETURN을 입력하고, fred\*와 bob*을 입력한다. 미니버퍼에서 받아들인 문자열은 다른 방식으로 해석한다.

6.3.3 Q2

감사합니다. 저도 실은 같은 책을 보면서 공부하고 있습니다.(?) 이렇게 학습능력이 떨어져서야 참! 헤헤.... 첫째로 Emacs가 죽는 경우는 위의 경우를 실행하고 난후에 wikitest화일은 저장하고 하지 않고, close할때 생깁니다. gnuserver error라고 하면서 stnin으로 부터 입력을 받을수 없다고 합니다. 그런데 이런 error message가 나왔다가 안 나왔다가 합니다. 두번째로 위의 function을 실행하면 제대로된 결과가 한번에 나오지 않습니다. 두번 이상 실행해야 나옵니다.(그래서 제 나름대로 생각하기에 그냥! 글의 마지막으로 움직여서 그렇지 않나! 생각해서 생각나는 데로 적어 본 것입니다) 이렇게 금방 보실 분이 있을줄은 생각도 못하고요... 섯째로 "미니버퍼에서 받아 들인 문자열은 다른 방식으로 해석한다" 라는 말이 도대체 무슨 말인지를 알수 없었습니다. *를 escapse sequence로 받아들이려하면 앞에 \\가 있어야 한다는 말은 이해가 갑니다. 그래서 제 생각에는 \\\ 세개만 있으면 되지 않나 생각을 했습니다. 그런데 이렇게 하고 했더니 Invalid \ use라고 하는 error message가 나오더군요! 그래서 결국 \\\\ 하나를 더 했더니, 제대로 된 결과가 나왔습니다. 왜 하나를 더 해야 하나요? ps) 목록를 tex file로 만들기가 쉽지 않네요? *를 item가 한칸더 들어간 *를 item2로 해 놓고 나서 여기에 적절히 환경으로 둘러싸주어야 하는데.... 시작과 끝점을 만들기가 쉽지를 않습니다. 쉽지 않아서 그냥 쉬고 있습니다. 뭔가 방법이 나올듯 합니다만. --synapse

6.3.4 A2

답변은 아니지만 좀 구분할 필요가 있을듯 하여 편의상 Q1, Q2라 붙였습니다. 정확한 답이 아니라 죄송 ^^ 구체적인 예를 드셨는데 제가 잘 이해를 못하겠습니다. 어떤 소스로 위의 lisp을 실행하셨는지요? 정확한 소스를 인용해주시면 저도 한번 해보겠습니다. 실은 작은나무님이 lisp을 예전에 하셨다고 하니 아마 잘 봐주실겁니다. :)

두번째 위 function이 parameter가 없습니다. buffer전체라던가 그런게 전혀 없는데 실행될때 어떻게 어디서 어디까지 변경해야 하는지를 모르겠지요. 아마 replace-regexp함수가 특별한 인자가 없으면 커서위치부터 마지막 까지 동작하지 않을까 추측됩니다. M-x describe-function RETURN replace-regexp RETURN 하시면 설명이 나올겁니다.

미니버퍼란 이맥스 맨 아래 반향영역을 의미한다는 것은 아시겠죠. 보통 윈도우의 경우 위의 함수를 실행하듯이 M-x replace-regexp RETURN 이라고 치면 Replace regexp:이 나옵니다. 그러면 찾을 문자를 입력하고 RETURN을 입력하면 Replace regexp begin with: 나오면 바꿀 문자를 입력하게 됩니다. 이때 이렇게 묻는 말에 답변(?)할때는 일반적으로 역슬래시를 하나만 쓴다는 뜻입니다. 무척 긴데 별로 잘 설명되지는 않는군요. 간단히 interactive함수를 함수로 call할때는 역슬래시를 두개, 직접 이맥스의 명령어로 사용할때는 역슬래시를 한개 이렇게 이해해도 될것 같습니다만.

맞습니다. Emacs lisp-interaction mode로 해서 간단히 실험해 보았습니다. 본 wiki page 내용을 copy해서 emacs에 붙여넣고 나서 새로운 창 하나를 띄웁니다. 그리고 M-x lisp-interaction-mode 하시고요. 위의 코드를 받아서 copy하고 나서 화일의 끝에 가서 C-j하시면 wiki-mod라는 함수가 정의됩니다. 그리고 나서 다시 이전 wiki page내용을 copy한 것으로 와서 M-x wiki-mod하면 바뀐 결과가 나옵니다. 위에서 목록을 바꾸는 것을 만들고 있는데, 배워야 할것도 많지만, 신기하기는 합니다.감사합니다.--synapse

^
Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2007-11-11 00:30:08
Processing time 0.0772 sec