Files
emacs/lisp/emacs-application-framework/app/org-previewer/eaf-org-previewer.el
2022-01-04 15:21:47 +01:00

267 lines
8.6 KiB
EmacsLisp

;;; eaf-org-previewer.el --- Org previewer
;; Filename: eaf-org-previewer.el
;; Description: Org previewer
;; Author: Andy Stewart <lazycat.manatee@gmail.com>
;; Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
;; Copyright (C) 2021, Andy Stewart, all rights reserved.
;; Created: 2021-08-01 10:23:59
;; Version: 0.1
;; Last-Updated: 2021-08-01 10:23:59
;; By: Andy Stewart
;; URL: http://www.emacswiki.org/emacs/download/eaf-org-previewer.el
;; Keywords:
;; Compatibility: GNU Emacs 28.0.50
;;
;; Features that might be required by this library:
;;
;;
;;
;;; This file is NOT part of GNU Emacs
;;; License
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; Org previewer
;;
;;; Installation:
;;
;; Put eaf-org-previewer.el to your load-path.
;; The load-path is usually ~/elisp/.
;; It's set in your ~/.emacs like this:
;; (add-to-list 'load-path (expand-file-name "~/elisp"))
;;
;; And the following to your ~/.emacs startup file.
;;
;; (require 'eaf-org-previewer)
;;
;; No need more.
;;; Customize:
;;
;;
;;
;; All of the above can customize by:
;; M-x customize-group RET eaf-org-previewer RET
;;
;;; Change log:
;;
;; 2021/08/01
;; * First released.
;;
;;; Acknowledgements:
;;
;;
;;
;;; TODO
;;
;;
;;
;;; Require
(require 'ox-html)
;;; Code:
(defcustom eaf-org-previewer-keybinding
'(("C--" . "zoom_out")
("C-=" . "zoom_in")
("C-0" . "zoom_reset")
("C-s" . "search_text_forward")
("C-r" . "search_text_backward")
("C-n" . "scroll_up")
("C-p" . "scroll_down")
("C-f" . "scroll_right")
("C-b" . "scroll_left")
("C-v" . "scroll_up_page")
("C-y" . "yank_text")
("C-w" . "kill_text")
("M-e" . "atomic_edit")
("M-c" . "caret_toggle_browsing")
("M-D" . "select_text")
("M-s" . "open_link")
("M-S" . "open_link_new_buffer")
("M-B" . "open_link_background_buffer")
("C-/" . "undo_action")
("M-_" . "redo_action")
("M-w" . "copy_text")
("M-f" . "history_forward")
("M-b" . "history_backward")
("M-q" . "clear_cookies")
("C-t" . "toggle_password_autofill")
("C-d" . "save_page_password")
("M-a" . "toggle_adblocker")
("C-M-q" . "clear_history")
("C-M-i" . "import_chrome_history")
("M-v" . "scroll_down_page")
("M-<" . "scroll_to_begin")
("M->" . "scroll_to_bottom")
("M-p" . "duplicate_page")
("M-t" . "new_blank_page")
("M-d" . "toggle_dark_mode")
("SPC" . "insert_or_scroll_up_page")
("J" . "insert_or_select_left_tab")
("K" . "insert_or_select_right_tab")
("j" . "insert_or_scroll_up")
("k" . "insert_or_scroll_down")
("h" . "insert_or_scroll_left")
("l" . "insert_or_scroll_right")
("f" . "insert_or_open_link")
("F" . "insert_or_open_link_new_buffer")
("B" . "insert_or_open_link_background_buffer")
("c" . "insert_or_caret_at_line")
("u" . "insert_or_scroll_down_page")
("d" . "insert_or_scroll_up_page")
("H" . "insert_or_history_backward")
("L" . "insert_or_history_forward")
("t" . "insert_or_new_blank_page")
("T" . "insert_or_recover_prev_close_page")
("i" . "insert_or_focus_input")
("I" . "insert_or_open_downloads_setting")
("r" . "insert_or_refresh_page")
("g" . "insert_or_scroll_to_begin")
("x" . "insert_or_close_buffer")
("G" . "insert_or_scroll_to_bottom")
("-" . "insert_or_zoom_out")
("=" . "insert_or_zoom_in")
("0" . "insert_or_zoom_reset")
("m" . "insert_or_save_as_bookmark")
("o" . "insert_or_open_browser")
("y" . "insert_or_download_youtube_video")
("Y" . "insert_or_download_youtube_audio")
("p" . "insert_or_toggle_device")
("P" . "insert_or_duplicate_page")
("1" . "insert_or_save_as_pdf")
("2" . "insert_or_save_as_single_file")
("3" . "insert_or_save_as_screenshot")
("v" . "insert_or_view_source")
("e" . "insert_or_edit_url")
("n" . "insert_or_export_text")
("," . "insert_or_switch_to_reader_mode")
("." . "insert_or_translate_text")
(";" . "insert_or_translate_page")
("C-M-c" . "copy_code")
("C-M-l" . "copy_link")
("C-a" . "select_all_or_input_text")
("M-u" . "clear_focus")
("C-j" . "open_downloads_setting")
("M-o" . "eval_js")
("M-O" . "eval_js_file")
("<escape>" . "eaf-browser-send-esc-or-exit-fullscreen")
("M-," . "eaf-send-down-key")
("M-." . "eaf-send-up-key")
("M-m" . "eaf-send-return-key")
("<f5>" . "refresh_page")
("<f12>" . "open_devtools")
("<C-return>" . "eaf-send-ctrl-return-sequence")
)
"The keybinding of EAF Org Previewer."
:type 'cons)
(defcustom eaf-org-dark-mode "follow"
""
:type 'string)
(defcustom eaf-org-extension-list
'("org")
"The extension list of org previewer application."
:type 'cons)
(defvar eaf-org-file-list '())
(defvar eaf-org-killed-file-list '())
(defun eaf--org-delete-preview-file (org-file)
"Delete the org-preview file when given ORG-FILE name."
(let ((org-html-file (concat (file-name-sans-extension org-file) ".html")))
(when (file-exists-p org-html-file)
(delete-file org-html-file)
(message "[EAF] Cleaned org-preview file %s (%s)." org-html-file org-file))))
(defun eaf--org-killed-buffer-clean ()
"Function cleaning the killed org buffer."
(dolist (org-killed-buffer eaf-org-killed-file-list)
(unless (get-file-buffer org-killed-buffer)
(setq eaf-org-file-list (remove org-killed-buffer eaf-org-file-list))
(eaf--org-delete-preview-file org-killed-buffer)))
(setq eaf-org-killed-file-list nil))
(defun eaf--org-preview-monitor-kill ()
"Function monitoring when org-preview application is killed."
;; Because save org buffer will trigger `kill-buffer' action,
;; but org buffer still live after do `kill-buffer' action.
;; So I run a timer to check org buffer is live after `kill-buffer' action.
(when (member (buffer-file-name) eaf-org-file-list)
(unless (member (buffer-file-name) eaf-org-killed-file-list)
(push (buffer-file-name) eaf-org-killed-file-list))
(run-with-timer 1 nil (lambda () (eaf--org-killed-buffer-clean)))))
(defun eaf--org-preview-monitor-buffer-save ()
"Save org-preview buffer."
(when (eaf-epc-live-p eaf-epc-process)
(ignore-errors
;; eaf-org-file-list?
(org-html-export-to-html)
(eaf-call-async "update_buffer_with_url" eaf-org-previewer-module-path (buffer-file-name) "")
(message "[EAF] Export %s to HTML." (buffer-file-name)))))
(defun eaf--org-preview-display (buf)
"Given BUF, split window to show file and previewer."
(let ((url (buffer-local-value
'eaf--buffer-url buf)))
;; Find file first, because `find-file' will trigger `kill-buffer' operation.
(save-excursion
(find-file url)
(org-html-export-to-html)
(add-hook 'after-save-hook #'eaf--org-preview-monitor-buffer-save nil t)
(add-hook 'kill-buffer-hook #'eaf--org-preview-monitor-kill nil t))
;; Add file name to `eaf-org-file-list' after command `find-file'.
(unless (member url eaf-org-file-list)
(push url eaf-org-file-list))
;; Split window to show file and previewer.
(eaf-split-preview-windows url)
;; Switch to new buffer if buffer create successful.
(switch-to-buffer buf)
(other-window +1)))
(add-hook 'eaf-stop-process-hook
#'(lambda ()
(dolist (org-file-name eaf-org-file-list)
(eaf--org-delete-preview-file org-file-name))
(setq eaf-org-file-list nil)
(setq eaf-org-killed-file-list nil)))
(add-to-list 'eaf-app-binding-alist '("org-previewer" . eaf-org-previewer-keybinding))
(setq eaf-org-previewer-module-path (concat (file-name-directory load-file-name) "buffer.py"))
(add-to-list 'eaf-app-module-path-alist '("org-previewer" . eaf-org-previewer-module-path))
(add-to-list 'eaf-preview-display-function-alist '("org-previewer" . eaf--org-preview-display))
(add-to-list 'eaf-app-extensions-alist '("org-previewer" . eaf-org-extension-list))
(provide 'eaf-org-previewer)
;;; eaf-org-previewer.el ends here