diff --git a/README.md b/README.md index 6e4039e..d21ad1c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ EAF is extensible, you can develop any PyQt application and integrate it into Em | Terminal Emulator | RSS Reader | | :--------: | :------: | -| | | +| | | | | | ## Install EAF @@ -62,28 +62,32 @@ If you use [use-package](https://github.com/jwiegley/use-package), a sample conf sudo pip3 install dbus-python python-xlib pyqt5 pyqtwebengine pymupdf grip qrcode feedparser ``` -3. Compile ```qtermwidget-git``` use the following command: -```Elisp -git clone https://github.com/lxqt/qtermwidget.git --depth=1 -mkdir build && cd build -cmake .. -DQTERMWIDGET_BUILD_PYTHON_BINDING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=/usr -make -sudo make install +3. Install and config ```wetty```: +```Bash +# Install wetty +sudo yarn global add wetty + +# Make wetty login with public key +ssh-keygen +cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys + +# You need add below in .bashrc if you are Chinese +echo 'export LANG=zh_CN.UTF-8' >> ~/.bashrc ``` Package info: -| Package | Package Repo | Classification | Package Description | -| :-------- | :---- | :------ | :------ | -| dbus-python | pip3 | Core | DBus IPC to communicate python with elisp | -| python-xlib | pip3 | Core | Stick app window into Emacs frame | -| pyqt5 | pip3 | Core | GUI library required for applications | -| pyqtwebengine | pip3 | Core | Browser: QtWebEngine for browser application | -| pymupdf | pip3 | Application | PDF Viewer: Rendering engine | -| grip | pip3 | Application | Markdown Previewer: Markdown render server | -| qrcode | pip3 | Application | File Transfer: Render QR code pointing local files | -| feedparser | pip3 | Application | RSS Reader: feed parser | -| qtermwidget-git | compile from source | Application | Terminal: QTermWidget, PyQt5 terminal emulator | +| Package | Package Repo | Classification | Package Description | +| :-------- | :---- | :------ | :------ | +| dbus-python | pip3 | Core | DBus IPC to communicate python with elisp | +| python-xlib | pip3 | Core | Stick app window into Emacs frame | +| pyqt5 | pip3 | Core | GUI library required for applications | +| pyqtwebengine | pip3 | Core | Browser: QtWebEngine for browser application | +| pymupdf | pip3 | Application | PDF Viewer: Rendering engine | +| grip | pip3 | Application | Markdown Previewer: Markdown render server | +| qrcode | pip3 | Application | File Transfer: Render QR code pointing local files | +| feedparser | pip3 | Application | RSS Reader: feed parser | +| wetty | yarn | Application | Terminal: Share SSH over Web | ## Launch EAF Applications diff --git a/app/file-sender/buffer.py b/app/file-sender/buffer.py index 171e11f..878bb4d 100644 --- a/app/file-sender/buffer.py +++ b/app/file-sender/buffer.py @@ -24,11 +24,11 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QColor, QFont from PyQt5.QtWidgets import QWidget, QLabel, QVBoxLayout from core.buffer import Buffer +from core.utils import get_free_port import http.server as BaseHTTPServer import os import qrcode import shutil -import socket import sys import threading @@ -130,24 +130,12 @@ class FileTransferWidget(QWidget): print("Network is unreachable") sys.exit() - 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 - def start_server(self, filename): global local_file_path local_file_path = filename - self.port = self.get_free_port() + self.port = get_free_port() self.local_ip = self.get_local_ip() self.set_address("http://{0}:{1}/{2}".format(self.local_ip, self.port, filename)) diff --git a/app/markdown-previewer/buffer.py b/app/markdown-previewer/buffer.py index f349ed1..985434d 100644 --- a/app/markdown-previewer/buffer.py +++ b/app/markdown-previewer/buffer.py @@ -22,9 +22,8 @@ from PyQt5.QtCore import QUrl from PyQt5.QtGui import QColor from core.browser import BrowserBuffer -from core.utils import PostGui +from core.utils import PostGui, get_free_port import os -import socket import subprocess import threading @@ -33,7 +32,7 @@ class AppBuffer(BrowserBuffer): BrowserBuffer.__init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, False, QColor(255, 255, 255, 255)) # Get free port to render markdown. - self.port = self.get_free_port() + self.port = get_free_port() self.url = url # Start markdown render process. @@ -46,18 +45,6 @@ class AppBuffer(BrowserBuffer): 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))) diff --git a/app/terminal/buffer.py b/app/terminal/buffer.py index 9c433a4..fba66e6 100644 --- a/app/terminal/buffer.py +++ b/app/terminal/buffer.py @@ -19,30 +19,48 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from PyQt5.QtGui import QColor, QFont -from core.buffer import Buffer -import QTermWidget +from PyQt5.QtCore import QUrl +from PyQt5.QtGui import QColor +from core.browser import BrowserBuffer +from core.utils import PostGui, get_free_port +import os +import subprocess +import signal +import threading +import getpass -class AppBuffer(Buffer): +class AppBuffer(BrowserBuffer): def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict): - Buffer.__init__(self, buffer_id, url, arguments, emacs_var_dict, True, QColor(0, 0, 0, 255)) + BrowserBuffer.__init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, False, QColor(255, 255, 255, 255)) - self.add_widget(QTermWidget.QTermWidget()) + # Get free port to render markdown. + self.port = get_free_port() + self.url = url - self.buffer_widget.setTerminalFont(QFont('Source Code Pro', 14)) - self.buffer_widget.setColorScheme('Linux') + # Start wetty process. + self.background_process = subprocess.Popen( + "wetty -p {0} --base / --sshuser {1} --sshauth publickey -c bash".format(self.port, getpass.getuser()), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=True) - self.buffer_widget.finished.connect(self.request_close_buffer) + # Add timer make load markdown preview link after grip process start finish. + threading.Timer(1, self.load_wetty_server).start() - def get_key_event_widgets(self): - return self.buffer_widget.children() + self.reset_default_zoom() - def fake_key_event_filter(self, event_string): - if event_string == "RET": - self.buffer_widget.sendText("\n") + @PostGui() + def load_wetty_server(self): + self.buffer_widget.setUrl(QUrl("http://localhost:{0}".format(self.port))) - def zoom_out(self): - self.buffer_widget.zoomOut() + paths = os.path.split(self.url) + if len(paths) > 0: + self.change_title(paths[-1]) - def zoom_in(self): - self.buffer_widget.zoomIn() + def handle_destroy(self): + os.killpg(os.getpgid(self.background_process.pid), signal.SIGTERM) + + self.before_destroy_hook.emit() + + if self.buffer_widget is not None: + self.buffer_widget.destroy() diff --git a/core/utils.py b/core/utils.py index 2ac4e4b..9ad638a 100644 --- a/core/utils.py +++ b/core/utils.py @@ -22,6 +22,7 @@ from PyQt5 import QtCore import functools import os +import socket class PostGui(QtCore.QObject): @@ -59,3 +60,15 @@ def touch(path): with open(path, 'a'): os.utime(path) + +def get_free_port(): + """ + 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 diff --git a/eaf.el b/eaf.el index 507c6ca..8a7d062 100644 --- a/eaf.el +++ b/eaf.el @@ -7,7 +7,7 @@ ;; Copyright (C) 2018, Andy Stewart, all rights reserved. ;; Created: 2018-06-15 14:10:12 ;; Version: 0.5 -;; Last-Updated: Tue Jan 14 00:36:40 2020 (-0500) +;; Last-Updated: Wed Jan 22 23:11:57 2020 (-0500) ;; By: Mingde (Matthew) Zeng ;; URL: http://www.emacswiki.org/emacs/download/eaf.el ;; Keywords: @@ -1062,7 +1062,8 @@ This function works best if paired with a fuzzy search package." (history (completing-read "[EAF/browser] Search || URL || History: " history-list)) (history-url (when (string-match "[^\s]+$" history) (match-string 0 history)))) - (if (string-match "^\\(https?://\\)?[a-z0-9]+\\([-.][a-z0-9]+\\)*.+\\..+[a-z0-9.]\\{2,5\\}\\(:[0-9]{1,5}\\)?\\(/.*\\)?$" history-url) + (if (and history-url + (string-match "^\\(https?://\\)?[a-z0-9]+\\([-.][a-z0-9]+\\)*.+\\..+[a-z0-9.]\\{2,5\\}\\(:[0-9]{1,5}\\)?\\(/.*\\)?$" history-url)) (eaf-open-browser history-url) (eaf-open-browser history)))))) diff --git a/screenshot/terminal.gif b/screenshot/terminal.gif new file mode 100644 index 0000000..8c3dce6 Binary files /dev/null and b/screenshot/terminal.gif differ diff --git a/screenshot/terminal.png b/screenshot/terminal.png deleted file mode 100644 index b4e412f..0000000 Binary files a/screenshot/terminal.png and /dev/null differ