#!/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.QtCore import QUrl, QTimer, QPointF, Qt from PyQt5.QtGui import QColor from PyQt5.QtWidgets import QApplication from core.browser import BrowserBuffer from core.utils import PostGui, get_free_port, interactive import os import subprocess import signal import threading import getpass import json from urllib import request from http.server import SimpleHTTPRequestHandler from socketserver import TCPServer class AppBuffer(BrowserBuffer): def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, module_path): BrowserBuffer.__init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, module_path, False) # Get free port. self.port = get_free_port() self.http_url = "http://127.0.0.1:{0}".format(get_free_port()) self.url = url arguments_dict = json.loads(arguments) self.command = arguments_dict["command"] self.start_directory = arguments_dict["directory"] self.current_directory = self.start_directory self.executing_command = "" self.index_file = "{0}/index.html".format(self.http_url) self.server_js = os.path.join(os.path.dirname(__file__), "server.js") self.buffer_widget.titleChanged.connect(self.change_title) http_thread = threading.Thread(target=self.run_http_server, args=()) http_thread.start() self.search_term = "" # Start server process. args = ["node", self.server_js, str(self.port), self.start_directory, self.command] self.background_process = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False) self.open_terminal_page() QTimer.singleShot(250, self.focus_widget) self.build_all_methods(self) self.timer=QTimer() self.timer.start(250) self.timer.timeout.connect(self.checking_status) def run_http_server(self): class Handler(SimpleHTTPRequestHandler): def __init__(self, *args, **kwargs): # directory=os.path.dirname(__file__), This argument add in python3.7 after super().__init__(*args, **kwargs) def translate_path(self, path): # On python3.7 before version, http server don't support setting directory # default use the project path. path = super().translate_path(path) return os.path.dirname(__file__) + path[len(os.getcwd()):] with TCPServer(("127.0.0.1", int(self.http_url.split(":")[-1])), Handler) as h: h.serve_forever() @PostGui() def open_terminal_page(self): theme = "light" if self.emacs_var_dict["eaf-terminal-dark-mode"] == "true" or \ (self.emacs_var_dict["eaf-terminal-dark-mode"] == "follow" and self.emacs_var_dict["eaf-emacs-theme-mode"] == "dark"): theme = "dark" with request.urlopen(self.index_file) as f: html = f.read().decode("utf-8").replace("%1", str(self.port)).replace("%2", self.http_url).replace("%3", theme).replace("%4", self.emacs_var_dict["eaf-terminal-font-size"]).replace("%5", self.current_directory).replace("%6", self.emacs_var_dict["eaf-terminal-font-family"]) self.buffer_widget.setHtml(html) def checking_status(self): changed_directory = str(self.buffer_widget.execute_js("title")) changed_executing_command = str(self.buffer_widget.execute_js("executing_command")) if len(changed_executing_command) > 30: changed_executing_command = changed_executing_command[:30] if changed_executing_command != self.executing_command and changed_executing_command != "": self.change_title(changed_executing_command) self.executing_command = changed_executing_command elif changed_executing_command == "" and self.executing_command != "" or not changed_directory == self.current_directory: self.change_title(changed_directory) if not changed_directory == self.current_directory: self.eval_in_emacs.emit('eaf--change-default-directory', [changed_directory]) self.current_directory = changed_directory if self.executing_command != "": self.executing_command = "" if subprocess.Popen.poll(self.background_process) is not None: self.destroy_buffer() def destroy_buffer(self): self.close_buffer() self.timer.stop() @interactive def copy_text(self): text = self.buffer_widget.execute_js("get_selection();") if text == "": self.message_to_emacs.emit("Nothing selected") else: self.set_clipboard_text(text) self.message_to_emacs.emit("Copy text") @interactive def yank_text(self): text = self.get_clipboard_text() self.buffer_widget.eval_js("paste(`{}`);".format(text)) @interactive def scroll_other_buffer(self, scroll_direction, scroll_type): if scroll_type == "page": if scroll_direction == "up": self.scroll_up_page() else: self.scroll_down_page() else: if scroll_direction == "up": self.scroll_up() else: self.scroll_down() @interactive def scroll_up(self): self.buffer_widget.eval_js("scroll_line(1);") @interactive def scroll_down(self): self.buffer_widget.eval_js("scroll_line(-1);") @interactive def scroll_up_page(self): self.buffer_widget.eval_js("scroll_page(1);") @interactive def scroll_down_page(self): self.buffer_widget.eval_js("scroll_page(-1);") @interactive def scroll_to_begin(self): self.buffer_widget.eval_js("scroll_to_begin();") @interactive def scroll_to_bottom(self): self.buffer_widget.eval_js("scroll_to_bottom();") def select_all(self): self.buffer_widget.eval_js("select_all();") def clear_selection(self): self.buffer_widget.eval_js("clear_selection();") def clear(self): self.buffer_widget.eval_js("clear();") def _search_text(self, text, is_backward = False): if self.search_term != text: self.search_term = text if is_backward: # self.web_page.findText(self.search_term, self.web_page.FindBackward) self.buffer_widget.eval_js("find_next('{}')".format(text)) else: # self.web_page.findText(self.search_term) self.buffer_widget.eval_js("find_prev('{}')".format(text)) @interactive def search_text_forward(self): if self.search_term == "": self.send_input_message("Forward Search Text: ", "search_text_forward") else: self._search_text(self.search_term) @interactive def search_text_backward(self): if self.search_term == "": self.send_input_message("Backward Search Text: ", "search_text_backward") else: self._search_text(self.search_term, True) @interactive def action_quit(self): if self.search_term != "": self._search_text("") def handle_input_response(self, callback_tag, result_content): if callback_tag == "search_text_forward": self._search_text(str(result_content)) elif callback_tag == "search_text_backward": self._search_text(str(result_content), True)