使 Emacs 中的文档视图适合页面宽度

Posted

技术标签:

【中文标题】使 Emacs 中的文档视图适合页面宽度【英文标题】:Making Document View in Emacs fit to width of page 【发布时间】:2014-04-23 06:32:11 【问题描述】:

我正在尝试使用 Emacs 中的文档视图来阅读 PDF,但我不知道如何使它的行为类似于许多 PDF 阅读器的“适合宽度”命令。有没有内部方法可以做到这一点?

【问题讨论】:

M-x doc-view-fit-width-to-window(在 DocView 模式下默认绑定到 W)不符合您的要求吗? 感谢您提出这个问题 - 它让我了解了 doc-view 提供的内容(通过“describe-mode”) - 适合宽度、适合页面、以文本形式查看。 @Chris - 效果很好,谢谢!文档视图启动时是否有一个挂钩,我可以将此命令绑定到? @MrSinister13,不幸的是我找不到这样做的好方法。有doc-view-mode-hook,但从那个钩子运行doc-view-fit-width-to-window 似乎并没有做任何有用的事情。我确信这可以通过比我拥有的更多的 elisp 知识来实现​​...... 【参考方案1】:

下面的 sn-p 定义了一个新的次要模式doc-view-autofit-mode,我在下面使用doc-view-mode-hook 激活了它。它适用于我在 Ubuntu 14.04 上的 Emacs 24.3 上,甚至可以在我调整窗口大小时调整缩放大小!

(由于doc-view-autofit-timer-start,通常会有短暂的调整大小延迟,但我很高兴能忍受这一点。)

我不相信这个解决方案;我找到了这个代码on the emacs-devel mailing list。

(require 'cl)

;;;; Automatic fitting minor mode
(defcustom doc-view-autofit-timer-start 1.0
  "Initial value (seconds) for the timer that delays the fitting when
`doc-view-autofit-fit' is called (Which is when a window
configuration change occurs and a document needs to be fitted)."
  :type 'number
  :group 'doc-view)

(defcustom doc-view-autofit-timer-inc 0.02
  "Value to increase (seconds) the timer (see `doc-view-autofit-timer-start')
by, if there is another window configuration change occuring, before
it runs out."
  :type 'number
  :group 'doc-view)

(defcustom doc-view-autofit-default-fit 'width
  "The fitting type initially used when mode is enabled.
Valid values are: width, height, page."
  :type 'symbol
  :group 'doc-view)

(defvar doc-view-autofit-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-c W") 'doc-view-autofit-width)
    (define-key map (kbd "C-c H") 'doc-view-autofit-height)
    (define-key map (kbd "C-c P") 'doc-view-autofit-page)
    map)
  "Keymap used by `doc-view-autofit-mode'.")

(defun doc-view-autofit-set (type)
  "Set autofitting to TYPE for current buffer."
  (when doc-view-autofit-mode
    (setq doc-view-autofit-type type)
    (doc-view-autofit-fit)))

(defun doc-view-autofit-width ()
  "Set autofitting to width for current buffer."
  (interactive) (doc-view-autofit-set 'width))

(defun doc-view-autofit-height ()
  "Set autofitting to height for current buffer."
  (interactive) (doc-view-autofit-set 'height))

(defun doc-view-autofit-page ()
  "Set autofitting to page for current buffer."
  (interactive) (doc-view-autofit-set 'page))

(defun doc-view-autofit-fit ()
  "Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
  (lexical-let
      ((window (selected-window)))
    (if (equal doc-view-autofit-timer nil)
        (setq doc-view-autofit-timer
              (run-with-timer
               doc-view-autofit-timer-start nil
               (lambda ()
                 (if (window-live-p window)
                     (save-selected-window
                       (select-window window)
                       (cancel-timer doc-view-autofit-timer)
                       (setq doc-view-autofit-timer nil)
                       (cond
                        ((equal 'width doc-view-autofit-type)
                         (doc-view-fit-width-to-window))
                        ((equal 'height doc-view-autofit-type)
                         (doc-view-fit-height-to-window))
                        ((equal 'page doc-view-autofit-type)
                         (doc-view-fit-page-to-window))))))))
      (timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc))))

(define-minor-mode doc-view-autofit-mode
  "Minor mode for automatic (timer based) fitting in DocView."
  :lighter " AFit" :keymap doc-view-autofit-mode-map :group 'doc-view
  (when doc-view-autofit-mode
    (set (make-local-variable 'doc-view-autofit-type)
         doc-view-autofit-default-fit)
    (set (make-local-variable 'doc-view-autofit-timer) nil)
    (add-hook 'window-configuration-change-hook
              'doc-view-autofit-fit nil t)
    (doc-view-autofit-fit))
  (when (not doc-view-autofit-mode)
    (remove-hook 'window-configuration-change-hook
                 'doc-view-autofit-fit t)
    (when doc-view-autofit-timer
      (cancel-timer doc-view-autofit-timer)
      (setq doc-view-autofit-timer nil))
    (setq doc-view-autofit-type nil)))

(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode)

【讨论】:

使用上述解决方案,我添加了以下两个定义:(defvar doc-view-autofit-timer nil)(defvar doc-view-autofit-type nil)【参考方案2】:

它对我有用:

(add-hook 'doc-view-mode-hook 'doc-view-fit-width-to-window)

更新:如果转换(到 png 或其他内容)仍在进行中(首先打开文档),它将无法正常工作。还有另一种更可靠的方法来处理这种特殊情况(它根本不使用钩子,而是使用建议):

(defadvice doc-view-display (after fit-width activate)
  (doc-view-fit-width-to-window))

【讨论】:

真的吗?你的 Emacs 版本是多少?我仍然无法让它在 Ubuntu 上的 Emacs 24.3 下工作...... 实际上,这似乎适用于 redisplay,例如如果您 C-c C-c 进入编辑模式然后返回。但它在初始显示时对我不起作用。 这仍然给了我相同的行为:它适用于重新显示,但不适用于初始加载。在初始加载时,我得到File mode specification error: (error "Invalid image specification: nil") 您可以通过M-x toggle-debug-on-error 启用调试并显示堆栈吗?当我尝试使用钩子时出现此错误,但有建议我无法重现它。拟合也适用于初始负载。 是的,我收到了this stack trace。在 Ubuntu 14.04 上使用 emacs -Q,Emacs 版本 24.3.50.1。【参考方案3】:

以下是 Chris 对答案的轻微修改——它提供了与 find-file-other-window 等函数的兼容性——例如,当 selected-window 与显示 *.pdf 文件的函数不同时。

(defvar last-displayed-doc-view-buffer nil)

(defun get-last-displayed-doc-view-buffer ()
  (setq last-displayed-doc-view-buffer (current-buffer)))

(add-hook 'doc-view-mode-hook 'get-last-displayed-doc-view-buffer)

(defun doc-view-autofit-fit ()
  "Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
  (if (null doc-view-autofit-timer)
    (setq doc-view-autofit-timer
      (run-with-timer doc-view-autofit-timer-start nil (lambda ()
        (let* (
            (selected-window
              (cond
                ((eq major-mode 'doc-view-mode)
                  (selected-window))
                (t
                  (get-buffer-window last-displayed-doc-view-buffer))))
            (current-buffer
              (cond
                ((eq major-mode 'doc-view-mode)
                  (current-buffer))
                (t
                  (get-buffer last-displayed-doc-view-buffer))))
            (selected-fit
              (when (buffer-live-p (get-buffer current-buffer))
                (with-current-buffer (get-buffer current-buffer)
                  doc-view-autofit-type))) )
          (when (window-live-p selected-window)
            (with-selected-window selected-window
              (when doc-view-autofit-timer (cancel-timer doc-view-autofit-timer))
              (setq doc-view-autofit-timer nil)
              (cond
                ((eq 'width selected-fit)
                  (doc-view-fit-width-to-window))
                ((eq 'height selected-fit)
                  (doc-view-fit-height-to-window))
                ((eq 'page selected-fit)
                  (doc-view-fit-page-to-window)))))))))
    (timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc)))

而且,正如我之前对 Chris 回答的评论中所述,以下变量需要定义:

(defvar doc-view-autofit-timer nil)

(defvar doc-view-autofit-type nil)

因为上面的修改在doc-view-mode-hook中增加了一个新的函数来获取current-buffer,这是函数doc-view-autofit-fit所需要的,所以需要保证后面的函数附加到@的末尾987654329@。所以变化看起来像这样——即,我们为 append 参数添加一个t

(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode t)

克里斯的回答中没有被上述修改取代的所有其他内容仍然有效。


待办事项

创建一个测试以在滚动时检查每个页面,以确保视图与autofit-type 一致。目前,在处理较长的*.pdf 文件时,页面大小会出现错误。

【讨论】:

【参考方案4】:

请注意:(require 'cl) 已过时。由于emacs-24.3应该是

(require ‘cl-lib) 

见http://www.emacswiki.org/emacs/CommonLispForEmacs

【讨论】:

以上是关于使 Emacs 中的文档视图适合页面宽度的主要内容,如果未能解决你的问题,请参考以下文章

如何使自定义的 UITableViewCell xib 宽度适合设备宽度

在GridView AutoGenerateColumns中调整列的宽度以使文本适合页面

如何使 svg 适合 html 的宽度和高度?

使UIImageView适合屏幕宽度但保持纵横比[swift]

如何使列的宽度适合其在 HTML 表格中的内容?

使绝对元素的宽度适合内容