Emacs — calculating new window-start/end without redisplay

谁说胖子不能爱 提交于 2019-11-30 05:30:13

问题


Is it possible to calculate a new window-start/end without a redisplay occurring? If so, then an example would be greatly appreciated. If not, then what is the best way to approximate it?

Example:  We want to move to a new area of the buffer somewhere off screen, and place overlays when we get there. We might be using page-down or scroll-down or paragraph-down or end-of-buffer. When we get to that new point, we want to calculate the new window-start and the new window-end. However, we want to avoid a momentary naked looking buffer without any overlays. Ideally, the redisplay would occur once those overlays are added. I want to restrict new overlays to the new region based upon the new window-start/end.

  • Point-Min:  point = 1

  • Old Window Start:  point = 1000

  • Old Window End:  point = 1500

  • New Window Start:  point = 3500

  • New Window End: point = 4000

  • Point-Max:  point = 6000

Problem: When using the post-command-hook to try and calculate the new window-start and new window-end, the previous display positions are being used instead -- i.e., the old window-start and the old window-end.


Here is a sample of the project I am working on. Absent fixing the window-start \ window-end problem, I get the following error:

Error in post-command-hook (my-eol-ruler-function):   (error "Invalid search bound (wrong side of point)")`. 

The error happens when going from (point-min) to the end of the buffer with the interactive function end-of-buffer. In the context of this error, (point-max) is beyond the old window-end.


EDIT:  Updated code to include a message: (message "point: %s | window-start: %s | window-end: %s | point-max: %s" (point) (window-start) (window-end) (point-max) ). The message is used to demonstrate that the new window-start and new window-end are not calculated within the post-command-hook because a redisplay has not yet occurred. However, I am trying to avoid a redisplay until after the new overlays have been placed -- otherwise, a naked buffer without overlays is visible for a split second.


(defvar my-eol-ruler nil "A horizontal ruler stretching from eol (end of line) to the window edge.") (make-variable-buffer-local 'my-eol-ruler)  (defvar my-eol-pilcrow nil "A pilcrow symbol placed at the end of every line except the current line.") (make-variable-buffer-local 'my-eol-pilcrow)  (defun my-eol-ruler-function ()   (let* (     (opoint (point))     (window-width (window-width))     (window-start (window-start))     (window-end (window-end))     (col-eovl       (save-excursion         (vertical-motion 1)         (skip-chars-backward " \r\n" (- (point) 1))         (- (current-column) (progn (vertical-motion 0) (current-column)))))     (my-current-line-length (- (- window-width col-eovl) 3))     (pilcrow       (propertize (char-to-string ?\u00B6)         'face '(:foreground "white")         'cursor t))     (pilcrow-underlined       (propertize (char-to-string ?\u00B6)         'face '(:foreground "white" :underline "yellow")         'cursor t))     (underline (propertize (char-to-string ?\u2009)           'display `(space :width ,my-current-line-length)           'face '(:underline "yellow")           'cursor t)))   (when (or my-eol-ruler my-eol-pilcrow)     (dolist (description `(         ,my-eol-ruler         ,my-eol-pilcrow ))       (remove-overlays (point-min) (point-max)         'after-string description)) )   (setq my-eol-ruler (concat pilcrow-underlined underline))   (setq my-eol-pilcrow pilcrow)   (save-excursion     (end-of-line)     (overlay-put (make-overlay (point) (point))       'after-string my-eol-ruler ) )   (message "point:  %s | window-start:  %s | window-end:  %s | point-max:  %s"     (point)     (window-start)     (window-end)     (point-max) )   (save-excursion     (goto-char window-end)     (while (re-search-backward "\n" window-start t)       (let* (           (pbol (point-at-bol))           (pbovl (save-excursion (vertical-motion 0) (point)))           (peol (point))           (peol-pbol-region-p             (if (region-active-p)               (= peol pbol)))           (eol-inside-region-p             (if (region-active-p)               (and                 (<= reg-beg peol)                 (> reg-end peol))))           (col-eovl             (save-excursion               (vertical-motion 1)               (skip-chars-backward " \r\n" (- (point) 1))               (- (current-column) (progn (vertical-motion 0) (current-column)))))           (my-last-column (current-column))           (window-width-bug-p (= my-last-column (- window-width 1)))           (shazbot-pbol             (save-excursion               (end-of-line)               (re-search-backward "\s\\|\t" pbol t) (+ (point) 1)))           (wrapped-window-width-bug-p (= col-eovl (- window-width 1))) )         (when           (or             (< opoint pbol)             (> opoint peol))         (overlay-put (make-overlay peol peol) 'after-string my-eol-pilcrow))))) ))  (add-hook 'post-command-hook 'my-eol-ruler-function) 

Beginning of the buffer, before the error occurs.


End of the buffer -- the error occurs when executing the interactive function end-of-buffer from a point at the beginning of the buffer.

Error in post-command-hook (my-eol-ruler-function):   (error "Invalid search bound (wrong side of point)") 


回答1:


See also Emacs bug tracker feature request #22404 (which has not yet been implemented, but the mailing archive contains a rough draft rudimentary patch that creates a new hook for this specific issue): https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22404

  • Minor-mode for testing window-start and window-end BEFORE visual redisplay.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; test-mode ;; A minor-mode for testing `window-start` / `window-end` BEFORE visual redisplay.  (defvar test-this-command nil "This local variable is set within the `post-command-hook`; and, is also used by the `window-scroll-functions` hook.") (make-variable-buffer-local 'test-this-command)  (defun test-post-command-hook-fn () "A function attached to the `post-command-hook`."   (setq test-this-command this-command)   (test-demo-fn))  (defun test-window-scroll-functions-fn (win _start) "A function attached to the `window-scroll-functions` hook."   (test-demo-fn))  (defun test-demo-fn () "This is a test-mode demonstration function."   (when       (and         test-mode         test-this-command         (window-live-p (get-buffer-window (current-buffer)))         (not (minibufferp))         (pos-visible-in-window-p (point)           (get-buffer-window (current-buffer) (selected-frame)) t))     (let* (         (selected-window (selected-window))         (window-start (window-start selected-window))         (window-end (window-end selected-window t)) )       (message "window-start: %s | window-end: %s" window-start window-end)       (setq test-this-command nil) )))  (define-minor-mode test-mode "A minor-mode for testing `window-start` / `window-end` BEFORE visual redisplay."   :init-value nil   :lighter " TEST"   :keymap nil   :global nil   :group nil   (cond     (test-mode       (set (make-local-variable 'scroll-conservatively) 101)       (add-hook 'post-command-hook 'test-post-command-hook-fn nil t)       (add-hook 'window-scroll-functions 'test-window-scroll-functions-fn nil t)       (when (called-interactively-p 'any)         (message "Turned ON `test-mode`.")))     (t       (kill-local-variable 'scroll-conservatively)       (kill-local-variable 'test-this-command)       (remove-hook 'post-command-hook 'test-post-command-hook-fn t)       (remove-hook 'window-scroll-functions 'test-window-scroll-functions-fn t)       (when (called-interactively-p 'any)         (message "Turned OFF `test-mode`.") ))))  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 



回答2:


Offhand, I'd say that the error is raised because you pass a BOUND arg to a search function. For example:

(re-search-backward "\n" window-start t)  (re-search-backward "\s\\|\t" pbol t) 

Check your values of window-start and pbol. Remember that when you search backward the bound must not be greater than the current position (point).




回答3:


I think you want to use jit-lock-register instead of post-command-hook. This way, the redisplay code will call you back once it has decided of a window-start and you'll be able to add the overlays you want before the buffer's content is displayed.



来源:https://stackoverflow.com/questions/23923371/emacs-calculating-new-window-start-end-without-redisplay

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!