bugfixes (#191)
All checks were successful
Build AppImage / Explore-Gitea-Actions (push) Successful in 2m2s
All checks were successful
Build AppImage / Explore-Gitea-Actions (push) Successful in 2m2s
added basic syntax check; closes #148 Co-authored-by: Dominik Demuth <dominik.demuth@physik.tu-darmstadt.de> Reviewed-on: #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'
|
# 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
|
# 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.
|
# 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 = QtWidgets.QVBoxLayout(self.namespace_box)
|
||||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||||
self.tabWidget.addTab(self.namespace_box, "")
|
self.tabWidget.addTab(self.namespace_box, "")
|
||||||
self.plainTextEdit = CodeEditor(self.splitter)
|
self.editor = EditorWidget(self.splitter)
|
||||||
self.plainTextEdit.setEnabled(True)
|
self.editor.setObjectName("editor")
|
||||||
self.plainTextEdit.setObjectName("plainTextEdit")
|
|
||||||
self.verticalLayout.addWidget(self.splitter)
|
self.verticalLayout.addWidget(self.splitter)
|
||||||
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
|
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
|
||||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||||
@ -63,8 +62,8 @@ class Ui_Dialog(object):
|
|||||||
|
|
||||||
self.retranslateUi(Dialog)
|
self.retranslateUi(Dialog)
|
||||||
self.tabWidget.setCurrentIndex(0)
|
self.tabWidget.setCurrentIndex(0)
|
||||||
self.buttonBox.accepted.connect(Dialog.accept)
|
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
|
||||||
self.buttonBox.rejected.connect(Dialog.reject)
|
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
|
||||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
|
||||||
def retranslateUi(self, 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.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.kwargs_box), _translate("Dialog", "Multiple choice"))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.namespace_box), _translate("Dialog", "Available Functions"))
|
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'
|
# 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
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
@ -20,15 +21,12 @@ class Ui_MainWindow(object):
|
|||||||
self.verticalLayout.setContentsMargins(3, 3, 3, 3)
|
self.verticalLayout.setContentsMargins(3, 3, 3, 3)
|
||||||
self.verticalLayout.setSpacing(3)
|
self.verticalLayout.setSpacing(3)
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
self.edit_field = CodeEditor(self.centralwidget)
|
self.widget = EditorWidget(self.centralwidget)
|
||||||
font = QtGui.QFont()
|
self.widget.setObjectName("widget")
|
||||||
font.setPointSize(10)
|
self.verticalLayout.addWidget(self.widget)
|
||||||
self.edit_field.setFont(font)
|
|
||||||
self.edit_field.setObjectName("edit_field")
|
|
||||||
self.verticalLayout.addWidget(self.edit_field)
|
|
||||||
MainWindow.setCentralWidget(self.centralwidget)
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
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.menubar.setObjectName("menubar")
|
||||||
self.menuFile = QtWidgets.QMenu(self.menubar)
|
self.menuFile = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuFile.setObjectName("menuFile")
|
self.menuFile.setObjectName("menuFile")
|
||||||
@ -61,4 +59,4 @@ class Ui_MainWindow(object):
|
|||||||
self.actionSave.setText(_translate("MainWindow", "Save"))
|
self.actionSave.setText(_translate("MainWindow", "Save"))
|
||||||
self.actionSave_as.setText(_translate("MainWindow", "Save as..."))
|
self.actionSave_as.setText(_translate("MainWindow", "Save as..."))
|
||||||
self.actionClose.setText(_translate("MainWindow", "Close"))
|
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
|
return self
|
||||||
|
|
||||||
def update_function(self):
|
def update_function(self):
|
||||||
prev_text = self.plainTextEdit.toPlainText().split('\n')
|
prev_text = self.editor.toPlainText().split('\n')
|
||||||
func_body = ''
|
func_body = ''
|
||||||
in_body = False
|
in_body = False
|
||||||
for line in prev_text:
|
for line in prev_text:
|
||||||
@ -89,9 +89,12 @@ class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
else:
|
else:
|
||||||
k += f' def func(x):\n'
|
k += f' def func(x):\n'
|
||||||
|
|
||||||
|
if func_body:
|
||||||
k += func_body
|
k += func_body
|
||||||
|
else:
|
||||||
|
k += ' return x'
|
||||||
|
|
||||||
self.plainTextEdit.setPlainText(k)
|
self.editor.setPlainText(k)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QtWidgets.QMessageBox.warning(self, 'Failure', f'Error found: {e.args[0]}')
|
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()):
|
for i in range(self.choices.count()):
|
||||||
kwargs.append(self.choices.widget(i).get_strings())
|
kwargs.append(self.choices.widget(i).get_strings())
|
||||||
if kwargs:
|
if kwargs:
|
||||||
return f" choices = {', '.join(kwargs)}\n"
|
return f" choices = [{', '.join(kwargs)}]\n"
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@ -475,12 +478,3 @@ class DescWidget(QtWidgets.QWidget):
|
|||||||
f" equation = r'{self.eq_lineedit.text()}'\n"
|
f" equation = r'{self.eq_lineedit.text()}'\n"
|
||||||
|
|
||||||
return stringi
|
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']),
|
(r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),
|
||||||
# 'class' followed by an identifier
|
# 'class' followed by an identifier
|
||||||
(r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),
|
(r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),
|
||||||
# @ followed by a word
|
|
||||||
|
# decorator @ followed by a word
|
||||||
(r'\s*@(\w+)\s*', 0, STYLES['property']),
|
(r'\s*@(\w+)\s*', 0, STYLES['property']),
|
||||||
|
|
||||||
# Numeric literals
|
# Numeric literals
|
||||||
@ -80,7 +81,6 @@ class PythonHighlighter(QtGui.QSyntaxHighlighter):
|
|||||||
(r'\b[+-]?0[xX][\dA-Fa-f]+[lL]?\b', 0, STYLES['numbers']),
|
(r'\b[+-]?0[xX][\dA-Fa-f]+[lL]?\b', 0, STYLES['numbers']),
|
||||||
(r'\b[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b', 0, STYLES['numbers']),
|
(r'\b[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b', 0, STYLES['numbers']),
|
||||||
|
|
||||||
|
|
||||||
# Double-quoted string, possibly containing escape sequences
|
# Double-quoted string, possibly containing escape sequences
|
||||||
(r'[rf]?"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
|
(r'[rf]?"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
|
||||||
# Single-quoted string, possibly containing escape sequences
|
# Single-quoted string, possibly containing escape sequences
|
||||||
@ -185,7 +185,6 @@ class CodeEditor(QtWidgets.QPlainTextEdit):
|
|||||||
self.update_width_linenumber(0)
|
self.update_width_linenumber(0)
|
||||||
|
|
||||||
self.highlight = PythonHighlighter(self.document())
|
self.highlight = PythonHighlighter(self.document())
|
||||||
self.textChanged.connect(self._check_syntax)
|
|
||||||
|
|
||||||
def keyPressEvent(self, evt):
|
def keyPressEvent(self, evt):
|
||||||
if evt.key() == QtCore.Qt.Key_Tab:
|
if evt.key() == QtCore.Qt.Key_Tab:
|
||||||
@ -263,22 +262,48 @@ class CodeEditor(QtWidgets.QPlainTextEdit):
|
|||||||
|
|
||||||
self.setExtraSelections(extra_selections)
|
self.setExtraSelections(extra_selections)
|
||||||
|
|
||||||
def color_line(self, color):
|
|
||||||
# is_valid, exception = self._check_syntax()
|
class EditorWidget(QtWidgets.QWidget):
|
||||||
# if is_valid == 1:
|
def __init__(self, parent=None):
|
||||||
doc = self.document()
|
super().__init__(parent=parent)
|
||||||
print(doc.findBlockByLineNumber(color))
|
|
||||||
|
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]):
|
def _check_syntax(self) -> (int, tuple[typing.Any]):
|
||||||
|
is_valid = True
|
||||||
|
|
||||||
# Compile into an AST and check for syntax errors.
|
# Compile into an AST and check for syntax errors.
|
||||||
try:
|
try:
|
||||||
_ = parse(self.toPlainText(), filename='<string>')
|
_ = 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 pathlib import Path
|
||||||
|
|
||||||
from ..Qt import QtWidgets, QtCore, QtGui
|
from ..Qt import QtWidgets, QtCore, QtGui
|
||||||
from ..lib.codeeditor import CodeEditor
|
from ..lib.codeeditor import EditorWidget
|
||||||
|
|
||||||
|
|
||||||
class QUsermodelEditor(QtWidgets.QMainWindow):
|
class QUsermodelEditor(QtWidgets.QMainWindow):
|
||||||
@ -26,7 +26,7 @@ class QUsermodelEditor(QtWidgets.QMainWindow):
|
|||||||
layout.setContentsMargins(3, 3, 3, 3)
|
layout.setContentsMargins(3, 3, 3, 3)
|
||||||
layout.setSpacing(3)
|
layout.setSpacing(3)
|
||||||
|
|
||||||
self.edit_field = CodeEditor(self.centralwidget)
|
self.edit_field = EditorWidget(self.centralwidget)
|
||||||
font = QtGui.QFont('default')
|
font = QtGui.QFont('default')
|
||||||
font.setStyleHint(font.Monospace)
|
font.setStyleHint(font.Monospace)
|
||||||
font.setPointSize(10)
|
font.setPointSize(10)
|
||||||
|
@ -86,11 +86,7 @@
|
|||||||
<layout class="QVBoxLayout" name="verticalLayout_6"/>
|
<layout class="QVBoxLayout" name="verticalLayout_6"/>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="CodeEditor" name="plainTextEdit">
|
<widget class="EditorWidget" name="editor" native="true"/>
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -107,9 +103,10 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>CodeEditor</class>
|
<class>EditorWidget</class>
|
||||||
<extends>QPlainTextEdit</extends>
|
<extends>QWidget</extends>
|
||||||
<header>..lib.codeeditor</header>
|
<header>..lib.codeeditor</header>
|
||||||
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -31,13 +31,7 @@
|
|||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="CodeEditor" name="edit_field">
|
<widget class="EditorWidget" name="widget" native="true"/>
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<pointsize>10</pointsize>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -47,7 +41,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>30</height>
|
<height>20</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
@ -85,9 +79,10 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>CodeEditor</class>
|
<class>EditorWidget</class>
|
||||||
<extends>QPlainTextEdit</extends>
|
<extends>QWidget</extends>
|
||||||
<header>..lib.codeeditor</header>
|
<header>..lib.codeeditor</header>
|
||||||
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
Loading…
Reference in New Issue
Block a user