2008년 03월 01일
find-tag 기능 변경하기 (2) find-tag-default 분석하기
1. find-tag-default 소스를 봐야겠군요..
find-tag-default는 현재 find-tag함수에서 default 값을 리턴할때 사용하는 함수입니다. 제가 불만을 가진 함수 이기도 하죠.. 어쨋든 이것이 하는 일은 버퍼의 커서가 위치한 단어를 읽어서 리턴하는 것입니다.
제가 작성할 프로그램도 내부에서 find-tag-default와 비슷한 기능을 분명 필요로 할 것이기 때문에 먼저 find-tag-defaul를 분석해야 할 것 같습니다.
제가 만든 프로그램은 아래와 같은 방식으로 동작하게 될 것입니다.
b::add 라는 내용이 버퍼에 있습니다. 커서는 add에 위치하고 있습니다. 이때, find-tag-default를 수행하면 add를 리턴합니다.
그리고 다시한번 검사를 하는 겁니다. 만약 add앞의 문자가 "::"라면, 커서를 b로 이동 시킨다음에 다시 find-tag-default를 호출하는 것입니다.
그러면 b를 리턴할 것입니다. 이 둘을 "::"와 concat해서 리턴하는 것입니다. 그러면 b::add가 되겠죠..
여기서 find-tag-default는 string자체만 리턴하지 단어의 위치는 리턴하지 않기 때문에, 약간수정해서 단어, 단어의 시작 위치를 리턴하게 할 생각입니다.
2. find-tag-default에서 쓰인 함수들 정리.
find-tag-default 함수의 소스는 '/usr/share/emacs-21.3/lisp/progmodes/etags.el' 의 768째 줄에 있었습니다. 참고하세요.
(defun find-tag-default ()
(save-excursion
(while (looking-at "\\sw\\|\\s_")
(forward-char 1))
(if (or (re-search-backward "\\sw\\|\\s_"
(save-excursion (beginning-of-line) (point))
t)
(re-search-forward "\\(\\sw\\|\\s_\\)+"
(save-excursion (end-of-line) (point))
t))
(progn (goto-char (match-end 0))
(buffer-substring-no-properties
(point)
(progn (forward-sexp -1)
(while (looking-at "\\s'")
(forward-char 1))
(point))))
nil)))
save-excursion : save-excursion내에서 변경된 커서의 위치는 save-excursion을 빠져 나가면서 이전 커서의 위치로 복구 됩니다.
looking-at : 커서 아래 위치한 text가 regexp를 만족하는지 여부를 리턴(t or nil) 합니다.
forward-char : 커서를 앞으로 한칸 이동합니다.
C-h f : 함수 description을 출력합니다.
re-search-backward 의 함수 description을보면 아래와 같습니다. 함수 description을 보기위한 단축키는 C-h f입니다.
(re-search-backward "regexp" optional limit-of-search what-to-do-if-search-fails repeat-count)
:거꾸로 가면서 regexp 찾음. 두번째 인자부터는 옵셔널임(없어도 됨)
어디까지 탐색할지 location 값 (2번째 인자), 찾으면 머할지 (3번째 인자). 반복횟수(4번째 인자)
re-search-forward는 re-search-backward와 탐색 방향만 다름니다.
정규식 문자에서 \\두개 붙은것은 \붙은것과 같은 의미입니다. 문자열에서 \는 특별한 의미로 사용되기 때문에 \\을 사용합니다.
여기서 \sw 와 \s_가 나옵니다. 이것은 emacs의 syntax table의 syntax class와 관련이 있습니다.
대충 \sw는 w(word constituent) syntax class에 속하냐 를 묻는것이고, \s_ 은 _(symbol constituent) syntax class에 속하는지 묻는것입니다.
syntax table은 버퍼가 현재 어떤 mode에 있는지에 따라 틀립니다.
\s_의 경우를 예를 들어 보겠습니다.
c++인 경우는 문자 이외에 simbol을 형성할 수 있는게 오직 "_"밖에 없습니다. 하지만 lisp인 경우엔 ".?:-_"등 많죠..
그렇기 때문에 c++-mode인 경우와 emacs-lisp-mode인 경우 각각 다른 \s_를 적용할 수 있는 것입니다.
예를 들면, a::add의 경우 c++-mode에서는 :문자가 \s_가 아니기 때문에 add만 리턴합니다. 하지만 emacs-lisp-mode인 경우,
:문자가 \s_에 속하기 때문에 a::add를 리턴하게 됩니다.
이것을 이용해도 쉽게 문제가 해결될 듯 합니다. 즉, c++의 syntax table의 \s_ syntax class에 : 문자를 추가 시킨다음 find-tag-default를 호출하고 값이 리턴되면 바로 syntax class에서 제거 하는 것이죠..
하지만 이것은 의도하지 않은 동작을 할 우려가 있습니다. 즉, aaa::bbb 에서 aaa에 커서를 위치시키고 find-tag를 하는 경우엔 aaa class를 원했던 것인데, aaa::bbb가 리턴되기 때문에, bbb메소드로 찾아가겠지요..
point : 현재 커서 위치를 리턴합니다.
(match-beginning 0)
: 마지막에 행했던 regular expression search에서 찾았던 단어의 위치를 리턴합니다.
만약 마지막에 찾았던 단어가 abcd 라면, a위치를 리턴합니다.
이것과 대조되는 것으로 (match-end 0)이 있는데, 위의 경우 d다음 위치를 리턴합니다.
(buffer-substring start end) : start부터 end까지 버퍼에 있는것을 copy해서 리턴합니다.
(buffer-substring-no-properties start end) : buffer-substring와 기본적으로 같지만, text속성은 copy하지 않고 text자체만 copy해서 리턴합니다.
forward-sexp : sexp단위로 커서를 움직이는 함수.
3. find-tag-default 분석
이제 라인 단위로 분석해 봅시다.
(defun find-tag-default ()
(save-excursion ;find-tag-default를 수행하면서 변경한 cursor의 위치가 함수 사용이 끝나고 원래 위치로 복구됩니다.
(while (looking-at "\\sw\\|\\s_")
(forward-char 1)) ; 현재 커서가 단어를 만족하는 동안 커서를 앞으로 전진 시킴니다. 즉, 결국 단어의 끝 다음 칸으로 가겠군요.
(if (or (re-search-backward "\\sw\\|\\s_"
(save-excursion (beginning-of-line) (point))
t) ; 커서 아래에 단어가 없을 경우 backward방향의 단어를사용, 위의 while문 덕분에 대부분 여기에 속합니다.
(re-search-forward "\\(\\sw\\|\\s_\\)+"
(save-excursion (end-of-line) (point))
t)) ; 커서 아래에 단어가 없을 경우 forward 방향의 단어를 사용.
(progn (goto-char (match-end 0)) ; 그 단어의 끝으로 커서를 이동시킴
(buffer-substring-no-properties
(point) ; 단어의 끝 위치
(progn (forward-sexp -1) ; 단어의 앞으로 커서 이동
(while (looking-at "\\s'")
(forward-char 1)) ; expression prefix는 무시.
(point)))) ; expression prefix를 제외한 실제 단어의 앞위치
nil)))
이걸 어떤 식으로 수정할지 대충 보이는 군요.. 실제 단어의 앞위치를 단어와 같이 리턴해 주면 됩니다. 현재는 buffer-substring-no-properties를 통해서 단어만 리턴하고 있습니다.
그럼 다음편에서는 실제로 프로그램을 작성해 보고 수행해 보겠습니다.
find-tag-default는 현재 find-tag함수에서 default 값을 리턴할때 사용하는 함수입니다. 제가 불만을 가진 함수 이기도 하죠.. 어쨋든 이것이 하는 일은 버퍼의 커서가 위치한 단어를 읽어서 리턴하는 것입니다.
제가 작성할 프로그램도 내부에서 find-tag-default와 비슷한 기능을 분명 필요로 할 것이기 때문에 먼저 find-tag-defaul를 분석해야 할 것 같습니다.
제가 만든 프로그램은 아래와 같은 방식으로 동작하게 될 것입니다.
b::add 라는 내용이 버퍼에 있습니다. 커서는 add에 위치하고 있습니다. 이때, find-tag-default를 수행하면 add를 리턴합니다.
그리고 다시한번 검사를 하는 겁니다. 만약 add앞의 문자가 "::"라면, 커서를 b로 이동 시킨다음에 다시 find-tag-default를 호출하는 것입니다.
그러면 b를 리턴할 것입니다. 이 둘을 "::"와 concat해서 리턴하는 것입니다. 그러면 b::add가 되겠죠..
여기서 find-tag-default는 string자체만 리턴하지 단어의 위치는 리턴하지 않기 때문에, 약간수정해서 단어, 단어의 시작 위치를 리턴하게 할 생각입니다.
2. find-tag-default에서 쓰인 함수들 정리.
find-tag-default 함수의 소스는 '/usr/share/emacs-21.3/lisp/progmodes/etags.el' 의 768째 줄에 있었습니다. 참고하세요.
(defun find-tag-default ()
(save-excursion
(while (looking-at "\\sw\\|\\s_")
(forward-char 1))
(if (or (re-search-backward "\\sw\\|\\s_"
(save-excursion (beginning-of-line) (point))
t)
(re-search-forward "\\(\\sw\\|\\s_\\)+"
(save-excursion (end-of-line) (point))
t))
(progn (goto-char (match-end 0))
(buffer-substring-no-properties
(point)
(progn (forward-sexp -1)
(while (looking-at "\\s'")
(forward-char 1))
(point))))
nil)))
save-excursion : save-excursion내에서 변경된 커서의 위치는 save-excursion을 빠져 나가면서 이전 커서의 위치로 복구 됩니다.
looking-at : 커서 아래 위치한 text가 regexp를 만족하는지 여부를 리턴(t or nil) 합니다.
forward-char : 커서를 앞으로 한칸 이동합니다.
C-h f : 함수 description을 출력합니다.
re-search-backward 의 함수 description을보면 아래와 같습니다. 함수 description을 보기위한 단축키는 C-h f입니다.
(re-search-backward "regexp" optional limit-of-search what-to-do-if-search-fails repeat-count)
:거꾸로 가면서 regexp 찾음. 두번째 인자부터는 옵셔널임(없어도 됨)
어디까지 탐색할지 location 값 (2번째 인자), 찾으면 머할지 (3번째 인자). 반복횟수(4번째 인자)
re-search-forward는 re-search-backward와 탐색 방향만 다름니다.
정규식 문자에서 \\두개 붙은것은 \붙은것과 같은 의미입니다. 문자열에서 \는 특별한 의미로 사용되기 때문에 \\을 사용합니다.
여기서 \sw 와 \s_가 나옵니다. 이것은 emacs의 syntax table의 syntax class와 관련이 있습니다.
대충 \sw는 w(word constituent) syntax class에 속하냐 를 묻는것이고, \s_ 은 _(symbol constituent) syntax class에 속하는지 묻는것입니다.
syntax table은 버퍼가 현재 어떤 mode에 있는지에 따라 틀립니다.
\s_의 경우를 예를 들어 보겠습니다.
c++인 경우는 문자 이외에 simbol을 형성할 수 있는게 오직 "_"밖에 없습니다. 하지만 lisp인 경우엔 ".?:-_"등 많죠..
그렇기 때문에 c++-mode인 경우와 emacs-lisp-mode인 경우 각각 다른 \s_를 적용할 수 있는 것입니다.
예를 들면, a::add의 경우 c++-mode에서는 :문자가 \s_가 아니기 때문에 add만 리턴합니다. 하지만 emacs-lisp-mode인 경우,
:문자가 \s_에 속하기 때문에 a::add를 리턴하게 됩니다.
이것을 이용해도 쉽게 문제가 해결될 듯 합니다. 즉, c++의 syntax table의 \s_ syntax class에 : 문자를 추가 시킨다음 find-tag-default를 호출하고 값이 리턴되면 바로 syntax class에서 제거 하는 것이죠..
하지만 이것은 의도하지 않은 동작을 할 우려가 있습니다. 즉, aaa::bbb 에서 aaa에 커서를 위치시키고 find-tag를 하는 경우엔 aaa class를 원했던 것인데, aaa::bbb가 리턴되기 때문에, bbb메소드로 찾아가겠지요..
point : 현재 커서 위치를 리턴합니다.
(match-beginning 0)
: 마지막에 행했던 regular expression search에서 찾았던 단어의 위치를 리턴합니다.
만약 마지막에 찾았던 단어가 abcd 라면, a위치를 리턴합니다.
이것과 대조되는 것으로 (match-end 0)이 있는데, 위의 경우 d다음 위치를 리턴합니다.
(buffer-substring start end) : start부터 end까지 버퍼에 있는것을 copy해서 리턴합니다.
(buffer-substring-no-properties start end) : buffer-substring와 기본적으로 같지만, text속성은 copy하지 않고 text자체만 copy해서 리턴합니다.
forward-sexp : sexp단위로 커서를 움직이는 함수.
3. find-tag-default 분석
이제 라인 단위로 분석해 봅시다.
(defun find-tag-default ()
(save-excursion ;find-tag-default를 수행하면서 변경한 cursor의 위치가 함수 사용이 끝나고 원래 위치로 복구됩니다.
(while (looking-at "\\sw\\|\\s_")
(forward-char 1)) ; 현재 커서가 단어를 만족하는 동안 커서를 앞으로 전진 시킴니다. 즉, 결국 단어의 끝 다음 칸으로 가겠군요.
(if (or (re-search-backward "\\sw\\|\\s_"
(save-excursion (beginning-of-line) (point))
t) ; 커서 아래에 단어가 없을 경우 backward방향의 단어를사용, 위의 while문 덕분에 대부분 여기에 속합니다.
(re-search-forward "\\(\\sw\\|\\s_\\)+"
(save-excursion (end-of-line) (point))
t)) ; 커서 아래에 단어가 없을 경우 forward 방향의 단어를 사용.
(progn (goto-char (match-end 0)) ; 그 단어의 끝으로 커서를 이동시킴
(buffer-substring-no-properties
(point) ; 단어의 끝 위치
(progn (forward-sexp -1) ; 단어의 앞으로 커서 이동
(while (looking-at "\\s'")
(forward-char 1)) ; expression prefix는 무시.
(point)))) ; expression prefix를 제외한 실제 단어의 앞위치
nil)))
이걸 어떤 식으로 수정할지 대충 보이는 군요.. 실제 단어의 앞위치를 단어와 같이 리턴해 주면 됩니다. 현재는 buffer-substring-no-properties를 통해서 단어만 리턴하고 있습니다.
그럼 다음편에서는 실제로 프로그램을 작성해 보고 수행해 보겠습니다.
# by | 2008/03/01 14:39 | Emacs Lisp | 트랙백 | 덧글(0)





☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]