diff --git a/markdown-mode.el b/markdown-mode.el index 1dbd185b..8884e0e2 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -1096,12 +1096,23 @@ update the buffer containing the preview and return the buffer." :type 'function) (defcustom markdown-live-preview-delete-export 'delete-on-destroy - "Delete exported html file when using `markdown-live-preview-export' on every + "Delete exported html file when using `markdown-live-preview-mode' on every export by setting to 'delete-on-export, when quitting `markdown-live-preview-mode' by setting to 'delete-on-destroy, or not at all when nil." :group 'markdown - :type 'symbol) + :type '(symbol :validate markdown-live-preview-validate-delete-export)) + +(defcustom markdown-live-preview-idle-delay 1 + "Delay to wait idle before refreshing `markdown-live-preview-mode' output." + :group 'markdown + :type 'integer) + +(defcustom markdown-live-preview-do-sync nil + "Whether to do live preview exports synchronously on save, or asynchronously +with an idle timer." + :group 'markdown + :type 'boolean) (defcustom markdown-list-indent-width 4 "Depth of indentation for markdown lists. Used in `markdown-demote-list-item' @@ -4610,7 +4621,7 @@ See also `markdown-mode-map'.") ["Export" markdown-export] ["Export & View" markdown-export-and-preview] ["Open" markdown-open] - ["Live Export" markdown-live-preview-mode + ["Live Preview" markdown-live-preview-mode :style toggle :selected markdown-live-preview-mode] ["Kill ring save" markdown-kill-ring-save] "---" @@ -5844,145 +5855,295 @@ current filename, but with the extension removed and replaced with .html." (interactive) (browse-url-of-file (markdown-export))) -(defvar markdown-live-preview-buffer nil - "Buffer used to preview markdown output in `markdown-live-preview-export'.") -(make-variable-buffer-local 'markdown-live-preview-buffer) +(defun markdown-open () + "Open file for the current buffer with `markdown-open-command'." + (interactive) + (if (not markdown-open-command) + (error "Variable `markdown-open-command' must be set") + (if (not buffer-file-name) + (error "Must be visiting a file") + (call-process markdown-open-command + nil nil nil buffer-file-name)))) + +(defun markdown-kill-ring-save () + "Run Markdown on file and store output in the kill ring." + (interactive) + (save-window-excursion + (markdown) + (with-current-buffer markdown-output-buffer-name + (kill-ring-save (point-min) (point-max))))) + + +;;; Live Preview =============================================================== + +(defun markdown-live-preview-validate-delete-export (widget) + (let ((sym (widget-value widget))) + (unless (memq sym '(delete-on-export delete-on-destroy nil)) + (widget-put widget :error (format "Invalid value: '%s'" + (symbol-name sym))) + widget))) + +(defvar markdown-live-preview-view-buffer nil + "Buffer used to preview markdown output in +`markdown-live-preview-sync-export' and `markdown-live-preview-async-export'.") +(make-variable-buffer-local 'markdown-live-preview-view-buffer) (defvar markdown-live-preview-source-buffer nil "Buffer with markdown source generating the source of the current -buffer. Inverse of `markdown-live-preview-buffer'.") +buffer. Inverse of `markdown-live-preview-view-buffer'.") (make-variable-buffer-local 'markdown-live-preview-source-buffer) -(defvar markdown-live-preview-currently-exporting nil) +(defvar markdown-live-preview-currently-exporting-process nil + "Asynchronous process currently running, generated by +`markdown-live-preview-async-export'.") +(make-variable-buffer-local 'markdown-live-preview-currently-exporting-process) -(defun markdown-live-preview-get-filename () - "Standardize the filename exported by `markdown-live-preview-export'." - (markdown-export-file-name ".html")) +(defvar markdown-live-preview-idle-timer nil + "Idle timer updating live previews using +`markdown-live-preview-async-export'.") +(make-variable-buffer-local 'markdown-live-preview-idle-timer) + +(defvar markdown-live-preview-current-buffer-sync-async nil + "Status of sync or async live preview in current buffer.") +(make-variable-buffer-local 'markdown-live-preview-current-buffer-sync-async) + +(defun markdown-live-preview-has-eww-p () + (and (require 'eww nil t) + (fboundp 'libxml-parse-html-region))) (defun markdown-live-preview-window-eww (file) - "A `markdown-live-preview-window-function' for previewing with eww." - (if (require 'eww nil t) + "A `markdown-live-preview-window-function' for previewing with `eww'." + (if (markdown-live-preview-has-eww-p) (progn (eww-open-file file) (get-buffer "*eww*")) (error "eww is not present or not loaded on this version of emacs"))) +(defun markdown-live-preview-link-source-view-buffers (src-buf view-buf) + (with-current-buffer src-buf + (setq markdown-live-preview-view-buffer view-buf)) + (with-current-buffer view-buf + (setq markdown-live-preview-source-buffer src-buf))) + +(defun markdown-live-preview-get-filename () + "Standardize the filename exported by `markdown-live-preview-async-export'." + (markdown-export-file-name ".html")) + +(defun markdown-live-preview-delete-export () + (let ((outfile-name (markdown-live-preview-get-filename))) + (when (and outfile-name (file-exists-p outfile-name)) + (delete-file outfile-name)))) + (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 +alive." + (when (buffer-live-p buf) (mapcar (lambda (win) (list win (window-point win) (window-start win))) (get-buffer-window-list buf)))) -(defun markdown-live-preview-window-deserialize (window-posns) +(defun markdown-live-preview-window-deserialize (window-posns view-buf) "Apply window point and scroll data from WINDOW-POSNS, given by -`markdown-live-preview-window-serialize'." +`markdown-live-preview-window-serialize', displaying VIEW-BUF." (cl-destructuring-bind (win pt start) window-posns (when (window-live-p win) - (set-window-buffer win markdown-live-preview-buffer) + (set-window-buffer win view-buf) (set-window-point win pt) (set-window-start win start)))) -(defun markdown-live-preview-export () +(defun markdown-live-preview-async-cleanup-export (buf msg) + (with-current-buffer buf + (when (eq markdown-live-preview-delete-export 'delete-on-export) + (markdown-live-preview-delete-export)) + (setq markdown-live-preview-currently-exporting-process nil)) + (message msg)) + +(defun markdown-live-preview-get-displaying-window (window-data-list) + (or (caar window-data-list) + ;; if not displaying buf in any window, then make a new window and display + ;; it there + (markdown-display-buffer-other-window (window-buffer)))) + +(defun markdown-live-preview-create-display (out-file &optional src-buf) + (let* ((src-buf (or src-buf (current-buffer))) + (had-view-buffer + (with-current-buffer src-buf markdown-live-preview-view-buffer)) + (window-data-list + (with-current-buffer src-buf + (markdown-live-preview-window-serialize + markdown-live-preview-view-buffer))) + (display-win + (markdown-live-preview-get-displaying-window window-data-list)) + (view-buf + (save-window-excursion + (with-selected-window display-win + (funcall markdown-live-preview-window-function out-file))))) + (markdown-live-preview-link-source-view-buffers src-buf view-buf) + (with-current-buffer view-buf + (add-hook 'kill-buffer-hook #'markdown-live-preview-teardown-view t t)) + (with-current-buffer src-buf + (if had-view-buffer + (if window-data-list + (cl-loop for window-data in window-data-list + do (markdown-live-preview-window-deserialize + window-data view-buf)) + (delete-window display-win)) + (set-window-buffer display-win view-buf))))) + +(defun markdown-live-preview-async-create-view-display (src-buf out-file msg) + (unwind-protect + (markdown-live-preview-create-display out-file src-buf) + (markdown-live-preview-async-cleanup-export src-buf msg))) + +(defun markdown-live-preview-do-sentinel (src-buf out-file proc) + (unless (or (process-live-p proc) + (not (buffer-live-p src-buf))) + (let ((cur-msg (current-message)) + (proc-buf (process-buffer proc))) + (kill-buffer proc-buf) + (markdown-live-preview-async-create-view-display + src-buf out-file cur-msg)))) + +(defun markdown-live-preview-make-async-sentinel (src-buf out-file) + (lambda (proc _) (markdown-live-preview-do-sentinel src-buf out-file proc))) + +(defconst markdown-live-preview-proc-name "*markdown-live-preview*") +(defconst markdown-live-preview-buf-name "*markdown-live-preview-output*") + +(defun markdown-live-preview-async-export () + (interactive) + (unless markdown-live-preview-currently-exporting-process + (let* ((cur-buf (current-buffer)) + (mode major-mode) + (out-file (markdown-live-preview-get-filename)) + (sentinel (markdown-live-preview-make-async-sentinel + cur-buf out-file)) + (proc + (start-process-shell-command + markdown-live-preview-proc-name markdown-live-preview-buf-name + ;; using redirection means emacs doesn't have to process output, + ;; which interrupts the user less + (concat + markdown-command " " + (and markdown-command-needs-filename + (if (buffer-file-name) + (shell-quote-argument (buffer-file-name)) + (user-error "Must be visiting a file"))) + " > " (shell-quote-argument out-file))))) + (setq markdown-live-preview-currently-exporting-process proc) + (set-process-sentinel proc sentinel) + (with-temp-buffer + (let ((tmp-buf (current-buffer))) + (with-current-buffer cur-buf + (copy-to-buffer tmp-buf (point-min) (point-max)))) + (funcall mode) + (run-hooks 'markdown-before-export-hook) + (process-send-region proc (point-min) (point-max)) + (process-send-eof proc) + (run-hooks 'markdown-after-export-hook) + proc)))) + +(defvar markdown-live-preview-currently-exporting nil) + +(defun markdown-live-preview-sync-export () "Export to XHTML using `markdown-export' and browse the resulting file within Emacs using `markdown-live-preview-window-function' Return the buffer displaying the rendered output." (interactive) (let* ((markdown-live-preview-currently-exporting t) - (cur-buf (current-buffer)) - (export-file (markdown-export (markdown-live-preview-get-filename))) - ;; get positions in all windows currently displaying output buffer - (window-data - (markdown-live-preview-window-serialize - markdown-live-preview-buffer))) - (save-window-excursion - (let ((output-buffer - (funcall markdown-live-preview-window-function export-file))) - (with-current-buffer output-buffer - (setq markdown-live-preview-source-buffer cur-buf) - (add-hook 'kill-buffer-hook - #'markdown-live-preview-remove-on-kill t t)) - (with-current-buffer cur-buf - (setq markdown-live-preview-buffer output-buffer)))) - (with-current-buffer cur-buf - ;; reset all windows displaying output buffer to where they were, - ;; now with the new output - (mapc #'markdown-live-preview-window-deserialize window-data) - ;; delete html editing buffer - (let ((buf (get-file-buffer export-file))) (when buf (kill-buffer buf))) - (when (and export-file (file-exists-p export-file) - (eq markdown-live-preview-delete-export - 'delete-on-export)) - (delete-file export-file)) - markdown-live-preview-buffer))) - -(defun markdown-live-preview-remove () - (when (buffer-live-p markdown-live-preview-buffer) - (kill-buffer markdown-live-preview-buffer)) - (setq markdown-live-preview-buffer nil) + (out-file (markdown-export (markdown-live-preview-get-filename)))) + (markdown-live-preview-create-display out-file) + ;; delete html editing buffer + (let ((buf (get-file-buffer out-file))) + (when buf (kill-buffer buf))) + (when (and out-file (file-exists-p out-file) + (eq markdown-live-preview-delete-export + 'delete-on-export)) + (delete-file out-file)) + markdown-live-preview-view-buffer)) + +(defun markdown-live-preview-update (buf) + (lambda () (with-current-buffer buf (markdown-live-preview-async-export)))) + +(defun markdown-live-preview-setup () + (setq markdown-live-preview-current-buffer-sync-async + markdown-live-preview-do-sync) + (add-hook 'kill-buffer-hook #'markdown-live-preview-teardown-source t t) + (if markdown-live-preview-current-buffer-sync-async + (progn + (add-hook + 'after-save-hook #'markdown-live-preview-do-sync-preview t t) + (markdown-live-preview-sync-export)) + (setq markdown-live-preview-idle-timer + (run-with-idle-timer + markdown-live-preview-idle-delay t + (markdown-live-preview-update (current-buffer)))) + (markdown-live-preview-async-export))) + +(defun markdown-live-preview-teardown-view () + (with-current-buffer markdown-live-preview-source-buffer + (setq markdown-live-preview-view-buffer nil)) + (setq markdown-live-preview-source-buffer nil)) + +(defun markdown-live-preview-teardown-async () + (when (buffer-live-p markdown-live-preview-view-buffer) + ;; calls `kill-buffer-hook' within `markdown-live-preview-view-buffer' + (kill-buffer markdown-live-preview-view-buffer)) + (when (and markdown-live-preview-currently-exporting-process + (process-live-p markdown-live-preview-currently-exporting-process)) + (set-process-sentinel markdown-live-preview-currently-exporting-process nil) + (delete-process markdown-live-preview-currently-exporting-process)) + (setq markdown-live-preview-view-buffer nil + markdown-live-preview-currently-exporting-process nil) + ;; if set to 'delete-on-export, the output has already been deleted + (when (eq markdown-live-preview-delete-export 'delete-on-destroy) + (markdown-live-preview-delete-export)) + (when markdown-live-preview-idle-timer + (cancel-timer markdown-live-preview-idle-timer) + (setq markdown-live-preview-idle-timer nil)) + (remove-hook 'kill-buffer-hook #'markdown-live-preview-teardown-source t)) + +(defun markdown-live-preview-teardown-sync () + (when (buffer-live-p markdown-live-preview-view-buffer) + (kill-buffer markdown-live-preview-view-buffer)) + (setq markdown-live-preview-view-buffer nil) + (remove-hook 'after-save-hook #'markdown-live-preview-do-sync-preview t) ;; if set to 'delete-on-export, the output has already been deleted (when (eq markdown-live-preview-delete-export 'delete-on-destroy) (let ((outfile-name (markdown-live-preview-get-filename))) (when (file-exists-p outfile-name) (delete-file outfile-name))))) +(defun markdown-live-preview-teardown-source () + (if markdown-live-preview-current-buffer-sync-async + (markdown-live-preview-teardown-sync) + (markdown-live-preview-teardown-async))) + (defun markdown-display-buffer-other-window (buf) - (let ((cur-buf (current-buffer))) - (switch-to-buffer-other-window buf) - (set-buffer cur-buf))) - -(defun markdown-live-preview-if-markdown () - (when (and (derived-mode-p 'markdown-mode) - markdown-live-preview-mode) - (unless markdown-live-preview-currently-exporting - (if (buffer-live-p markdown-live-preview-buffer) - (markdown-live-preview-export) - (markdown-display-buffer-other-window - (markdown-live-preview-export)))))) - -(defun markdown-live-preview-remove-on-kill () - (cond ((and (derived-mode-p 'markdown-mode) - markdown-live-preview-mode) - (markdown-live-preview-remove)) - (markdown-live-preview-source-buffer - (with-current-buffer markdown-live-preview-source-buffer - (setq markdown-live-preview-buffer nil)) - (setq markdown-live-preview-source-buffer nil)))) + (let ((pop-up-windows t)) + (select-window (display-buffer buf t)))) (defun markdown-live-preview-switch-to-output () (interactive) "Turn on `markdown-live-preview-mode' if not already on, and switch to its output buffer in another window." (if markdown-live-preview-mode - (markdown-display-buffer-other-window (markdown-live-preview-export))) + (markdown-display-buffer-other-window markdown-live-preview-view-buffer)) (markdown-live-preview-mode)) (defun markdown-live-preview-re-export () (interactive) "If the current buffer is a buffer displaying the exported version of a -`markdown-live-preview-mode' buffer, call `markdown-live-preview-export' and -update this buffer's contents." +`markdown-live-preview-mode' buffer, call `markdown-live-preview-async-export' +or `markdown-live-preview-sync-export' and update this buffer's contents." (when markdown-live-preview-source-buffer (with-current-buffer markdown-live-preview-source-buffer - (markdown-live-preview-export)))) - -(defun markdown-open () - "Open file for the current buffer with `markdown-open-command'." - (interactive) - (if (not markdown-open-command) - (error "Variable `markdown-open-command' must be set") - (if (not buffer-file-name) - (error "Must be visiting a file") - (call-process markdown-open-command - nil nil nil buffer-file-name)))) + (if markdown-live-preview-current-buffer-sync-async + (markdown-live-preview-sync-export) + (markdown-live-preview-async-export))))) -(defun markdown-kill-ring-save () - "Run Markdown on file and store output in the kill ring." - (interactive) - (save-window-excursion - (markdown) - (with-current-buffer markdown-output-buffer-name - (kill-ring-save (point-min) (point-max))))) +(defun markdown-live-preview-do-sync-preview () + (unless markdown-live-preview-currently-exporting + (markdown-live-preview-sync-export))) ;;; Links ===================================================================== @@ -6508,10 +6669,6 @@ before regenerating font-lock rules for extensions." (add-hook 'window-configuration-change-hook 'markdown-fontify-buffer-wiki-links t t) - ;; add live preview export hook - (add-hook 'after-save-hook #'markdown-live-preview-if-markdown t t) - (add-hook 'kill-buffer-hook #'markdown-live-preview-remove-on-kill t t) - ;; do the initial link fontification (markdown-fontify-buffer-wiki-links)) @@ -6550,13 +6707,14 @@ before regenerating font-lock rules for extensions." (markdown-gfm-parse-buffer-for-languages)) -;;; Live Preview Mode ============================================ +;;; Live Preview Mode ========================================================= (define-minor-mode markdown-live-preview-mode "Toggle native previewing on save for a specific markdown file." + :group 'markdown-mode :lighter " MD-Preview" (if markdown-live-preview-mode - (markdown-display-buffer-other-window (markdown-live-preview-export)) - (markdown-live-preview-remove))) + (markdown-live-preview-setup) + (markdown-live-preview-teardown-source))) (provide 'markdown-mode) diff --git a/tests/markdown-test.el b/tests/markdown-test.el index c61127d7..d8352882 100644 --- a/tests/markdown-test.el +++ b/tests/markdown-test.el @@ -3739,7 +3739,7 @@ Detail: https://github.com/jrblevin/markdown-mode/issues/79" (defmacro markdown-temp-eww (&rest body) `(progn - ,@(if (featurep 'eww) body + ,@(if (markdown-live-preview-has-eww-p) body `((ad-enable-advice #'markdown-live-preview-window-eww 'around 'markdown-create-fake-eww) (ad-activate #'markdown-live-preview-window-eww) @@ -3748,45 +3748,163 @@ Detail: https://github.com/jrblevin/markdown-mode/issues/79" 'around 'markdown-create-fake-eww) (ad-activate #'markdown-live-preview-window-eww))))) -(ert-deftest test-markdown-ext/live-preview-exports () +(defun markdown-test/live-preview-wait () + (unless markdown-live-preview-current-buffer-sync-async + (sit-for (* markdown-live-preview-idle-delay 10)) + (accept-process-output + markdown-live-preview-currently-exporting-process nil nil t))) + +(defun markdown-test/live-preview-exports () (markdown-test-temp-file "inline.text" - (unless (require 'eww nil t) - (should-error (markdown-live-preview-mode))) - (markdown-temp-eww - (markdown-live-preview-mode) - (should (buffer-live-p markdown-live-preview-buffer)) - (should (eq (current-buffer) - (with-current-buffer markdown-live-preview-buffer - markdown-live-preview-source-buffer))) - (kill-buffer markdown-live-preview-buffer) - (should (null markdown-live-preview-buffer)) - (set-buffer-modified-p t) - (save-buffer) ; should create new export - (should (buffer-live-p markdown-live-preview-buffer))))) - -(ert-deftest test-markdown-ext/live-preview-delete-exports () - (markdown-temp-eww - (let ((markdown-live-preview-delete-export 'delete-on-destroy) - file-output) - (markdown-test-temp-file "inline.text" - (markdown-live-preview-mode) - (setq file-output (markdown-export-file-name))) - (should-not (file-exists-p file-output))) - (let ((markdown-live-preview-delete-export 'delete-on-export) - file-output) - (markdown-test-temp-file "inline.text" + (let ((markdown-live-preview-idle-delay .01)) + (markdown-temp-eww (markdown-live-preview-mode) - (setq file-output (markdown-export-file-name)) - (should-not (file-exists-p file-output)))) - (let ((markdown-live-preview-delete-export nil) - file-output) + (markdown-test/live-preview-wait) + (should (buffer-live-p markdown-live-preview-view-buffer)) + (should (eq (current-buffer) + (with-current-buffer markdown-live-preview-view-buffer + markdown-live-preview-source-buffer))) + (kill-buffer markdown-live-preview-view-buffer) + (should (null markdown-live-preview-view-buffer)) + (if markdown-live-preview-current-buffer-sync-async + (markdown-live-preview-sync-export) + (markdown-live-preview-async-export) + (markdown-test/live-preview-wait)) + (should (buffer-live-p markdown-live-preview-view-buffer)))))) + +(ert-deftest test-markdown-ext/live-preview-exports-sync () + (let ((markdown-live-preview-do-sync t)) + (unless (markdown-live-preview-has-eww-p) + (should-error (markdown-live-preview-sync-export))) + (markdown-test/live-preview-exports))) + +(ert-deftest test-markdown-ext/live-preview-exports-async () + (markdown-test/live-preview-exports)) + +(defun markdown-test/live-preview-delete-exports () + (let ((markdown-live-preview-idle-delay .01) + file-output) + (markdown-temp-eww + (let ((markdown-live-preview-delete-export 'delete-on-destroy)) + (markdown-test-temp-file "inline.text" + (markdown-live-preview-mode) + (markdown-test/live-preview-wait) + (setq file-output (markdown-export-file-name))) + (should-not (file-exists-p file-output))) + (let ((markdown-live-preview-delete-export 'delete-on-export)) + (markdown-test-temp-file "inline.text" + (markdown-live-preview-mode) + (markdown-test/live-preview-wait) + (setq file-output (markdown-export-file-name)) + (should-not (file-exists-p file-output)))) (unwind-protect (markdown-test-temp-file "inline.text" (markdown-live-preview-mode) + (markdown-test/live-preview-wait) (setq file-output (markdown-export-file-name)) + (setq markdown-live-preview-delete-export nil) (should (file-exists-p file-output))) (delete-file file-output))))) +(ert-deftest test-markdown-ext/live-preview-delete-exports-sync () + (let ((markdown-live-preview-do-sync t)) + (markdown-test/live-preview-delete-exports))) + +(ert-deftest test-markdown-ext/live-preview-delete-exports-async () + (markdown-test/live-preview-delete-exports)) + +(defvar markdown-test-eww-window nil) +(defvar markdown-test-hit-advice nil) + +(defadvice eww-open-file (before markdown-test-set-window-width disable) + (setq markdown-test-hit-advice t) + (should (eq (selected-window) markdown-test-eww-window))) + +(defadvice get-buffer-create (before markdown-set-window-width-mock disable) + (when (let ((buf (ad-get-arg 0))) (and (stringp buf) (string= buf "*eww*"))) + (setq markdown-test-hit-advice t) + (should (eq (selected-window) markdown-test-eww-window)))) + +(defmacro markdown-eww-open-file-advice (&rest body) + (if (markdown-live-preview-has-eww-p) + `(progn + (ad-enable-advice #'eww-open-file 'before + 'markdown-test-set-window-width) + (ad-activate #'eww-open-file) + ,@body + (ad-disable-advice #'eww-open-file 'before + 'markdown-test-set-window-width) + (ad-activate #'eww-open-file)) + `(progn + (ad-enable-advice #'get-buffer-create 'before + 'markdown-set-window-width-mock) + (ad-activate #'get-buffer-create) + ,@body + (ad-disable-advice #'get-buffer-create 'before + 'markdown-set-window-width-mock) + (ad-activate #'get-buffer-create)))) + +(defadvice markdown-live-preview-get-displaying-window + (after markdown-test-get-test-window disable) + (setq markdown-test-eww-window ad-return-value)) + +(defmacro markdown-initial-window-create-advice (&rest body) + `(progn + (ad-enable-advice #'markdown-live-preview-get-displaying-window + 'after 'markdown-test-get-test-window) + (ad-activate #'markdown-live-preview-get-displaying-window) + ,@body + (ad-disable-advice #'markdown-live-preview-get-displaying-window + 'after 'markdown-test-get-test-window) + (ad-activate #'markdown-live-preview-get-displaying-window))) + +(defun markdown-test/test-window-usage-live-preview () + (setq markdown-test-hit-advice nil) + (save-window-excursion + (markdown-test-temp-file "inline.text" + (let ((markdown-live-preview-idle-delay .01) + (windows (window-list)) + (md-buf (current-buffer))) + (cl-loop for win in windows + unless (eq win (selected-window)) + do (delete-window win)) + ;; note that advices are used in this test to supply `should' conditions + (markdown-temp-eww + ;; test that first window created by + ;; `markdown-live-preview-get-displaying-window' is the same window + ;; that is used to finally render the buffer, on the first try + (markdown-eww-open-file-advice + (markdown-initial-window-create-advice + (if markdown-live-preview-do-sync + (markdown-live-preview-sync-export) + (markdown-live-preview-async-export) + (markdown-test/live-preview-wait)) + (should (eq t markdown-test-hit-advice)) + (setq markdown-test-hit-advice nil)) + (setq markdown-test-eww-window + (get-buffer-window (get-buffer "*eww*"))) + (should markdown-live-preview-view-buffer) + (with-selected-window (get-buffer-window md-buf) + (if markdown-live-preview-do-sync + (markdown-live-preview-sync-export) + (markdown-live-preview-async-export) + (markdown-test/live-preview-wait)) + ;; at this point, `eww-render' should have finished, and eww should + ;; have redisplayed. the advice checks that, since there was a + ;; single window displaying the *eww* buffer, that window was used + ;; as the selected window so that eww renders with a width + ;; equal to the width of its window + (should (eq t markdown-test-hit-advice)))))))) + (setq markdown-test-hit-advice nil)) + +(ert-deftest test-markdown-ext/live-preview-window-size-sync () + (let ((markdown-live-preview-do-sync t)) + (markdown-test/test-window-usage-live-preview))) + +(ert-deftest test-markdown-ext/live-preview-window-size-async () + (let ((markdown-live-preview-do-sync nil)) + (markdown-test/test-window-usage-live-preview))) + (provide 'markdown-test) ;;; markdown-test.el ends here