diff --git a/markdown-mode.el b/markdown-mode.el index bcb61fa2..e791584b 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5873,21 +5873,63 @@ buffer. Inverse of `markdown-live-preview-buffer'.") (get-buffer "*eww*")) (error "eww is not present or not loaded on this version of emacs"))) +(defun markdown-visual-lines-between-points (beg end) + (save-excursion + (goto-char beg) + (cl-loop with count = 0 + while (progn (end-of-visual-line) + (and (< (point) end) (line-move-visual 1 t))) + do (cl-incf count) + finally return count))) + (defun markdown-live-preview-window-serialize (buf) "Get window point and scroll data for all windows displaying BUF if BUF is -non-nil." - (when buf - (mapcar (lambda (win) (list win (window-point win) (window-start win))) - (get-buffer-window-list buf)))) +live." + (when (buffer-live-p buf) + (with-current-buffer buf + (mapcar + (lambda (win) + (with-selected-window win + (let* ((start (window-start)) + (pt (window-point)) + (pt-or-sym (cond ((= pt (point-min)) 'min) + ((= pt (point-max)) 'max) + (t pt))) + (diff (markdown-visual-lines-between-points + start pt))) + (message "serialize: start=%d, pt=%d, pt-or-sym=%S, diff=%d" + start pt pt-or-sym diff) + (list win pt-or-sym diff)))) + (get-buffer-window-list buf))))) + +(defun markdown-get-point-back-lines (pt num-lines) + (save-excursion + (goto-char pt) + (line-move-visual (- num-lines) t) + ;; in testing, can occasionally overshoot the number of lines to traverse + (let ((actual-num-lines (markdown-visual-lines-between-points (point) pt))) + (when (> actual-num-lines num-lines) + (line-move-visual (- actual-num-lines num-lines) t))) + (point))) (defun markdown-live-preview-window-deserialize (window-posns) "Apply window point and scroll data from WINDOW-POSNS, given by `markdown-live-preview-window-serialize'." - (cl-destructuring-bind (win pt start) window-posns + (cl-destructuring-bind (win pt-or-sym diff) window-posns (when (window-live-p win) - (set-window-buffer win markdown-live-preview-buffer) - (set-window-point win pt) - (set-window-start win start)))) + (with-current-buffer markdown-live-preview-buffer + (set-window-buffer win (current-buffer)) + (cl-destructuring-bind (actual-pt actual-diff) + (cl-case pt-or-sym + (min (list (point-min) 0)) + (max (list (point-max) diff)) + (t (list pt-or-sym diff))) + (message "deserialize: pt-or-sym=%S, diff=%d" pt-or-sym actual-diff) + (message "point-back-lines: %d" + (markdown-get-point-back-lines actual-pt actual-diff)) + (set-window-start + win (markdown-get-point-back-lines actual-pt actual-diff)) + (set-window-point win actual-pt)))))) (defun markdown-live-preview-export () "Export to XHTML using `markdown-export' and browse the resulting file within diff --git a/tests/markdown-test.el b/tests/markdown-test.el index 1f8cf625..379247f2 100644 --- a/tests/markdown-test.el +++ b/tests/markdown-test.el @@ -3767,25 +3767,30 @@ Detail: https://github.com/jrblevin/markdown-mode/issues/79" (kill-buffer))))) (defadvice markdown-live-preview-window-eww - (around markdown-create-fake-eww disable) + (around markdown-test-create-fake-eww disable) (setq ad-return-value (get-buffer-create "*eww*"))) -(defmacro markdown-temp-eww (&rest body) +(defmacro markdown-test-fake-eww (&rest body) `(progn - ,@(if (featurep 'eww) body + ,@(if (and (fboundp 'libxml-parse-html-region) (require 'eww nil t)) body `((ad-enable-advice #'markdown-live-preview-window-eww - 'around 'markdown-create-fake-eww) + 'around 'markdown-test-create-fake-eww) (ad-activate #'markdown-live-preview-window-eww) ,@body (ad-disable-advice #'markdown-live-preview-window-eww - 'around 'markdown-create-fake-eww) + 'around 'markdown-test-create-fake-eww) (ad-activate #'markdown-live-preview-window-eww))))) +(defmacro markdown-test-eww-or-nothing (test &rest body) + (if (and (fboundp 'libxml-parse-html-region) (require 'eww nil t)) `(progn ,@body) + (message "no eww, or no libxml2 found: skipping %s" test) + nil)) + (ert-deftest test-markdown-ext/live-preview-exports () (markdown-test-temp-file "inline.text" - (unless (require 'eww nil t) + (unless (and (fboundp 'libxml-parse-html-region) (require 'eww nil t)) (should-error (markdown-live-preview-mode))) - (markdown-temp-eww + (markdown-test-fake-eww (markdown-live-preview-mode) (should (buffer-live-p markdown-live-preview-buffer)) (should (eq (current-buffer) @@ -3798,7 +3803,7 @@ Detail: https://github.com/jrblevin/markdown-mode/issues/79" (should (buffer-live-p markdown-live-preview-buffer))))) (ert-deftest test-markdown-ext/live-preview-delete-exports () - (markdown-temp-eww + (markdown-test-fake-eww (let ((markdown-live-preview-delete-export 'delete-on-destroy) file-output) (markdown-test-temp-file "inline.text" @@ -3820,6 +3825,49 @@ Detail: https://github.com/jrblevin/markdown-mode/issues/79" (should (file-exists-p file-output))) (delete-file file-output))))) +(ert-deftest test-markdown-ext/live-preview-follow-min-max () + (markdown-test-eww-or-nothing "live-preview-follow-min-max" + (markdown-test-temp-file "inline.text" + (markdown-live-preview-mode) + (should (buffer-live-p markdown-live-preview-buffer)) + (should (window-live-p (get-buffer-window markdown-live-preview-buffer))) + (with-selected-window (get-buffer-window markdown-live-preview-buffer) + (goto-char (point-min))) + (goto-char (point-min)) + (insert "a test ") + (markdown-live-preview-export) + (let (final-pt final-win-st-diff) + ;; test that still starts at point-min + (with-selected-window (get-buffer-window markdown-live-preview-buffer) + (should (= (window-point) 1)) + (should (= (markdown-visual-lines-between-points + (window-start) (window-point)) + 0)) + (set-window-point (selected-window) (point-max)) + (setq final-pt (window-point) + final-win-st-diff (markdown-visual-lines-between-points + (window-start) (window-point)))) + (goto-char (point-min)) + (insert "this is ") + (markdown-live-preview-export) + (with-selected-window (get-buffer-window markdown-live-preview-buffer) + (should (= (window-point) (+ final-pt (length "this is ")))) + (should (= (markdown-visual-lines-between-points + (window-start) (window-point)) + final-win-st-diff)) + ;; test that still starts at point-max, with correct line difference + (goto-char (floor (/ (float (- (point-max) (point-min))) 2))) + (setq final-pt (window-point) + final-win-st-diff (markdown-visual-lines-between-points + (window-start) final-pt))) + (markdown-live-preview-export) + ;; test that still starts at same point, with correct line difference + (with-selected-window (get-buffer-window markdown-live-preview-buffer) + (should (= (window-point) final-pt)) + (should (= (markdown-visual-lines-between-points + (window-start) (window-point)) + final-win-st-diff))))))) + (provide 'markdown-test) ;;; markdown-test.el ends here