왜 C-d 키를 눌러 스크롤하면 절반 이상이 넘을까?
Emacs에서 Evil 모드를 사용하고 있다. Vim 키바인딩을 Emacs에서 사용하기 위해서다. Emacs와 Vim을 같이 쓰는 대화합의 장이다.
현재 편집 영역의 절반을 아래로 스크롤 하는 C-d
키 동작이 이상하다. C-f
키가 한 페이지를 아래로 스크롤 한다면 C-d
키는 절반을 아래로 스크롤해야 한다. 하지만 어떨 때는 C-f
키를 누른 것처럼 한 페이지 정도를 아래로 스크롤 한다.
왜 이런 걸까?
C-d
키에 바인딩한 evil-scroll-down
함수 주요 코드
왜 화면 절반보다 더 많은 라인을 스크롤 하는지 함수를 살펴보자. C-d
키를 누르면 evil-scroll-down
함수를 실행한다.
(evil-define-command evil-scroll-down (count)
(interactive "<c>")
;; ...
(setq count (evil--get-scroll-count count))
;; ...
)
evil--get-scroll-count
함수가 얼마만큼 스크롤 할 것인지를 계산하는 함수다.
(defun evil--get-scroll-count (count)
"Given a user-supplied COUNT, return scroll count."
(cl-flet ((posint (x) (and (natnump x) (< 0 x) x)))
(or (posint count)
(posint evil-scroll-count)
(/ (window-body-height) 2))))
window-body-height
함수 리턴 값을 2로 나눈다. 즉 window-body-height
함수 리턴 값이 현재 화면에 보이는 총 라인 수다. 그걸 반으로 나눠서 화면 절반만 스크롤할 값을 구한다.
그렇다면 이상하다. Emacs 기본 라이브러리 함수인 window-body-height
가 이상한 값을 리턴할리는 없잖아?
window-body-height
값이 왜 이런가?
M-:
키에 바인딩된 eval-expression
함수를 호출한 후 (window-body-height)
를 입력해서 지금 포커스가 있는 위도의 body height를 구해봤다.
찾았다. window-body-height
함수 리턴 값이 더 크게 나오고 있다. 49줄을 표시하고 있는 윈도에서 실행하니 63이 나온다. 이걸 반으로 나누고 있으니 기대와 다르게 절반 이상이 스크롤된 것이다. 한편으로는 이 함수를 엄청나게 많이 쓰고 있을 텐데, 어떻게 고칠지 막막하다.
’bug#54894: 28.1; window-body-height returns wrong result if line-spacing’ 글에서 원인을 찾았다. line-spacing
값이 nil이 아닐 때, window-body-height
함수 리턴 값이 텍스트 줄 수와 다르다는 버그 리포트다.
줄 간격이 있으면 읽기 편해서 아래처럼 줄 간격을 세팅해서 쓰고 있다.
(set-default 'line-spacing 0.2)
해결 방법이 있을 것 같아서 버그 리포트 글을 읽어보았다.
It does handle that correctly. Like with most (if not all) functions that return window and frame dimensions, the return value is in unit of a canonical line height for the frame. It doesn’t count the actual text lines. So it isn’t affected by stuff like line-spacing, the actual height of the lines due to changes in fonts, etc.
bug#54894: 28.1; window-body-height returns wrong result if line-spacing - li…
리턴 값이 실제 텍스트 라인 수가 아니라 프레임의 표준 줄 높이다(unit of a canonical line height for the frame). 읽어도 이해가 안 되는 답변이다. 프레임의 표준 줄 높이는 또 뭐람. 잘 모르겠지만 확실한 건 window-body-height
함수 구현이 절대 바뀔 리가 없다는 것이다.
line-spacing
값이 nil이 아닐 때, 텍스트 라인 수를 구하는 방법을 찾아야 한다. 혹은 line-spacing
값을 nil로 설정하고 눈이 적응하는 방법도 있다.
evil--get-scroll-count
함수 override로 해결?
line-spacing
값이 nil이 아닐 때, 텍스트 라인 수를 구하는 방법은 없는 걸까? 픽셀로 연산하는 방법이 있다.
(/ (window-body-height nil t) (default-line-height))
window-body-height
함수 두 번째 인자로 t
넘겨서 pixel 단위로 현재 포커스가 있는 윈도 크기를 구한다. 거기에 default-line-height
로 line-spacing
값이 반영된 줄 높이를 나눠서 구한다.
이제 적용할 차례다. Advice를 사용해 evil--get-scroll-count
함수를 덮어쓰자.
(after! evil
(defun my-evil-get-scroll-count (count)
"Given a user-supplied COUNT, return scroll count."
(let ((line-count (/ (window-body-height nil t)
(default-line-height))))
(cl-flet ((posint (x) (and (natnump x) (< 0 x) x)))
(or (posint count)
(posint evil-scroll-count)
(/ line-count 2)))))
(advice-add 'evil--get-scroll-count :override #'my-evil-get-scroll-count))
line-spacing
널 지키려고 내가 이렇게까지 한다.
하지만
결론 - line-spacing
을 nil
로 설정하다
line-spacing
을 고려해 텍스트 줄 수를 구하게 evil--get-scroll-count
함수를 덮어써서 한동안 신나 하며 잘 썼다. 스크롤 관련 동작들이 잘 동작하다가 한 번씩 튀는 현상을 경험했다. 예전처럼 그런 현상들이 나오는 것이다. line-spacing
이 nil
일 때 잘 동작하는 어떤 함수를 어디에선가 사용하고 있다!
발견할 때마다 고쳐가며 line-spacing
값을 지켜야 할까? 아니면 line-spacing
을 nil
값으로 설정하고 이 문제에서 자유로워질 것인가?
line-spacing
을 nil
로 설정했다. 처음엔 눈에 안 들어오지만 금새 눈이 적응한다. 눈을 적응시키고 line-spacing
문제에서 자유로워지기로 했다. 지켜주지 못해 미안해.
C-x C-s C-x C-c