diff --git a/README.md b/README.md index e8ff3bc..4fe003f 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ Using this framework, you can use PyQt develop powerful graphics programs to ext ### Browser ![img](./screenshot/browser.gif) +### Markdown Previewer +![img](./screenshot/markdown_previewer.gif) + ### Image Viewer ![img](./screenshot/image_viewer.gif) @@ -27,9 +30,17 @@ Using this framework, you can use PyQt develop powerful graphics programs to ext 1. Install python libraries: ```Bash sudo pacman -S python-xlib python-pyqt5 python-pymediainfo -sudo pip install PyMuPDF +sudo pip install PyMuPDF grip ``` +| Package | Use for | +| :-------- | :---- | +| python-xlib | Stick app window into emacs frame | +| python-pyqt5 | GUI library required for application development | +| python-pymediainfo | Detect file type, then choose the right application to open | +| PyMuPDF | Render engine required for PDF Viewer | +| grip | Markdown render server for Markdown Previewer | + 2. Clone this repository and add below code in your ~/.emacs ```Elisp (require 'eaf) @@ -40,28 +51,29 @@ sudo pip install PyMuPDF ``` M-x eaf-open ``` -| App | Way to open | Key | Event | -| -------- | :---- | :-----: | :---- | -| Browser | URL | Left Button | Open link current tab | -| | | Ctrl + Left Button | Open link in new tab | -| Image Viewer | Image file path | j | Load next image in current directory | -| | | k | Load previous image in current directory | -| Video Player | Video file path | Space | Play or Pause | -| | | h | Seek backward | -| | | l | Seek forward | -| Pdf Viewer | Pdf file path | j | Scroll up | -| | | k | Scroll down | -| | | Space | Scroll up page | -| | | b | Scroll down page | -| | | , | Scroll to end | -| | | . | Scroll to home | -| | | t | Switch scale mode | -| | | - | Zoom out | -| | | = | Zoom in | -| | | 0 | Zoomn reset | -| | | g | Goto page | -| Camera | Type 'eaf-camera' | | | -| Demo | Type 'eaf-demo' | | | +| App | Way to open | Key | Event | +| :-------- | :---- | :-----: | :---- | +| 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 | +| | | k | Load previous image in current directory | +| Video Player | Video file path | Space | Play or Pause | +| | | h | Seek backward | +| | | l | Seek forward | +| Pdf Viewer | Pdf file path | j | Scroll up | +| | | k | Scroll down | +| | | Space | Scroll up page | +| | | b | Scroll down page | +| | | , | Scroll to end | +| | | . | Scroll to home | +| | | t | Switch scale mode | +| | | - | Zoom out | +| | | = | Zoom in | +| | | 0 | Zoomn reset | +| | | g | Goto page | +| Camera | Type 'eaf-camera' | | | +| Demo | Type 'eaf-demo' | | | ### Why this awesome framework can't works with MacOS? There are mainly three obstacles: diff --git a/app/markdownpreviewer/buffer.py b/app/markdownpreviewer/buffer.py new file mode 100644 index 0000000..7556063 --- /dev/null +++ b/app/markdownpreviewer/buffer.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- 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 + +class AppBuffer(Buffer): + def __init__(self, buffer_id, url): + Buffer.__init__(self, buffer_id, url, False, QColor(255, 255, 255, 255)) + + # Get free port to render markdown. + self.port = self.get_free_port() + + # Start markdown render process. + subprocess.Popen("grip {0} {1}".format(url, self.port), shell=True) + + # Init widget. + self.add_widget(BrowserWidget()) + self.buffer_widget.titleChanged.connect(self.change_title) + + # Add timer make load markdown preview link after grip process start finish. + timer = threading.Timer(2, self.load_markdown_server) + timer.start() + + def get_free_port(self): + """ + Determines a free port using sockets. + """ + free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + free_socket.bind(('0.0.0.0', 0)) + free_socket.listen(5) + port = free_socket.getsockname()[1] + free_socket.close() + + return port + + @PostGui() + def load_markdown_server(self): + self.buffer_widget.setUrl(QUrl("http://localhost:{0}".format(self.port))) + self.buffer_widget.update() + +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/eaf.py b/eaf.py index 6b2e5ba..ba8d60c 100755 --- a/eaf.py +++ b/eaf.py @@ -63,6 +63,8 @@ class EAF(dbus.service.Object): if extension in [".pdf", ".xps", ".oxps", ".cbz", ".epub", ".fb2", "fbz"]: return self.create_app(buffer_id, url, "app.pdfviewer.buffer") + if extension in [".md"]: + return self.create_app(buffer_id, url, "app.markdownpreviewer.buffer") else: file_info = MediaInfo.parse(url) if file_is_image(file_info): diff --git a/screenshot/markdown_previewer.gif b/screenshot/markdown_previewer.gif new file mode 100644 index 0000000..5317405 Binary files /dev/null and b/screenshot/markdown_previewer.gif differ