forked from IPKM/nmreval
bugfixes (#191)
added basic syntax check; closes #148 Co-authored-by: Dominik Demuth <dominik.demuth@physik.tu-darmstadt.de> Reviewed-on: IPKM/nmreval#191
This commit is contained in:
parent
2cf94af2c4
commit
694d47267d
@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'resources/_ui/fitcreationdialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.4
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
@ -51,9 +51,8 @@ class Ui_Dialog(object):
|
||||
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.namespace_box)
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.tabWidget.addTab(self.namespace_box, "")
|
||||
self.plainTextEdit = CodeEditor(self.splitter)
|
||||
self.plainTextEdit.setEnabled(True)
|
||||
self.plainTextEdit.setObjectName("plainTextEdit")
|
||||
self.editor = EditorWidget(self.splitter)
|
||||
self.editor.setObjectName("editor")
|
||||
self.verticalLayout.addWidget(self.splitter)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
@ -63,8 +62,8 @@ class Ui_Dialog(object):
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
self.buttonBox.accepted.connect(Dialog.accept)
|
||||
self.buttonBox.rejected.connect(Dialog.reject)
|
||||
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
@ -74,4 +73,4 @@ class Ui_Dialog(object):
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.args_box), _translate("Dialog", "Variables"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.kwargs_box), _translate("Dialog", "Multiple choice"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.namespace_box), _translate("Dialog", "Available Functions"))
|
||||
from ..lib.codeeditor import CodeEditor
|
||||
from ..lib.codeeditor import EditorWidget
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'resources/_ui/usermodeleditor.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.12.3
|
||||
# Created by: PyQt5 UI code generator 5.15.10
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@ -20,15 +21,12 @@ class Ui_MainWindow(object):
|
||||
self.verticalLayout.setContentsMargins(3, 3, 3, 3)
|
||||
self.verticalLayout.setSpacing(3)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.edit_field = CodeEditor(self.centralwidget)
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
self.edit_field.setFont(font)
|
||||
self.edit_field.setObjectName("edit_field")
|
||||
self.verticalLayout.addWidget(self.edit_field)
|
||||
self.widget = EditorWidget(self.centralwidget)
|
||||
self.widget.setObjectName("widget")
|
||||
self.verticalLayout.addWidget(self.widget)
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30))
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20))
|
||||
self.menubar.setObjectName("menubar")
|
||||
self.menuFile = QtWidgets.QMenu(self.menubar)
|
||||
self.menuFile.setObjectName("menuFile")
|
||||
@ -61,4 +59,4 @@ class Ui_MainWindow(object):
|
||||
self.actionSave.setText(_translate("MainWindow", "Save"))
|
||||
self.actionSave_as.setText(_translate("MainWindow", "Save as..."))
|
||||
self.actionClose.setText(_translate("MainWindow", "Close"))
|
||||
from ..lib.codeeditor import CodeEditor
|
||||
from ..lib.codeeditor import EditorWidget
|
||||
|
@ -54,7 +54,7 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
|
||||
return self
|
||||
|
||||
def update_function(self):
|
||||
prev_text = self.plainTextEdit.toPlainText().split('\n')
|
||||
prev_text = self.editor.toPlainText().split('\n')
|
||||
func_body = ''
|
||||
in_body = False
|
||||
for line in prev_text:
|
||||
@ -89,9 +89,12 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
|
||||
else:
|
||||
k += f' def func(x):\n'
|
||||
|
||||
if func_body:
|
||||
k += func_body
|
||||
else:
|
||||
k += ' return x'
|
||||
|
||||
self.plainTextEdit.setPlainText(k)
|
||||
self.editor.setPlainText(k)
|
||||
except Exception as e:
|
||||
QtWidgets.QMessageBox.warning(self, 'Failure', f'Error found: {e.args[0]}')
|
||||
|
||||
@ -215,7 +218,7 @@ class KwargsWidget(QtWidgets.QWidget):
|
||||
for i in range(self.choices.count()):
|
||||
kwargs.append(self.choices.widget(i).get_strings())
|
||||
if kwargs:
|
||||
return f" choices = {', '.join(kwargs)}\n"
|
||||
return f" choices = [{', '.join(kwargs)}]\n"
|
||||
else:
|
||||
return ''
|
||||
|
||||
@ -475,12 +478,3 @@ class DescWidget(QtWidgets.QWidget):
|
||||
f" equation = r'{self.eq_lineedit.text()}'\n"
|
||||
|
||||
return stringi
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
app = QtWidgets.QApplication([])
|
||||
win = QUserFitCreator()
|
||||
win.show()
|
||||
|
||||
sys.exit(app.exec())
|
||||
|
@ -72,7 +72,8 @@ class PythonHighlighter(QtGui.QSyntaxHighlighter):
|
||||
(r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),
|
||||
# 'class' followed by an identifier
|
||||
(r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),
|
||||
# @ followed by a word
|
||||
|
||||
# decorator @ followed by a word
|
||||
(r'\s*@(\w+)\s*', 0, STYLES['property']),
|
||||
|
||||
# Numeric literals
|
||||
@ -80,7 +81,6 @@ class PythonHighlighter(QtGui.QSyntaxHighlighter):
|
||||
(r'\b[+-]?0[xX][\dA-Fa-f]+[lL]?\b', 0, STYLES['numbers']),
|
||||
(r'\b[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b', 0, STYLES['numbers']),
|
||||
|
||||
|
||||
# Double-quoted string, possibly containing escape sequences
|
||||
(r'[rf]?"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
|
||||
# Single-quoted string, possibly containing escape sequences
|
||||
@ -185,7 +185,6 @@ class CodeEditor(QtWidgets.QPlainTextEdit):
|
||||
self.update_width_linenumber(0)
|
||||
|
||||
self.highlight = PythonHighlighter(self.document())
|
||||
self.textChanged.connect(self._check_syntax)
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
if evt.key() == QtCore.Qt.Key_Tab:
|
||||
@ -263,22 +262,48 @@ class CodeEditor(QtWidgets.QPlainTextEdit):
|
||||
|
||||
self.setExtraSelections(extra_selections)
|
||||
|
||||
def color_line(self, color):
|
||||
# is_valid, exception = self._check_syntax()
|
||||
# if is_valid == 1:
|
||||
doc = self.document()
|
||||
print(doc.findBlockByLineNumber(color))
|
||||
|
||||
class EditorWidget(QtWidgets.QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.editor = CodeEditor(self)
|
||||
layout.addWidget(self.editor)
|
||||
|
||||
self.error_label = QtWidgets.QLabel(self)
|
||||
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.error_label.setFont(font)
|
||||
|
||||
self.error_label.setVisible(False)
|
||||
|
||||
layout.addWidget(self.error_label)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
for attr in ['appendPlainText', 'toPlainText', 'insertPlainText', 'setPlainText']:
|
||||
setattr(self, attr, getattr(self.editor, attr))
|
||||
|
||||
self.editor.textChanged.connect(self._check_syntax)
|
||||
|
||||
def _check_syntax(self) -> (int, tuple[typing.Any]):
|
||||
is_valid = True
|
||||
|
||||
# Compile into an AST and check for syntax errors.
|
||||
try:
|
||||
_ = parse(self.toPlainText(), filename='<string>')
|
||||
except SyntaxError as e:
|
||||
print('SyntaxError', e, e.args[0], e.lineno, e.offset, e.text)
|
||||
self.color_line(e.lineno)
|
||||
return 1, (e.lineno, e.offset)
|
||||
except Exception as e:
|
||||
print('Unexpected error', e)
|
||||
return 2, (e.args[0],)
|
||||
|
||||
return 0, tuple()
|
||||
except SyntaxError as e:
|
||||
self.error_label.setText(f'Syntax error in line {e.lineno}: {e.args[0]}')
|
||||
is_valid = False
|
||||
|
||||
except Exception as e:
|
||||
self.error_label.setText(f'Unexpected error: {e.args[0]}')
|
||||
is_valid = False
|
||||
|
||||
self.error_label.setVisible(not is_valid)
|
||||
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
|
||||
from ..Qt import QtWidgets, QtCore, QtGui
|
||||
from ..lib.codeeditor import CodeEditor
|
||||
from ..lib.codeeditor import EditorWidget
|
||||
|
||||
|
||||
class QUsermodelEditor(QtWidgets.QMainWindow):
|
||||
@ -26,7 +26,7 @@ class QUsermodelEditor(QtWidgets.QMainWindow):
|
||||
layout.setContentsMargins(3, 3, 3, 3)
|
||||
layout.setSpacing(3)
|
||||
|
||||
self.edit_field = CodeEditor(self.centralwidget)
|
||||
self.edit_field = EditorWidget(self.centralwidget)
|
||||
font = QtGui.QFont('default')
|
||||
font.setStyleHint(font.Monospace)
|
||||
font.setPointSize(10)
|
||||
|
@ -86,11 +86,7 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6"/>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="CodeEditor" name="plainTextEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="EditorWidget" name="editor" native="true"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -107,9 +103,10 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CodeEditor</class>
|
||||
<extends>QPlainTextEdit</extends>
|
||||
<class>EditorWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>..lib.codeeditor</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
|
@ -31,13 +31,7 @@
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CodeEditor" name="edit_field">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="EditorWidget" name="widget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -47,7 +41,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>30</height>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@ -85,9 +79,10 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CodeEditor</class>
|
||||
<extends>QPlainTextEdit</extends>
|
||||
<class>EditorWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>..lib.codeeditor</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
|
Loading…
Reference in New Issue
Block a user