diff --git a/HACKING.md b/HACKING.md
index 72c52fb..2ba08cd 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -134,9 +134,9 @@ You need implement "scroll" interface in AppBuffer, such as like PDF Viewer does
self.buffer_widget.scroll_down()
```
-scroll_direction is string, "up" mean scroll buffer up, "down" mean scroll buffer down.
+Argument "scroll_direction" is string, "up" mean scroll buffer up, "down" mean scroll buffer down.
-scroll_type is string, "page" mean scroll buffer by page, "line" mean scroll buffer by line.
+Argument "scroll_type" is string, "page" mean scroll buffer by page, "line" mean scroll buffer by line.
### Save/Restore session
We always need save and restore session for application, such as, save play position of video player.
@@ -153,9 +153,22 @@ You need implement interfaces "save_session_data" and "restore_session_data", be
self.buffer_widget.media_player.setPosition(position)
```
-session_data is string, you can put anything in it
+Argument "session_data" is string, you can put anything in it
All session data save at ~/.emacs.d/eaf/session.json file.
+### Update buffer
+If you need update buffer sometimes, such as update org-file previewer after save org-file.
+
+You need implement interfaces "update_with_data" , below is an example of Org Previewer does:
+
+```Python
+ def update_with_data(self, update_data):
+ self.load_org_html_file()
+ self.buffer_widget.reload()
+```
+
+Argument "update_data" is pass from elisp side.
+
## Todolist
[Some works you can hacking ;)](TODOLIST.md)
diff --git a/README.md b/README.md
index 4617478..9238093 100644
--- a/README.md
+++ b/README.md
@@ -29,10 +29,11 @@ Using this framework, you can use PyQt develop powerful graphics programs to ext
|
|
|
| | |
-| Air Share |
-| :--------: |
-|
|
-| |
+
+| Air Share | Org Previewer |
+| :--------: | :--------: |
+|
|
|
+| | |
## Installation
@@ -79,13 +80,14 @@ There are mainly three obstacles:
| :-------- | :---- | :-----: | :---- |
| Browser | URL | Left Button | Open link current tab |
| | | Ctrl + Left Button | Open link in new tab |
-| Markdown previewer | Markdown file path | | |
-| Image Viewer | Image file path | j | Load next image in current directory |
+| Markdown previewer | Type 'eaf-open' RET markdown filepath | | |
+| Org file previewer | Type 'eaf-open' RET org filepath | | |
+| Image Viewer | Type 'eaf-open' RET IMAGE filepath | j | Load next image in current directory |
| | | k | Load previous image in current directory |
-| Video Player | Video file path | Space | Play or Pause |
+| Video Player | Type 'eaf-open' RET video filepath | Space | Play or Pause |
| | | h | Seek backward |
| | | l | Seek forward |
-| Pdf Viewer | Pdf file path | j | Scroll up |
+| Pdf Viewer | Type 'eaf-open' RET PDF filepath | j | Scroll up |
| | | k | Scroll down |
| | | Space | Scroll up page |
| | | b | Scroll down page |
diff --git a/app/orgpreviewer/buffer.py b/app/orgpreviewer/buffer.py
new file mode 100644
index 0000000..a59463e
--- /dev/null
+++ b/app/orgpreviewer/buffer.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2018 Andy Stewart
+#
+# Author: Andy Stewart
+# Maintainer: Andy Stewart
+#
+# 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 of the License, or
+# 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. If not, see .
+
+from PyQt5 import QtCore
+from PyQt5.QtCore import QUrl, Qt
+from PyQt5.QtGui import QColor
+from PyQt5.QtWebKitWidgets import QWebView, QWebPage
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWebKit import QWebSettings
+from core.buffer import Buffer
+from core.utils import PostGui
+import socket
+import subprocess
+import threading
+import os
+
+class AppBuffer(Buffer):
+ def __init__(self, buffer_id, url):
+ Buffer.__init__(self, buffer_id, url, False, QColor(255, 255, 255, 255))
+
+ self.url = url
+ self.add_widget(BrowserWidget())
+
+ self.load_org_html_file()
+
+ def load_org_html_file(self):
+ self.buffer_widget.setUrl(QUrl.fromLocalFile(os.path.splitext(self.url)[0]+".html"))
+
+ def update_with_data(self, update_data):
+ self.load_org_html_file()
+ self.buffer_widget.reload()
+
+class BrowserWidget(QWebView):
+
+ def __init__(self):
+ super(QWebView, self).__init__()
+
+ self.web_page = WebPage()
+ self.setPage(self.web_page)
+
+ self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
+ self.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
+ self.settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
+
+class WebPage(QWebPage):
+
+ open_url_in_new_tab = QtCore.pyqtSignal(str)
+
+ def __init__(self):
+ super(WebPage, self).__init__()
+
+ def acceptNavigationRequest(self, frame, request, type):
+ modifiers = QApplication.keyboardModifiers()
+
+ # Handle myself if got user event.
+ if type == QWebPage.NavigationTypeLinkClicked:
+ if modifiers == Qt.ControlModifier:
+ self.open_url_in_new_tab.emit(request.url().toString())
+ else:
+ self.view().load(request.url())
+
+ # Return False to stop default behavior.
+ return False
+
+ # # Otherwise, use default behavior.
+ return QWebPage.acceptNavigationRequest(self, frame, request, type)
+
+ def javaScriptConsoleMessage(self, msg, lineNumber, sourceID):
+ pass
diff --git a/core/buffer.py b/core/buffer.py
index 665f1e6..3c5d42f 100644
--- a/core/buffer.py
+++ b/core/buffer.py
@@ -79,3 +79,6 @@ class Buffer(QGraphicsScene):
def restore_session_data(self, session_data):
pass
+
+ def update_with_data(self, update_data):
+ pass
diff --git a/eaf.el b/eaf.el
index 976ac78..d326cb5 100644
--- a/eaf.el
+++ b/eaf.el
@@ -114,6 +114,9 @@
(defvar eaf-title-length 30)
+(defvar eaf-org-file-list '())
+(defvar eaf-org-killed-file-list '())
+
(defcustom eaf-name "*eaf*"
"Name of eaf buffer."
:type 'string
@@ -167,6 +170,11 @@
;; Clean cache url and app name, avoid next start process to open buffer.
(setq eaf-first-start-url nil)
(setq eaf-first-start-app-name nil)
+ ;; Clean `eaf-org-file-list'
+ (dolist (org-file-name eaf-org-file-list)
+ (eaf-delete-org-preview-file org-file-name))
+ (setq eaf-org-file-list nil)
+ (setq eaf-org-killed-file-list nil)
))
(defun eaf-restart-process ()
@@ -225,7 +233,7 @@ We need calcuate render allocation to make sure no black border around render co
(dolist (window (window-list))
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
- (if (string= "eaf-mode" (format "%s" major-mode))
+ (if (eq major-mode 'eaf-mode)
(let* ((window-allocation (eaf-get-window-allocation window))
(x (nth 0 window-allocation))
(y (nth 1 window-allocation))
@@ -239,18 +247,53 @@ We need calcuate render allocation to make sure no black border around render co
(eaf-call "update_views" (mapconcat 'identity view-infos ","))
)))
+(defun eaf-delete-org-preview-file (org-file)
+ (setq org-html-file (concat (file-name-sans-extension org-file) ".html"))
+ (when (file-exists-p org-html-file)
+ (delete-file org-html-file)
+ (message (format "Clean org preview file %s (%s)" org-html-file org-file))
+ ))
+
+(defun eaf-org-killed-buffer-clean ()
+ (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-delete-org-preview-file org-killed-buffer)
+ ))
+ (setq eaf-org-killed-file-list nil))
+
(defun eaf-monitor-buffer-kill ()
(ignore-errors
(with-current-buffer (buffer-name)
- (when (string= "eaf-mode" (format "%s" major-mode))
- (eaf-call "kill_buffer" buffer-id)
- (message (format "Kill %s" buffer-id))
- ))))
+ (cond ((eq major-mode 'org-mode)
+ ;; NOTE:
+ ;; 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' aciton.
+ (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)))
+ ))
+ ((eq major-mode 'eaf-mode)
+ (eaf-call "kill_buffer" buffer-id)
+ (message (format "Kill %s" buffer-id)))
+ ))))
+
+(defun eaf-monitor-buffer-save ()
+ (ignore-errors
+ (with-current-buffer (buffer-name)
+ (cond ((and
+ (eq major-mode 'org-mode)
+ (member (buffer-file-name) eaf-org-file-list))
+ (org-html-export-to-html)
+ (eaf-call "update_buffer_with_url" "app.orgpreviewer.buffer" (buffer-file-name) "")
+ (message (format "export %s to html" (buffer-file-name))))))))
(defun eaf-monitor-key-event ()
(ignore-errors
(with-current-buffer (buffer-name)
- (when (string= "eaf-mode" (format "%s" major-mode))
+ (when (eq major-mode 'eaf-mode)
(let* ((event last-command-event)
(key (make-vector 1 event))
(key-command (format "%s" (key-binding key)))
@@ -303,7 +346,7 @@ We need calcuate render allocation to make sure no black border around render co
(dolist (window (window-list))
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
- (if (string= "eaf-mode" (format "%s" major-mode))
+ (if (eq major-mode 'eaf-mode)
(let* ((window-allocation (eaf-get-window-allocation window))
(x (nth 0 window-allocation))
(y (nth 1 window-allocation))
@@ -341,7 +384,7 @@ We need calcuate render allocation to make sure no black border around render co
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
(when (and
- (string= "eaf-mode" (format "%s" major-mode))
+ (eq major-mode 'eaf-mode)
(equal buffer-id bid))
(rename-buffer title)
(throw 'find-buffer t)
@@ -371,6 +414,7 @@ We need calcuate render allocation to make sure no black border around render co
(add-hook 'window-configuration-change-hook #'eaf-monitor-configuration-change)
(add-hook 'pre-command-hook #'eaf-monitor-key-event)
(add-hook 'kill-buffer-hook #'eaf-monitor-buffer-kill)
+(add-hook 'after-save-hook #'eaf-monitor-buffer-save)
(defun eaf-open-internal (url app-name)
(let* ((buffer (eaf-create-buffer url))
@@ -398,11 +442,32 @@ We need calcuate render allocation to make sure no black border around render co
(cond ((member extension-name '("pdf" "xps" "oxps" "cbz" "epub" "fb2" "fbz"))
(setq app-name "pdfviewer"))
((member extension-name '("md"))
+ ;; Split window to show file and previewer.
+ (delete-other-windows)
+ (find-file url)
+ (split-window-horizontally)
+ (other-window +1)
(setq app-name "markdownpreviewer"))
((member extension-name '("jpg" "png" "bmp"))
(setq app-name "imageviewer"))
((member extension-name '("avi" "rmvb" "ogg" "mp4"))
- (setq app-name "videoplayer"))))
+ (setq app-name "videoplayer"))
+ ((member extension-name '("org"))
+ ;; Find file first, because `find-file' will trigger `kill-buffer' operation.
+ (save-excursion
+ (find-file url)
+ (with-current-buffer (buffer-name)
+ (org-html-export-to-html)))
+ ;; 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.
+ (delete-other-windows)
+ (find-file url)
+ (split-window-horizontally)
+ (other-window +1)
+ (setq app-name "orgpreviewer")
+ )))
(t
(setq app-name "browser")
(unless (string-prefix-p "http" url)
diff --git a/eaf.py b/eaf.py
index fad365f..1d95a2f 100755
--- a/eaf.py
+++ b/eaf.py
@@ -56,6 +56,13 @@ class EAF(dbus.service.Object):
# otherwise some library will throw error, such as fitz library.
return self.create_app(buffer_id, str(url), "app.{0}.buffer".format(str(app_name)))
+ @dbus.service.method(EAF_DBUS_NAME, in_signature="sss", out_signature="")
+ def update_buffer_with_url(self, module_path, buffer_url, update_data):
+ for buffer in list(self.buffer_dict.values()):
+ if buffer.module_path == module_path and buffer.url == buffer_url:
+ buffer.update_with_data(update_data)
+ break
+
@dbus.service.method(EAF_DBUS_NAME, in_signature="sss", out_signature="")
def scroll_buffer(self, view_info, scroll_direction, scroll_type):
(buffer_id, _, _, _, _) = view_info.split(":")
diff --git a/screenshot/org_previewer.gif b/screenshot/org_previewer.gif
new file mode 100644
index 0000000..68ec0ce
Binary files /dev/null and b/screenshot/org_previewer.gif differ