Emacs - вычисление нового окна-начала/конца без повторного отображения

Можно ли вычислить новый оконный старт/конец без повторного отображения? Если да, то пример будет очень признателен. Если нет, то каков наилучший способ его аппроксимации?

Пример. Мы хотим переместиться в новую область буфера где-то за пределами экрана и поместить наложения, когда мы туда доберемся. Мы могли бы использовать прокрутку вниз или прокрутку вниз или абзац вниз или конец буфера. Когда мы доберемся до этой новой точки, мы хотим вычислить новый window-start и новый window-end. Тем не менее, мы хотим избежать мгновенного обнаженного буфера без каких-либо наложений. В идеале повторное отображение произойдет после добавления этих оверлеев. Я хочу ограничить новые накладки новым регионом на основе нового окна-начала/конца.

  • Point-Min: point = 1

  • Старое окно Начало: точка = 1000

  • Старый конец окна: точка = 1500

  • Новое окно Start: point = 3500

  • Конец нового окна: точка = 4000

  • Точка-Макс: точка = 6000

Проблема. При использовании post-command-hook to try и вычисления нового window-start и нового window-end вместо этого используются предыдущие позиции отображения - т.е. старый window-start и старый window-end.

Вот пример проекта, над которым я работаю. При отсутствии проблемы window-start\window-end я получаю следующую ошибку:

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

Ошибка происходит при переходе от (point-min) к концу буфера с помощью интерактивной функции end-of-buffer. В контексте этой ошибки (point-max) находится за пределами старого window-end.

EDIT: обновлен код для включения сообщения: (message "point: %s | window-start: %s | window-end: %s | point-max: %s" (point) (window-start) (window-end) (point-max) ). Это сообщение используется для демонстрации того, что новый window-start и новый window-end не вычисляются в post-command-hook, потому что повторное отображение еще не произошло. Тем не менее, я стараюсь избегать повторного отображения до тех пор, пока не будут размещены новые накладки - в противном случае голый буфер без наложений будет отображаться в течение секунды.

(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)

Начало буфера перед ошибкой.

Конец буфера - ошибка возникает при выполнении интерактивной функции end-of-buffer из точки в начале буфера.

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

3 ответа

См. также запрос функции отслеживания ошибок Emacs # 22404 (который еще не реализован, но в почтовом архиве содержится черновик рудиментарного патча, который создает новый крючок для этой конкретной проблемы): https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22404

  • Незначительный режим для тестирования window-start и window-end ПЕРЕД ПЕРВЫМ визуальным отображением.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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`.") ))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Я думаю, вы хотите использовать jit-lock-register вместо post-command-hook. Таким образом, код повторного отображения перезвонит вам после того, как он примет решение о запуске окна, и вы сможете добавить наложения, которые вы хотите, до отображения содержимого буфера.


Оффлайн, я бы сказал, что ошибка возникает из-за того, что вы передаете аргумент BOUND в функцию поиска. Например:

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

Проверьте значения window-start и pbol. Помните, что при поиске назад граница не должна превышать текущую позицию (точку).

licensed under cc by-sa 3.0 with attribution.