如何在 Emacs 中向上滚动超过缓冲区顶部?

5

Emacs(以及所有其他文本编辑器)默认情况下在缓冲区底部的空白行下方显示。我希望 Emacs 也能够向上滚动/显示像这样在缓冲区顶部以上的空白行,以便于在处理小文件时将顶部行显示在屏幕中央。


我认为在Emacs中这是不可能的。但也许会有人提供一个答案来说明如何做到。;-) - Drew
你有检查过这个模式吗?https://github.com/emacsmirror/centered-cursor-mode - Thomas
是的,我喜欢居中光标模式,我偶尔会使用它。但据我所见,它并不会将光标置于文件顶部的中心位置。 - Trevor Pogue
2个回答

2

Thomas的回答指导下,我已经为此创建了一个小模式,现在可以在MELPA上使用:

TopSpace - 重新调整第一行与可滚动的上边距/填充

topspace


1
太棒了!我也在寻找同样的东西,非常感谢你提供了一个其他人可以使用的解决方案。 - rybern

1
我已经开始了一个小的次模式来完成这个任务。然而,作为第一版,它可能存在漏洞,无法处理所有边缘情况(例如缩小范围),并且效率不高。
因此,如果您能够改进或扩展此代码,可以随时直接编辑此答案。
(defvar vertical-center-num-buffers 0
  "The number of buffers in which `vertical-center-mode' is activated.")

(define-minor-mode vertical-center-mode
  "This minor mode displays the contents of a buffer vertically
centered with respect to the window height. This, of course, only
makes sense for buffers whose content is shorter than the window
height."
  nil
  " vc"
  nil

  ;; is the mode being turned on or off?
  (if vertical-center-mode
  ;; on
  (progn
    ;; keep track of the number of lines in the buffer
    (setq-local vertical-center-num-lines (count-lines (point-min) (point-max)))
    ;; use an overlay to display empty lines at the beginning of the buffer
    (setq-local vertical-center-overlay (make-overlay (point-min) (point-max)))
    ;; initial call to the function that centers the buffer contents
    (vertical-center--lines-changed 0)

    ;; react to changes to the buffer or the window
    (add-hook 'kill-buffer-hook 'vertical-center--kill-buffer)
    (add-hook 'window-size-change-functions 'vertical-center--window-size-changed)
    (when (= vertical-center-num-buffers 0)
      (add-hook 'before-change-functions 'vertical-center--before-change)
      (add-hook 'after-change-functions 'vertical-center--after-change))

    ;; this is just to play nice and remove the above hook
    ;; functions when they're no longer needed. Let's keep our
    ;; fingers crossed that we'll always stay in sync.
    (setq vertical-center-num-buffers (1+ vertical-center-num-buffers)))

;; off
;; delete/unset data structures when the mode is turned off
(delete-overlay vertical-center-overlay)
(makunbound 'vertical-center-num-lines)
(makunbound 'vertical-center-overlay)
(setq vertical-center-num-buffers (1- vertical-center-num-buffers))

;; remove hook functions when they're no longer needed
(when (= vertical-center-num-buffers 0)
  (remove-hook 'kill-buffer-hook 'vertical-center--kill-buffer)
  (remove-hook 'window-size-change-functions 'vertical-center--window-size-changed)
  (remove-hook 'before-change-functions 'vertical-center--before-change)
  (remove-hook 'after-change-functions 'vertical-center--after-change))))

;; handle killing of buffers
(defun vertical-center--kill-buffer ()
  (when vertical-center-mode
(setq vertical-center-num-buffers (1- vertical-center-num-buffers))))    

;; react to changes in the window height
(defun vertical-center--window-size-changed (arg)
  (vertical-center--lines-changed 0))

;; handle deletions of buffer text
(defun vertical-center--before-change (beginning end)
  (when (boundp 'vertical-center-num-lines)
(let ((num-lines 0))
  (while (< beginning end)
    (when (= (char-after beginning) ?\n)
      (setq num-lines (1- num-lines)))
    (setq beginning (1+ beginning)))
  (when (< num-lines 0)
    (vertical-center--lines-changed num-lines)))))

;; handle insertions into the buffer
(defun vertical-center--after-change (beginning end previous-length)
  (when (boundp 'vertical-center-num-lines)
(let ((num-lines 0))
  (while (< beginning end)
    (when (= (char-after beginning) ?\n)
      (setq num-lines (1+ num-lines)))
    (setq beginning (1+ beginning)))
  (when (> num-lines 0)
    (vertical-center--lines-changed num-lines)))))

;; update the display when either the buffer content or the window
;; height has changed
(defun vertical-center--lines-changed (num-lines)
  (setq vertical-center-num-lines (+ vertical-center-num-lines num-lines))
  (let ((top-margin (/ (- (window-height) vertical-center-num-lines) 2)))
    ;; set the top margin
    (overlay-put vertical-center-overlay 'before-string 
             (when (> top-margin 0)
               (make-string top-margin ?\n)))))

将上面的代码保存在一个文件中,文件名为"vertical-center.el",放在你选择的目录中,然后将以下代码添加到你的.emacs文件中:

(setq load-path (append load-path "<directory>"))
(autoload 'vertical-center-mode "vertical-center")

这里的<directory>应该是你保存"vertical-center.el"文件的目录路径。

重新启动Emacs后,你现在可以通过输入M-x vertical-center-mode来激活或停用该模式。


太棒了,谢谢!这是我看到的第一个解决方案。对我来说,我想要能够在大文件和小文件中“滚动超过顶部边缘”,并手动控制滚动 - 即不必担心每次编辑后文件总是重新居中等。为此,我除了kill-buffer-hook之外删除了上面的钩子,在此次要中创建并添加了自定义钩子,触发vertical-center--lines-changed函数。然后,我的滚动键绑定也运行自定义钩子,根据滚动方向增加或减少覆盖大小。 - Trevor Pogue
听起来很棒。你觉得有没有办法将你的代码版本和我的代码结合起来,让用户可以配置他们想要自动居中还是简单滚动?你的代码在哪里可以找到? - Thomas
是的,我已经成功将滚动功能与您的版本集成,并在昨天提交了一个编辑请求以更新代码。我进行了一些相当重要的代码更改,不确定编辑审核需要多长时间。也许这种工作更适合在版本控制平台上完成。如果您有兴趣在Github存储库中进行协作,请告诉我。 - Trevor Pogue
1
当然,把它放在Github上。 - Thomas
1
好的,请在此处查看GitHub存储库。 - Trevor Pogue
1
嗨@Thomas,只是想让你知道,我最近完善了我的小模式,并且现在可以在MELPA上使用(请参见我对此问题的答案中的链接)。感谢你的帮助! - Trevor Pogue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接