From 6c3733e98079e1f7031bdd284c327ae6ab86fdc7 Mon Sep 17 00:00:00 2001 From: siogian Date: Sun, 23 May 2021 19:17:42 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=B8=BA=E6=8E=A7=E5=88=B6=E5=8F=B0?= =?UTF-8?q?=E6=96=B0=E5=A2=9E"=E6=9F=A5=E7=9C=8B=E5=8E=86=E5=8F=B2"?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20https://gitee.com/py2cn/pyminer/issues/I27?= =?UTF-8?q?AQJ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/others/ConsoleHistoryDialog.py | 98 +++++++++++++++ .../basic/others/Ui_ConsoleHistoryDialog.py | 115 ++++++++++++++++++ pmgwidgets/widgets/basic/others/console.py | 51 +++++++- 3 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py create mode 100644 pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py new file mode 100644 index 00000000..e2cd5596 --- /dev/null +++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py @@ -0,0 +1,98 @@ +import os + +from PySide2 import QtCore +from PySide2.QtCore import QItemSelectionModel +from PySide2.QtWidgets import QApplication, QDialog +from qtconsole.frontend_widget import FrontendWidget +from .Ui_ConsoleHistoryDialog import Ui_ConsoleHistoryDialog + + +class ConsoleHistoryDialog(QDialog, Ui_ConsoleHistoryDialog): + """ + Class implementing the shell history dialog. + """ + + def __init__(self, console): + super().__init__() + self.setupUi(self) + self.__console = console + + self.deleteButton.clicked.connect(self.on_deleteButton_clicked) + self.copyButton.clicked.connect(self.on_copyButton_clicked) + self.reloadButton.clicked.connect(self.on_reloadButton_clicked) + self.historyList.itemSelectionChanged.connect( + self.on_historyList_itemSelectionChanged) + + self.reloadButton.click() + + @QtCore.Slot(QtCore.QModelIndex) + def select(self, item): + print(item.data()) + + @QtCore.Slot() + def on_historyList_itemSelectionChanged(self): + """ + Private slot to handle a change of the selection. + """ + selected = len(self.historyList.selectedItems()) > 0 + self.deleteButton.setEnabled(selected) + self.copyButton.setEnabled(selected) + self.executeButton.setEnabled(selected) + + @QtCore.Slot() + def on_deleteButton_clicked(self): + """ + Private slot to delete the selected entries from the history. + """ + for itm in self.historyList.selectedItems(): + ditm = self.historyList.takeItem(self.historyList.row(itm)) + del ditm + self.historyList.scrollToItem(self.historyList.currentItem()) + self.historyList.setFocus() + + @QtCore.Slot() + def on_copyButton_clicked(self): + cmds = self.selected_cmds() + QApplication.clipboard().setText(cmds) + + @QtCore.Slot() + def on_executeButton_clicked(self): + cmds = self.selected_cmds() + self.__console.hint_command(cmds) + self.__console.do_execute(cmds, True, '') + # reload the list because shell modified it + self.on_reloadButton_clicked() + + @QtCore.Slot() + def on_reloadButton_clicked(self): + """ + Private slot to reload the history. + """ + history = self.__console.history_tail(0) + + self.historyList.clear() + self.historyList.addItems(history) + self.historyList.setCurrentRow( + self.historyList.count() - 1, + QItemSelectionModel.SelectionFlag.Select) + + self.historyList.scrollToItem(self.historyList.currentItem()) + + @QtCore.Slot(QtCore.QModelIndex) + def on_historyList_doubleClicked(self, item): + self.on_executeButton_clicked() + + def get_history(self): + history = [] + for index in range(self.historyList.count()): + history.append(self.historyList.item(index).text()) + return history + + def selected_cmds(self): + lines = [] + for index in range(self.historyList.count()): + # selectedItems() doesn't seem to preserve the order + itm = self.historyList.item(index) + if itm.isSelected(): + lines.append(itm.text()) + return (os.linesep.join(lines) + os.linesep).rstrip(os.linesep) diff --git a/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py new file mode 100644 index 00000000..e555d7ae --- /dev/null +++ b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +################################################################################ +# Form generated from reading UI file 'ConsoleHistoryDialog.ui' +## +# Created by: Qt User Interface Compiler version 6.1.0 +## +# WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_ConsoleHistoryDialog(object): + def setupUi(self, ConsoleHistoryDialog): + if not ConsoleHistoryDialog.objectName(): + ConsoleHistoryDialog.setObjectName(u"ConsoleHistoryDialog") + ConsoleHistoryDialog.resize(540, 506) + ConsoleHistoryDialog.setSizeGripEnabled(True) + self.gridLayout = QGridLayout(ConsoleHistoryDialog) + self.gridLayout.setObjectName(u"gridLayout") + self.historyList = QListWidget(ConsoleHistoryDialog) + self.historyList.setObjectName(u"historyList") + font = QFont() + font.setFamilies([u"Monospace"]) + self.historyList.setFont(font) + self.historyList.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.historyList.setAlternatingRowColors(True) + self.historyList.setSelectionMode(QAbstractItemView.ExtendedSelection) + self.historyList.setWordWrap(True) + + self.gridLayout.addWidget(self.historyList, 0, 0, 1, 1) + + self.verticalLayout = QVBoxLayout() + self.verticalLayout.setObjectName(u"verticalLayout") + self.deleteButton = QPushButton(ConsoleHistoryDialog) + self.deleteButton.setObjectName(u"deleteButton") + self.deleteButton.setEnabled(False) + + self.verticalLayout.addWidget(self.deleteButton) + + self.copyButton = QPushButton(ConsoleHistoryDialog) + self.copyButton.setObjectName(u"copyButton") + self.copyButton.setEnabled(False) + + self.verticalLayout.addWidget(self.copyButton) + + self.executeButton = QPushButton(ConsoleHistoryDialog) + self.executeButton.setObjectName(u"executeButton") + self.executeButton.setEnabled(False) + + self.verticalLayout.addWidget(self.executeButton) + + self.reloadButton = QPushButton(ConsoleHistoryDialog) + self.reloadButton.setObjectName(u"reloadButton") + + self.verticalLayout.addWidget(self.reloadButton) + + self.verticalSpacer = QSpacerItem( + 72, 208, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer) + + self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1) + + self.buttonBox = QDialogButtonBox(ConsoleHistoryDialog) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setStandardButtons( + QDialogButtonBox.Cancel | QDialogButtonBox.Ok) + + self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 2) + + QWidget.setTabOrder(self.historyList, self.deleteButton) + QWidget.setTabOrder(self.deleteButton, self.copyButton) + QWidget.setTabOrder(self.copyButton, self.executeButton) + QWidget.setTabOrder(self.executeButton, self.reloadButton) + QWidget.setTabOrder(self.reloadButton, self.buttonBox) + + self.retranslateUi(ConsoleHistoryDialog) + self.buttonBox.accepted.connect(ConsoleHistoryDialog.accept) + self.buttonBox.rejected.connect(ConsoleHistoryDialog.reject) + + QMetaObject.connectSlotsByName(ConsoleHistoryDialog) + # setupUi + + def retranslateUi(self, ConsoleHistoryDialog): + ConsoleHistoryDialog.setWindowTitle(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Shell History", None)) +# if QT_CONFIG(tooltip) + self.deleteButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Delete the selected entries", None)) +#endif // QT_CONFIG(tooltip) + self.deleteButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Delete", None)) +# if QT_CONFIG(tooltip) + self.copyButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Copy the selected entries to the current editor", None)) +#endif // QT_CONFIG(tooltip) + self.copyButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"C&opy", None)) +# if QT_CONFIG(tooltip) + self.executeButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Execute the selected entries", None)) +#endif // QT_CONFIG(tooltip) + self.executeButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Execute", None)) +# if QT_CONFIG(tooltip) + self.reloadButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Reload the history", None)) +#endif // QT_CONFIG(tooltip) + self.reloadButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Reload", None)) + # retranslateUi diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py index 8cb374e4..e5ca9412 100644 --- a/pmgwidgets/widgets/basic/others/console.py +++ b/pmgwidgets/widgets/basic/others/console.py @@ -9,13 +9,15 @@ Created on 2020/8/24 @description: Console Widget """ +import json +from features.io import settings import os from typing import Tuple, Dict, Callable from PySide2.QtCore import QObject, Signal, QThread, QWaitCondition, QMutex, QPoint, QCoreApplication, QTranslator, \ QLocale from PySide2.QtGui import QTextCursor -from PySide2.QtWidgets import QMessageBox, QMenu, QApplication +from PySide2.QtWidgets import QMessageBox, QMenu, QApplication, QDialog from qtconsole import styles from qtconsole.manager import QtKernelManager from qtconsole.rich_jupyter_widget import RichJupyterWidget @@ -68,6 +70,8 @@ class PMGIpythonConsole(RichJupyterWidget): self.is_first_execution = True self.confirm_restart = False + self.history_path = os.path.join(settings.get_pyminer_data_path(), 'console_history.json') + self.history = [] self.commands_pool = [] self.command_callback_pool: Dict[str, Callable] = {} @@ -133,6 +137,9 @@ class PMGIpythonConsole(RichJupyterWidget): trans = trans_dic.get(action.text()) trans = trans if trans is not None else action.text() action.setText(trans) + history_action = menu.addAction(_translate("PMGIpythonConsole", 'History')) + history_action.triggered.connect(self.show_history) + restart_action = menu.addAction(_translate("PMGIpythonConsole", 'Restart')) restart_action.triggered.connect(self.slot_restart_kernel) @@ -143,6 +150,17 @@ class PMGIpythonConsole(RichJupyterWidget): return menu + def show_history(self): + """ + Public slot to show the shell history dialog. + """ + from .ConsoleHistoryDialog import ConsoleHistoryDialog + # import readline + dlg = ConsoleHistoryDialog(self) + if dlg.exec() == QDialog.DialogCode.Accepted: + self.history = dlg.get_history() + super()._set_history(self.history) + def on_interrupt_kernel(self): """ 当点击中断执行时。 @@ -200,6 +218,8 @@ class PMGIpythonConsole(RichJupyterWidget): return 'Welcome To PMGWidgets Ipython Console!\n' def closeEvent(self, event): + self.history = self.history_tail(0) + self.save_history() if self.init_thread.isRunning(): self.console_object.stop() self.init_thread.quit() @@ -224,6 +244,14 @@ class PMGIpythonConsole(RichJupyterWidget): :param hint_text: 运行代码前显示的提示 :return: str 执行命令的 msgid """ + self.hint_command(hint_text) + if self.kernel_client is None: + self.commands_pool.append((source, hidden, hint_text)) + return '' + else: + return self.pmexecute(source, hidden) + + def hint_command(self, hint_text: str = '') -> str: cursor: QTextCursor = self._prompt_cursor cursor.movePosition(QTextCursor.End) # 运行文件时,显示文件名,无换行符,执行选中内容时,包含换行符 @@ -239,11 +267,6 @@ class PMGIpythonConsole(RichJupyterWidget): self._finalize_input_request() # display input string buffer in console. cursor.movePosition(QTextCursor.End) - if self.kernel_client is None: - self.commands_pool.append((source, hidden, hint_text)) - return '' - else: - return self.pmexecute(source, hidden) def _handle_stream(self, msg): parent_header = msg.get('parent_header') @@ -304,6 +327,22 @@ class PMGIpythonConsole(RichJupyterWidget): directory=os.path.join(os.path.dirname(__file__), 'translations')) app.installTranslator(_trans) + def _set_history(self, history): + """ 重写的方法。重新管理历史记录。 + """ + self.load_history() + super()._set_history(self.history) + + def load_history(self): + if os.path.exists(self.history_path): + with open(self.history_path) as f: + history = json.load(f) + self.history = history['history'] + + def save_history(self): + history = { 'history': self.history } + with open(self.history_path, 'w') as f: + json.dump(history, f) if __name__ == '__main__': import sys -- Gitee From f69ae7b6a0ea396ac0791aad67e0b09acebf998e Mon Sep 17 00:00:00 2001 From: siogian Date: Sun, 23 May 2021 19:17:42 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=B8=BA=E6=8E=A7=E5=88=B6=E5=8F=B0?= =?UTF-8?q?=E6=96=B0=E5=A2=9E"=E6=9F=A5=E7=9C=8B=E5=8E=86=E5=8F=B2"?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20https://gitee.com/py2cn/pyminer/issues/I27?= =?UTF-8?q?AQJ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/others/ConsoleHistoryDialog.py | 98 +++++++++++ .../basic/others/ConsoleHistoryDialog.ui | 158 ++++++++++++++++++ .../basic/others/Ui_ConsoleHistoryDialog.py | 115 +++++++++++++ pmgwidgets/widgets/basic/others/console.py | 51 +++++- 4 files changed, 416 insertions(+), 6 deletions(-) create mode 100644 pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py create mode 100644 pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui create mode 100644 pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py new file mode 100644 index 00000000..e2cd5596 --- /dev/null +++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py @@ -0,0 +1,98 @@ +import os + +from PySide2 import QtCore +from PySide2.QtCore import QItemSelectionModel +from PySide2.QtWidgets import QApplication, QDialog +from qtconsole.frontend_widget import FrontendWidget +from .Ui_ConsoleHistoryDialog import Ui_ConsoleHistoryDialog + + +class ConsoleHistoryDialog(QDialog, Ui_ConsoleHistoryDialog): + """ + Class implementing the shell history dialog. + """ + + def __init__(self, console): + super().__init__() + self.setupUi(self) + self.__console = console + + self.deleteButton.clicked.connect(self.on_deleteButton_clicked) + self.copyButton.clicked.connect(self.on_copyButton_clicked) + self.reloadButton.clicked.connect(self.on_reloadButton_clicked) + self.historyList.itemSelectionChanged.connect( + self.on_historyList_itemSelectionChanged) + + self.reloadButton.click() + + @QtCore.Slot(QtCore.QModelIndex) + def select(self, item): + print(item.data()) + + @QtCore.Slot() + def on_historyList_itemSelectionChanged(self): + """ + Private slot to handle a change of the selection. + """ + selected = len(self.historyList.selectedItems()) > 0 + self.deleteButton.setEnabled(selected) + self.copyButton.setEnabled(selected) + self.executeButton.setEnabled(selected) + + @QtCore.Slot() + def on_deleteButton_clicked(self): + """ + Private slot to delete the selected entries from the history. + """ + for itm in self.historyList.selectedItems(): + ditm = self.historyList.takeItem(self.historyList.row(itm)) + del ditm + self.historyList.scrollToItem(self.historyList.currentItem()) + self.historyList.setFocus() + + @QtCore.Slot() + def on_copyButton_clicked(self): + cmds = self.selected_cmds() + QApplication.clipboard().setText(cmds) + + @QtCore.Slot() + def on_executeButton_clicked(self): + cmds = self.selected_cmds() + self.__console.hint_command(cmds) + self.__console.do_execute(cmds, True, '') + # reload the list because shell modified it + self.on_reloadButton_clicked() + + @QtCore.Slot() + def on_reloadButton_clicked(self): + """ + Private slot to reload the history. + """ + history = self.__console.history_tail(0) + + self.historyList.clear() + self.historyList.addItems(history) + self.historyList.setCurrentRow( + self.historyList.count() - 1, + QItemSelectionModel.SelectionFlag.Select) + + self.historyList.scrollToItem(self.historyList.currentItem()) + + @QtCore.Slot(QtCore.QModelIndex) + def on_historyList_doubleClicked(self, item): + self.on_executeButton_clicked() + + def get_history(self): + history = [] + for index in range(self.historyList.count()): + history.append(self.historyList.item(index).text()) + return history + + def selected_cmds(self): + lines = [] + for index in range(self.historyList.count()): + # selectedItems() doesn't seem to preserve the order + itm = self.historyList.item(index) + if itm.isSelected(): + lines.append(itm.text()) + return (os.linesep.join(lines) + os.linesep).rstrip(os.linesep) diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui new file mode 100644 index 00000000..59fb2507 --- /dev/null +++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui @@ -0,0 +1,158 @@ + + ShellHistoryDialog + + + + 0 + 0 + 540 + 506 + + + + Shell History + + + true + + + + + + + Monospace + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + true + + + + + + + + + false + + + Delete the selected entries + + + &Delete + + + + + + + false + + + Copy the selected entries to the current editor + + + C&opy + + + + + + + false + + + Execute the selected entries + + + &Execute + + + + + + + Reload the history + + + &Reload + + + + + + + Qt::Vertical + + + + 72 + 208 + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + historyList + deleteButton + copyButton + executeButton + reloadButton + buttonBox + + + + + buttonBox + accepted() + ShellHistoryDialog + accept() + + + 333 + 487 + + + 323 + 505 + + + + + buttonBox + rejected() + ShellHistoryDialog + reject() + + + 167 + 490 + + + 169 + 504 + + + + + diff --git a/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py new file mode 100644 index 00000000..e555d7ae --- /dev/null +++ b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +################################################################################ +# Form generated from reading UI file 'ConsoleHistoryDialog.ui' +## +# Created by: Qt User Interface Compiler version 6.1.0 +## +# WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_ConsoleHistoryDialog(object): + def setupUi(self, ConsoleHistoryDialog): + if not ConsoleHistoryDialog.objectName(): + ConsoleHistoryDialog.setObjectName(u"ConsoleHistoryDialog") + ConsoleHistoryDialog.resize(540, 506) + ConsoleHistoryDialog.setSizeGripEnabled(True) + self.gridLayout = QGridLayout(ConsoleHistoryDialog) + self.gridLayout.setObjectName(u"gridLayout") + self.historyList = QListWidget(ConsoleHistoryDialog) + self.historyList.setObjectName(u"historyList") + font = QFont() + font.setFamilies([u"Monospace"]) + self.historyList.setFont(font) + self.historyList.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.historyList.setAlternatingRowColors(True) + self.historyList.setSelectionMode(QAbstractItemView.ExtendedSelection) + self.historyList.setWordWrap(True) + + self.gridLayout.addWidget(self.historyList, 0, 0, 1, 1) + + self.verticalLayout = QVBoxLayout() + self.verticalLayout.setObjectName(u"verticalLayout") + self.deleteButton = QPushButton(ConsoleHistoryDialog) + self.deleteButton.setObjectName(u"deleteButton") + self.deleteButton.setEnabled(False) + + self.verticalLayout.addWidget(self.deleteButton) + + self.copyButton = QPushButton(ConsoleHistoryDialog) + self.copyButton.setObjectName(u"copyButton") + self.copyButton.setEnabled(False) + + self.verticalLayout.addWidget(self.copyButton) + + self.executeButton = QPushButton(ConsoleHistoryDialog) + self.executeButton.setObjectName(u"executeButton") + self.executeButton.setEnabled(False) + + self.verticalLayout.addWidget(self.executeButton) + + self.reloadButton = QPushButton(ConsoleHistoryDialog) + self.reloadButton.setObjectName(u"reloadButton") + + self.verticalLayout.addWidget(self.reloadButton) + + self.verticalSpacer = QSpacerItem( + 72, 208, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer) + + self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1) + + self.buttonBox = QDialogButtonBox(ConsoleHistoryDialog) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setStandardButtons( + QDialogButtonBox.Cancel | QDialogButtonBox.Ok) + + self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 2) + + QWidget.setTabOrder(self.historyList, self.deleteButton) + QWidget.setTabOrder(self.deleteButton, self.copyButton) + QWidget.setTabOrder(self.copyButton, self.executeButton) + QWidget.setTabOrder(self.executeButton, self.reloadButton) + QWidget.setTabOrder(self.reloadButton, self.buttonBox) + + self.retranslateUi(ConsoleHistoryDialog) + self.buttonBox.accepted.connect(ConsoleHistoryDialog.accept) + self.buttonBox.rejected.connect(ConsoleHistoryDialog.reject) + + QMetaObject.connectSlotsByName(ConsoleHistoryDialog) + # setupUi + + def retranslateUi(self, ConsoleHistoryDialog): + ConsoleHistoryDialog.setWindowTitle(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Shell History", None)) +# if QT_CONFIG(tooltip) + self.deleteButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Delete the selected entries", None)) +#endif // QT_CONFIG(tooltip) + self.deleteButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Delete", None)) +# if QT_CONFIG(tooltip) + self.copyButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Copy the selected entries to the current editor", None)) +#endif // QT_CONFIG(tooltip) + self.copyButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"C&opy", None)) +# if QT_CONFIG(tooltip) + self.executeButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Execute the selected entries", None)) +#endif // QT_CONFIG(tooltip) + self.executeButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Execute", None)) +# if QT_CONFIG(tooltip) + self.reloadButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Reload the history", None)) +#endif // QT_CONFIG(tooltip) + self.reloadButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Reload", None)) + # retranslateUi diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py index 8cb374e4..e5ca9412 100644 --- a/pmgwidgets/widgets/basic/others/console.py +++ b/pmgwidgets/widgets/basic/others/console.py @@ -9,13 +9,15 @@ Created on 2020/8/24 @description: Console Widget """ +import json +from features.io import settings import os from typing import Tuple, Dict, Callable from PySide2.QtCore import QObject, Signal, QThread, QWaitCondition, QMutex, QPoint, QCoreApplication, QTranslator, \ QLocale from PySide2.QtGui import QTextCursor -from PySide2.QtWidgets import QMessageBox, QMenu, QApplication +from PySide2.QtWidgets import QMessageBox, QMenu, QApplication, QDialog from qtconsole import styles from qtconsole.manager import QtKernelManager from qtconsole.rich_jupyter_widget import RichJupyterWidget @@ -68,6 +70,8 @@ class PMGIpythonConsole(RichJupyterWidget): self.is_first_execution = True self.confirm_restart = False + self.history_path = os.path.join(settings.get_pyminer_data_path(), 'console_history.json') + self.history = [] self.commands_pool = [] self.command_callback_pool: Dict[str, Callable] = {} @@ -133,6 +137,9 @@ class PMGIpythonConsole(RichJupyterWidget): trans = trans_dic.get(action.text()) trans = trans if trans is not None else action.text() action.setText(trans) + history_action = menu.addAction(_translate("PMGIpythonConsole", 'History')) + history_action.triggered.connect(self.show_history) + restart_action = menu.addAction(_translate("PMGIpythonConsole", 'Restart')) restart_action.triggered.connect(self.slot_restart_kernel) @@ -143,6 +150,17 @@ class PMGIpythonConsole(RichJupyterWidget): return menu + def show_history(self): + """ + Public slot to show the shell history dialog. + """ + from .ConsoleHistoryDialog import ConsoleHistoryDialog + # import readline + dlg = ConsoleHistoryDialog(self) + if dlg.exec() == QDialog.DialogCode.Accepted: + self.history = dlg.get_history() + super()._set_history(self.history) + def on_interrupt_kernel(self): """ 当点击中断执行时。 @@ -200,6 +218,8 @@ class PMGIpythonConsole(RichJupyterWidget): return 'Welcome To PMGWidgets Ipython Console!\n' def closeEvent(self, event): + self.history = self.history_tail(0) + self.save_history() if self.init_thread.isRunning(): self.console_object.stop() self.init_thread.quit() @@ -224,6 +244,14 @@ class PMGIpythonConsole(RichJupyterWidget): :param hint_text: 运行代码前显示的提示 :return: str 执行命令的 msgid """ + self.hint_command(hint_text) + if self.kernel_client is None: + self.commands_pool.append((source, hidden, hint_text)) + return '' + else: + return self.pmexecute(source, hidden) + + def hint_command(self, hint_text: str = '') -> str: cursor: QTextCursor = self._prompt_cursor cursor.movePosition(QTextCursor.End) # 运行文件时,显示文件名,无换行符,执行选中内容时,包含换行符 @@ -239,11 +267,6 @@ class PMGIpythonConsole(RichJupyterWidget): self._finalize_input_request() # display input string buffer in console. cursor.movePosition(QTextCursor.End) - if self.kernel_client is None: - self.commands_pool.append((source, hidden, hint_text)) - return '' - else: - return self.pmexecute(source, hidden) def _handle_stream(self, msg): parent_header = msg.get('parent_header') @@ -304,6 +327,22 @@ class PMGIpythonConsole(RichJupyterWidget): directory=os.path.join(os.path.dirname(__file__), 'translations')) app.installTranslator(_trans) + def _set_history(self, history): + """ 重写的方法。重新管理历史记录。 + """ + self.load_history() + super()._set_history(self.history) + + def load_history(self): + if os.path.exists(self.history_path): + with open(self.history_path) as f: + history = json.load(f) + self.history = history['history'] + + def save_history(self): + history = { 'history': self.history } + with open(self.history_path, 'w') as f: + json.dump(history, f) if __name__ == '__main__': import sys -- Gitee From 34ddb2209c8a1e1c923fc9946074b352538bc1a1 Mon Sep 17 00:00:00 2001 From: siogian Date: Sun, 23 May 2021 19:17:42 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=B8=BA=E6=8E=A7=E5=88=B6=E5=8F=B0?= =?UTF-8?q?=E6=96=B0=E5=A2=9E"=E6=9F=A5=E7=9C=8B=E5=8E=86=E5=8F=B2"?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20https://gitee.com/py2cn/pyminer/issues/I27?= =?UTF-8?q?AQJ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/others/ConsoleHistoryDialog.py | 97 +++++++++++ .../basic/others/ConsoleHistoryDialog.ui | 158 ++++++++++++++++++ .../basic/others/Ui_ConsoleHistoryDialog.py | 115 +++++++++++++ pmgwidgets/widgets/basic/others/console.py | 73 ++++++-- 4 files changed, 431 insertions(+), 12 deletions(-) create mode 100644 pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py create mode 100644 pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui create mode 100644 pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py new file mode 100644 index 00000000..f29581fd --- /dev/null +++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py @@ -0,0 +1,97 @@ +import os + +from PySide2 import QtCore +from PySide2.QtCore import QItemSelectionModel +from PySide2.QtWidgets import QApplication, QDialog +from .Ui_ConsoleHistoryDialog import Ui_ConsoleHistoryDialog + + +class ConsoleHistoryDialog(QDialog, Ui_ConsoleHistoryDialog): + """ + Class implementing the shell history dialog. + """ + + def __init__(self, console): + super().__init__() + self.setupUi(self) + self.__console = console + + self.deleteButton.clicked.connect(self.on_deleteButton_clicked) + self.copyButton.clicked.connect(self.on_copyButton_clicked) + self.reloadButton.clicked.connect(self.on_reloadButton_clicked) + self.historyList.itemSelectionChanged.connect( + self.on_historyList_itemSelectionChanged) + + self.reloadButton.click() + + @QtCore.Slot(QtCore.QModelIndex) + def select(self, item): + print(item.data()) + + @QtCore.Slot() + def on_historyList_itemSelectionChanged(self): + """ + Private slot to handle a change of the selection. + """ + selected = len(self.historyList.selectedItems()) > 0 + self.deleteButton.setEnabled(selected) + self.copyButton.setEnabled(selected) + self.executeButton.setEnabled(selected) + + @QtCore.Slot() + def on_deleteButton_clicked(self): + """ + Private slot to delete the selected entries from the history. + """ + for itm in self.historyList.selectedItems(): + ditm = self.historyList.takeItem(self.historyList.row(itm)) + del ditm + self.historyList.scrollToItem(self.historyList.currentItem()) + self.historyList.setFocus() + + @QtCore.Slot() + def on_copyButton_clicked(self): + cmds = self.selected_cmds() + QApplication.clipboard().setText(cmds) + + @QtCore.Slot() + def on_executeButton_clicked(self): + cmds = self.selected_cmds() + self.__console.hint_command(cmds) + self.__console.do_execute(cmds, True, '') + # reload the list because shell modified it + self.on_reloadButton_clicked() + + @QtCore.Slot() + def on_reloadButton_clicked(self): + """ + Private slot to reload the history. + """ + history = self.__console.history_tail(0) + + self.historyList.clear() + self.historyList.addItems(history) + self.historyList.setCurrentRow( + self.historyList.count() - 1, + QItemSelectionModel.SelectionFlag.Select) + + self.historyList.scrollToItem(self.historyList.currentItem()) + + @QtCore.Slot(QtCore.QModelIndex) + def on_historyList_doubleClicked(self, item): + self.on_executeButton_clicked() + + def get_history(self): + history = [] + for index in range(self.historyList.count()): + history.append(self.historyList.item(index).text()) + return history + + def selected_cmds(self): + lines = [] + for index in range(self.historyList.count()): + # selectedItems() doesn't seem to preserve the order + itm = self.historyList.item(index) + if itm.isSelected(): + lines.append(itm.text()) + return (os.linesep.join(lines) + os.linesep).rstrip(os.linesep) diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui new file mode 100644 index 00000000..59fb2507 --- /dev/null +++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui @@ -0,0 +1,158 @@ + + ShellHistoryDialog + + + + 0 + 0 + 540 + 506 + + + + Shell History + + + true + + + + + + + Monospace + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + true + + + + + + + + + false + + + Delete the selected entries + + + &Delete + + + + + + + false + + + Copy the selected entries to the current editor + + + C&opy + + + + + + + false + + + Execute the selected entries + + + &Execute + + + + + + + Reload the history + + + &Reload + + + + + + + Qt::Vertical + + + + 72 + 208 + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + historyList + deleteButton + copyButton + executeButton + reloadButton + buttonBox + + + + + buttonBox + accepted() + ShellHistoryDialog + accept() + + + 333 + 487 + + + 323 + 505 + + + + + buttonBox + rejected() + ShellHistoryDialog + reject() + + + 167 + 490 + + + 169 + 504 + + + + + diff --git a/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py new file mode 100644 index 00000000..e555d7ae --- /dev/null +++ b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +################################################################################ +# Form generated from reading UI file 'ConsoleHistoryDialog.ui' +## +# Created by: Qt User Interface Compiler version 6.1.0 +## +# WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_ConsoleHistoryDialog(object): + def setupUi(self, ConsoleHistoryDialog): + if not ConsoleHistoryDialog.objectName(): + ConsoleHistoryDialog.setObjectName(u"ConsoleHistoryDialog") + ConsoleHistoryDialog.resize(540, 506) + ConsoleHistoryDialog.setSizeGripEnabled(True) + self.gridLayout = QGridLayout(ConsoleHistoryDialog) + self.gridLayout.setObjectName(u"gridLayout") + self.historyList = QListWidget(ConsoleHistoryDialog) + self.historyList.setObjectName(u"historyList") + font = QFont() + font.setFamilies([u"Monospace"]) + self.historyList.setFont(font) + self.historyList.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.historyList.setAlternatingRowColors(True) + self.historyList.setSelectionMode(QAbstractItemView.ExtendedSelection) + self.historyList.setWordWrap(True) + + self.gridLayout.addWidget(self.historyList, 0, 0, 1, 1) + + self.verticalLayout = QVBoxLayout() + self.verticalLayout.setObjectName(u"verticalLayout") + self.deleteButton = QPushButton(ConsoleHistoryDialog) + self.deleteButton.setObjectName(u"deleteButton") + self.deleteButton.setEnabled(False) + + self.verticalLayout.addWidget(self.deleteButton) + + self.copyButton = QPushButton(ConsoleHistoryDialog) + self.copyButton.setObjectName(u"copyButton") + self.copyButton.setEnabled(False) + + self.verticalLayout.addWidget(self.copyButton) + + self.executeButton = QPushButton(ConsoleHistoryDialog) + self.executeButton.setObjectName(u"executeButton") + self.executeButton.setEnabled(False) + + self.verticalLayout.addWidget(self.executeButton) + + self.reloadButton = QPushButton(ConsoleHistoryDialog) + self.reloadButton.setObjectName(u"reloadButton") + + self.verticalLayout.addWidget(self.reloadButton) + + self.verticalSpacer = QSpacerItem( + 72, 208, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.verticalSpacer) + + self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1) + + self.buttonBox = QDialogButtonBox(ConsoleHistoryDialog) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setStandardButtons( + QDialogButtonBox.Cancel | QDialogButtonBox.Ok) + + self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 2) + + QWidget.setTabOrder(self.historyList, self.deleteButton) + QWidget.setTabOrder(self.deleteButton, self.copyButton) + QWidget.setTabOrder(self.copyButton, self.executeButton) + QWidget.setTabOrder(self.executeButton, self.reloadButton) + QWidget.setTabOrder(self.reloadButton, self.buttonBox) + + self.retranslateUi(ConsoleHistoryDialog) + self.buttonBox.accepted.connect(ConsoleHistoryDialog.accept) + self.buttonBox.rejected.connect(ConsoleHistoryDialog.reject) + + QMetaObject.connectSlotsByName(ConsoleHistoryDialog) + # setupUi + + def retranslateUi(self, ConsoleHistoryDialog): + ConsoleHistoryDialog.setWindowTitle(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Shell History", None)) +# if QT_CONFIG(tooltip) + self.deleteButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Delete the selected entries", None)) +#endif // QT_CONFIG(tooltip) + self.deleteButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Delete", None)) +# if QT_CONFIG(tooltip) + self.copyButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Copy the selected entries to the current editor", None)) +#endif // QT_CONFIG(tooltip) + self.copyButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"C&opy", None)) +# if QT_CONFIG(tooltip) + self.executeButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Execute the selected entries", None)) +#endif // QT_CONFIG(tooltip) + self.executeButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Execute", None)) +# if QT_CONFIG(tooltip) + self.reloadButton.setToolTip(QCoreApplication.translate( + "ConsoleHistoryDialog", u"Reload the history", None)) +#endif // QT_CONFIG(tooltip) + self.reloadButton.setText(QCoreApplication.translate( + "ConsoleHistoryDialog", u"&Reload", None)) + # retranslateUi diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py index 8cb374e4..6dcb1e9d 100644 --- a/pmgwidgets/widgets/basic/others/console.py +++ b/pmgwidgets/widgets/basic/others/console.py @@ -10,16 +10,19 @@ Created on 2020/8/24 """ import os +import json from typing import Tuple, Dict, Callable from PySide2.QtCore import QObject, Signal, QThread, QWaitCondition, QMutex, QPoint, QCoreApplication, QTranslator, \ QLocale from PySide2.QtGui import QTextCursor -from PySide2.QtWidgets import QMessageBox, QMenu, QApplication +from PySide2.QtWidgets import QMessageBox, QMenu, QApplication, QDialog from qtconsole import styles from qtconsole.manager import QtKernelManager from qtconsole.rich_jupyter_widget import RichJupyterWidget from qtconsole.styles import default_light_syntax_style, default_light_style_sheet +from features.io import settings + default_dark_style_template = styles.default_template + """\ .in-prompt { color: #ff00ff; } @@ -55,7 +58,8 @@ class ConsoleInitThread(QObject): # stop channels and kernel kernel_client.stop_channels() - kernel_manager.shutdown_kernel(now=True) # add now=True; Fix exit error; 200924 liugang + # add now=True; Fix exit error; 200924 liugang + kernel_manager.shutdown_kernel(now=True) def stop(self): self.wait_condition.wakeAll() @@ -68,6 +72,9 @@ class PMGIpythonConsole(RichJupyterWidget): self.is_first_execution = True self.confirm_restart = False + self.history_path = os.path.join( + settings.get_pyminer_data_path(), 'console_history.json') + self.history = [] self.commands_pool = [] self.command_callback_pool: Dict[str, Callable] = {} @@ -133,16 +140,33 @@ class PMGIpythonConsole(RichJupyterWidget): trans = trans_dic.get(action.text()) trans = trans if trans is not None else action.text() action.setText(trans) - restart_action = menu.addAction(_translate("PMGIpythonConsole", 'Restart')) + history_action = menu.addAction( + _translate("PMGIpythonConsole", 'History')) + history_action.triggered.connect(self.show_history) + + restart_action = menu.addAction( + _translate("PMGIpythonConsole", 'Restart')) restart_action.triggered.connect(self.slot_restart_kernel) - stop_action = menu.addAction(_translate("PMGIpythonConsole", 'Interrupt')) + stop_action = menu.addAction( + _translate("PMGIpythonConsole", 'Interrupt')) # stop_action.triggered.connect(self.request_interrupt_kernel) stop_action.triggered.connect(self.on_interrupt_kernel) # stop_action.setEnabled(self._executing) return menu + def show_history(self): + """ + Public slot to show the shell history dialog. + """ + from .ConsoleHistoryDialog import ConsoleHistoryDialog + # import readline + dlg = ConsoleHistoryDialog(self) + if dlg.exec() == QDialog.DialogCode.Accepted: + self.history = dlg.get_history() + super()._set_history(self.history) + def on_interrupt_kernel(self): """ 当点击中断执行时。 @@ -200,6 +224,8 @@ class PMGIpythonConsole(RichJupyterWidget): return 'Welcome To PMGWidgets Ipython Console!\n' def closeEvent(self, event): + self.history = self.history_tail(0) + self.save_history() if self.init_thread.isRunning(): self.console_object.stop() self.init_thread.quit() @@ -224,6 +250,14 @@ class PMGIpythonConsole(RichJupyterWidget): :param hint_text: 运行代码前显示的提示 :return: str 执行命令的 msgid """ + self.hint_command(hint_text) + if self.kernel_client is None: + self.commands_pool.append((source, hidden, hint_text)) + return '' + else: + return self.pmexecute(source, hidden) + + def hint_command(self, hint_text: str = '') -> str: cursor: QTextCursor = self._prompt_cursor cursor.movePosition(QTextCursor.End) # 运行文件时,显示文件名,无换行符,执行选中内容时,包含换行符 @@ -237,18 +271,15 @@ class PMGIpythonConsole(RichJupyterWidget): # 删除多余的continuation_prompt self.undo() - self._finalize_input_request() # display input string buffer in console. + # display input string buffer in console. + self._finalize_input_request() cursor.movePosition(QTextCursor.End) - if self.kernel_client is None: - self.commands_pool.append((source, hidden, hint_text)) - return '' - else: - return self.pmexecute(source, hidden) def _handle_stream(self, msg): parent_header = msg.get('parent_header') if parent_header is not None: - msg_id = parent_header.get('msg_id') # 'fee0bee5-074c00d093b1455be6d166b1_10''] + # 'fee0bee5-074c00d093b1455be6d166b1_10''] + msg_id = parent_header.get('msg_id') if msg_id in self.command_callback_pool.keys(): callback = self.command_callback_pool.pop(msg_id) assert callable(callback) @@ -273,7 +304,8 @@ class PMGIpythonConsole(RichJupyterWidget): QMessageBox.warning(self, '警告', msg) source = '' msg_id = self.kernel_client.execute(source, hidden) - self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'user') + self._request_info['execute'][msg_id] = self._ExecutionRequest( + msg_id, 'user') self._hidden = hidden if not hidden: self.executing.emit(source) @@ -304,6 +336,23 @@ class PMGIpythonConsole(RichJupyterWidget): directory=os.path.join(os.path.dirname(__file__), 'translations')) app.installTranslator(_trans) + def _set_history(self, history): + """ 重写的方法。重新管理历史记录。 + """ + self.load_history() + super()._set_history(self.history) + + def load_history(self): + if os.path.exists(self.history_path): + with open(self.history_path) as f: + history = json.load(f) + self.history = history['history'] + + def save_history(self): + history = {'history': self.history} + with open(self.history_path, 'w') as f: + json.dump(history, f) + if __name__ == '__main__': import sys -- Gitee From 969ace8f0866f4784642f8c47124f875d0d1bdeb Mon Sep 17 00:00:00 2001 From: siogian Date: Mon, 24 May 2021 07:40:20 +0800 Subject: [PATCH 4/4] autopep8 format --- pmgwidgets/widgets/basic/others/console.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py index e5ca9412..d533453d 100644 --- a/pmgwidgets/widgets/basic/others/console.py +++ b/pmgwidgets/widgets/basic/others/console.py @@ -9,9 +9,8 @@ Created on 2020/8/24 @description: Console Widget """ -import json -from features.io import settings import os +import json from typing import Tuple, Dict, Callable from PySide2.QtCore import QObject, Signal, QThread, QWaitCondition, QMutex, QPoint, QCoreApplication, QTranslator, \ @@ -22,6 +21,7 @@ from qtconsole import styles from qtconsole.manager import QtKernelManager from qtconsole.rich_jupyter_widget import RichJupyterWidget from qtconsole.styles import default_light_syntax_style, default_light_style_sheet +from features.io import settings default_dark_style_template = styles.default_template + """\ .in-prompt { color: #ff00ff; } @@ -137,13 +137,16 @@ class PMGIpythonConsole(RichJupyterWidget): trans = trans_dic.get(action.text()) trans = trans if trans is not None else action.text() action.setText(trans) - history_action = menu.addAction(_translate("PMGIpythonConsole", 'History')) + history_action = menu.addAction( + _translate("PMGIpythonConsole", 'History')) history_action.triggered.connect(self.show_history) - restart_action = menu.addAction(_translate("PMGIpythonConsole", 'Restart')) + restart_action = menu.addAction( + _translate("PMGIpythonConsole", 'Restart')) restart_action.triggered.connect(self.slot_restart_kernel) - stop_action = menu.addAction(_translate("PMGIpythonConsole", 'Interrupt')) + stop_action = menu.addAction( + _translate("PMGIpythonConsole", 'Interrupt')) # stop_action.triggered.connect(self.request_interrupt_kernel) stop_action.triggered.connect(self.on_interrupt_kernel) # stop_action.setEnabled(self._executing) @@ -265,7 +268,8 @@ class PMGIpythonConsole(RichJupyterWidget): # 删除多余的continuation_prompt self.undo() - self._finalize_input_request() # display input string buffer in console. + # display input string buffer in console. + self._finalize_input_request() cursor.movePosition(QTextCursor.End) def _handle_stream(self, msg): @@ -340,7 +344,7 @@ class PMGIpythonConsole(RichJupyterWidget): self.history = history['history'] def save_history(self): - history = { 'history': self.history } + history = {'history': self.history} with open(self.history_path, 'w') as f: json.dump(history, f) -- Gitee