myokit 1.33.9__py3-none-any.whl → 1.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myokit/__init__.py +9 -36
- myokit/__main__.py +76 -142
- myokit/_aux.py +62 -16
- myokit/_bin/example.mmt +1 -2
- myokit/_bin/install-win/menu.json +7 -7
- myokit/_config.py +22 -31
- myokit/_datablock.py +30 -74
- myokit/_datalog.py +49 -72
- myokit/_err.py +25 -24
- myokit/_expressions.py +50 -68
- myokit/_io.py +15 -27
- myokit/_model_api.py +453 -249
- myokit/_myokit_version.py +1 -5
- myokit/_parsing.py +38 -44
- myokit/_progress.py +5 -8
- myokit/_protocol.py +99 -9
- myokit/_sim/__init__.py +7 -24
- myokit/_sim/cable.c +6 -8
- myokit/_sim/cable.py +6 -8
- myokit/_sim/cmodel.h +125 -70
- myokit/_sim/cmodel.py +12 -14
- myokit/_sim/compiler.py +1 -4
- myokit/_sim/cvodessim.c +196 -118
- myokit/_sim/cvodessim.py +130 -103
- myokit/_sim/differential.hpp +4 -4
- myokit/_sim/fiber_tissue.c +4 -8
- myokit/_sim/fiber_tissue.py +11 -13
- myokit/_sim/jacobian.cpp +2 -2
- myokit/_sim/jacobian.py +11 -8
- myokit/_sim/mcl.h +53 -55
- myokit/_sim/opencl.py +21 -27
- myokit/_sim/openclsim.c +3 -7
- myokit/_sim/openclsim.cl +3 -3
- myokit/_sim/openclsim.py +49 -40
- myokit/_sim/pacing.h +36 -16
- myokit/_sim/rhs.c +6 -13
- myokit/_sim/rhs.py +5 -14
- myokit/_sim/sundials.py +1 -4
- myokit/_system.py +10 -16
- myokit/_unit.py +4 -13
- myokit/float.py +0 -3
- myokit/formats/__init__.py +8 -10
- myokit/formats/ansic/__init__.py +0 -3
- myokit/formats/ansic/_ewriter.py +2 -4
- myokit/formats/ansic/_exporter.py +1 -4
- myokit/formats/ansic/template/cable.c +4 -4
- myokit/formats/ansic/template/euler.c +5 -5
- myokit/formats/ansic/template/sim.c +6 -6
- myokit/formats/axon/__init__.py +1 -3
- myokit/formats/axon/_abf.py +12 -17
- myokit/formats/axon/_atf.py +5 -6
- myokit/formats/axon/_importer.py +0 -3
- myokit/formats/cellml/__init__.py +0 -3
- myokit/formats/cellml/_ewriter.py +3 -6
- myokit/formats/cellml/_exporter.py +3 -6
- myokit/formats/cellml/_importer.py +1 -4
- myokit/formats/cellml/v1/__init__.py +0 -4
- myokit/formats/cellml/v1/_api.py +8 -11
- myokit/formats/cellml/v1/_parser.py +2 -5
- myokit/formats/cellml/v1/_writer.py +2 -11
- myokit/formats/cellml/v2/__init__.py +0 -3
- myokit/formats/cellml/v2/_api.py +8 -17
- myokit/formats/cellml/v2/_parser.py +2 -5
- myokit/formats/cellml/v2/_writer.py +1 -4
- myokit/formats/channelml/__init__.py +0 -3
- myokit/formats/channelml/_importer.py +11 -21
- myokit/formats/cpp/__init__.py +1 -3
- myokit/formats/cpp/_ewriter.py +0 -3
- myokit/formats/cuda/__init__.py +0 -3
- myokit/formats/cuda/_ewriter.py +2 -4
- myokit/formats/cuda/_exporter.py +0 -3
- myokit/formats/cuda/template/kernel.cu +8 -5
- myokit/formats/easyml/__init__.py +0 -3
- myokit/formats/easyml/_ewriter.py +9 -11
- myokit/formats/easyml/_exporter.py +2 -5
- myokit/formats/html/__init__.py +0 -3
- myokit/formats/html/_exporter.py +0 -3
- myokit/formats/html/_flatten.py +5 -21
- myokit/formats/latex/__init__.py +0 -3
- myokit/formats/latex/_ewriter.py +1 -4
- myokit/formats/latex/_exporter.py +4 -6
- myokit/formats/mathml/__init__.py +0 -3
- myokit/formats/mathml/_ewriter.py +2 -11
- myokit/formats/mathml/_parser.py +4 -6
- myokit/formats/matlab/__init__.py +0 -3
- myokit/formats/matlab/_ewriter.py +1 -4
- myokit/formats/matlab/_exporter.py +2 -5
- myokit/formats/matlab/template/main.m +3 -2
- myokit/formats/opencl/__init__.py +0 -3
- myokit/formats/opencl/_ewriter.py +2 -4
- myokit/formats/opencl/_exporter.py +2 -5
- myokit/formats/opencl/template/cable.c +10 -10
- myokit/formats/opencl/template/kernel.cl +1 -1
- myokit/formats/opencl/template/minilog.py +1 -1
- myokit/formats/python/__init__.py +0 -3
- myokit/formats/python/_ewriter.py +2 -5
- myokit/formats/python/_exporter.py +0 -3
- myokit/formats/python/template/sim.py +14 -14
- myokit/formats/sbml/__init__.py +0 -3
- myokit/formats/sbml/_api.py +50 -44
- myokit/formats/sbml/_importer.py +1 -4
- myokit/formats/sbml/_parser.py +2 -5
- myokit/formats/stan/__init__.py +0 -3
- myokit/formats/stan/_ewriter.py +2 -4
- myokit/formats/stan/_exporter.py +2 -5
- myokit/formats/stan/template/cell.stan +3 -3
- myokit/formats/sympy/__init__.py +0 -3
- myokit/formats/sympy/_ereader.py +1 -4
- myokit/formats/sympy/_ewriter.py +2 -5
- myokit/formats/wcp/__init__.py +0 -3
- myokit/formats/wcp/_wcp.py +2 -8
- myokit/formats/xml/__init__.py +0 -3
- myokit/formats/xml/_exporter.py +0 -3
- myokit/formats/xml/_split.py +0 -3
- myokit/gui/__init__.py +80 -246
- myokit/gui/datablock_viewer.py +103 -86
- myokit/gui/datalog_viewer.py +214 -66
- myokit/gui/explorer.py +15 -21
- myokit/gui/ide.py +171 -144
- myokit/gui/progress.py +9 -9
- myokit/gui/source.py +406 -375
- myokit/gui/vargrapher.py +2 -12
- myokit/lib/deps.py +12 -13
- myokit/lib/guess.py +3 -4
- myokit/lib/hh.py +20 -18
- myokit/lib/markov.py +21 -20
- myokit/lib/multi.py +1 -3
- myokit/lib/plots.py +20 -9
- myokit/pacing.py +0 -3
- myokit/pype.py +7 -18
- myokit/tests/__init__.py +3 -6
- myokit/tests/ansic_event_based_pacing.py +1 -4
- myokit/tests/ansic_fixed_form_pacing.py +3 -6
- myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
- myokit/tests/data/clancy-1999-fitting.mmt +1 -0
- myokit/tests/test_aux.py +13 -28
- myokit/tests/test_cellml_v1_api.py +4 -19
- myokit/tests/test_cellml_v1_parser.py +0 -15
- myokit/tests/test_cellml_v1_writer.py +0 -9
- myokit/tests/test_cellml_v2_api.py +4 -19
- myokit/tests/test_cellml_v2_parser.py +0 -15
- myokit/tests/test_cellml_v2_writer.py +0 -9
- myokit/tests/test_cmodel.py +16 -22
- myokit/tests/test_compiler_detection.py +1 -11
- myokit/tests/test_component.py +108 -56
- myokit/tests/test_config.py +34 -67
- myokit/tests/test_datablock.py +1 -9
- myokit/tests/test_datalog.py +19 -24
- myokit/tests/test_dependency_checking.py +8 -23
- myokit/tests/test_expressions.py +0 -9
- myokit/tests/test_float.py +1 -5
- myokit/tests/test_formats.py +0 -9
- myokit/tests/test_formats_axon.py +1 -9
- myokit/tests/test_formats_cellml.py +0 -15
- myokit/tests/test_formats_channelml.py +0 -15
- myokit/tests/test_formats_easyml.py +0 -14
- myokit/tests/test_formats_exporters.py +1 -16
- myokit/tests/test_formats_expression_writers.py +1 -17
- myokit/tests/test_formats_html.py +0 -3
- myokit/tests/test_formats_importers.py +1 -16
- myokit/tests/test_formats_mathml_content.py +0 -9
- myokit/tests/test_formats_mathml_presentation.py +0 -9
- myokit/tests/test_formats_opencl.py +0 -10
- myokit/tests/test_formats_sbml.py +0 -15
- myokit/tests/test_formats_sympy.py +0 -9
- myokit/tests/test_formats_wcp.py +1 -3
- myokit/tests/test_io.py +27 -27
- myokit/tests/test_jacobian_calculator.py +6 -14
- myokit/tests/test_jacobian_tracer.py +0 -9
- myokit/tests/test_lib_deps.py +0 -9
- myokit/tests/test_lib_guess.py +0 -9
- myokit/tests/test_lib_hh.py +18 -12
- myokit/tests/test_lib_markov.py +21 -13
- myokit/tests/test_lib_multi.py +0 -9
- myokit/tests/test_lib_plots.py +13 -8
- myokit/tests/test_meta.py +0 -3
- myokit/tests/test_model.py +390 -96
- myokit/tests/test_model_building.py +44 -96
- myokit/tests/test_opencl_info.py +5 -14
- myokit/tests/test_pacing_factory.py +0 -3
- myokit/tests/test_pacing_system_c.py +1 -23
- myokit/tests/test_pacing_system_py.py +0 -9
- myokit/tests/test_parsing.py +139 -56
- myokit/tests/test_progress_reporters.py +0 -3
- myokit/tests/test_protocol.py +0 -9
- myokit/tests/test_protocol_floating_point.py +1 -10
- myokit/tests/test_protocol_time_series.py +82 -0
- myokit/tests/test_pype.py +0 -9
- myokit/tests/test_quantity.py +0 -9
- myokit/tests/test_rhs_benchmarker.py +1 -9
- myokit/tests/test_sbml_api.py +27 -42
- myokit/tests/test_sbml_parser.py +4 -19
- myokit/tests/test_simulation_1d.py +45 -25
- myokit/tests/test_simulation_cvodes.py +321 -55
- myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
- myokit/tests/test_simulation_fiber_tissue.py +39 -12
- myokit/tests/test_simulation_log_interval.py +1 -431
- myokit/tests/test_simulation_opencl.py +69 -48
- myokit/tests/test_simulation_opencl_log_interval.py +1 -3
- myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
- myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
- myokit/tests/test_system_info.py +1 -11
- myokit/tests/test_tools.py +0 -9
- myokit/tests/test_unit.py +1 -10
- myokit/tests/test_user_functions.py +0 -10
- myokit/tests/test_variable.py +231 -27
- myokit/tools.py +5 -21
- myokit/units.py +5 -3
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
- myokit-1.35.0.dist-info/RECORD +391 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
- myokit/_exec_new.py +0 -15
- myokit/_exec_old.py +0 -15
- myokit/_sim/cvodesim.c +0 -1551
- myokit/_sim/cvodesim.py +0 -674
- myokit/_sim/icsim.cpp +0 -563
- myokit/_sim/icsim.py +0 -363
- myokit/_sim/psim.cpp +0 -656
- myokit/_sim/psim.py +0 -493
- myokit/lib/common.py +0 -1094
- myokit/tests/test_lib_common.py +0 -130
- myokit/tests/test_simulation_cvode.py +0 -612
- myokit/tests/test_simulation_ic.py +0 -108
- myokit/tests/test_simulation_p.py +0 -223
- myokit-1.33.9.dist-info/RECORD +0 -403
- /myokit/formats/opencl/template/{test → test.sh} +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
- {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
myokit/gui/source.py
CHANGED
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
# This file is part of Myokit.
|
|
7
7
|
# See http://myokit.org for copyright, sharing, and licensing details.
|
|
8
8
|
#
|
|
9
|
-
from __future__ import absolute_import, division
|
|
10
|
-
from __future__ import print_function, unicode_literals
|
|
11
|
-
|
|
12
9
|
import myokit
|
|
10
|
+
|
|
13
11
|
from myokit.gui import Qt, QtCore, QtGui, QtWidgets
|
|
14
12
|
|
|
13
|
+
|
|
15
14
|
# GUI components
|
|
16
15
|
# Constants
|
|
17
16
|
SPACE = ' '
|
|
@@ -54,7 +53,7 @@ COLOR_SELECTED_LINE = QtGui.QColor(238, 238, 238)
|
|
|
54
53
|
|
|
55
54
|
def _check_for_dark_mode(palette):
|
|
56
55
|
"""
|
|
57
|
-
Checks the default editor background color, and adjusts the
|
|
56
|
+
Checks the default editor background color, and adjusts the color scheme
|
|
58
57
|
if it looks like dark-mode is enabled.
|
|
59
58
|
"""
|
|
60
59
|
c = palette.base().color()
|
|
@@ -68,7 +67,7 @@ def _check_for_dark_mode(palette):
|
|
|
68
67
|
STYLE_ANNOT_KEY.setForeground(QtGui.QColor(0, 31, 231))
|
|
69
68
|
STYLE_ANNOT_VAL.setForeground(QtGui.QColor(57, 115, 214))
|
|
70
69
|
STYLE_KEYWORD_1.setForeground(QtGui.QColor(0, 128, 0))
|
|
71
|
-
STYLE_KEYWORD_1.setFontWeight(QtGui.QFont.Bold)
|
|
70
|
+
STYLE_KEYWORD_1.setFontWeight(QtGui.QFont.Weight.Bold)
|
|
72
71
|
STYLE_KEYWORD_2.setForeground(QtGui.QColor(0, 128, 128))
|
|
73
72
|
STYLE_LITERAL.setForeground(QtGui.QColor(255, 20, 215))
|
|
74
73
|
STYLE_INLINE_UNIT.setForeground(QtGui.QColor(128, 0, 128))
|
|
@@ -78,7 +77,7 @@ def _check_for_dark_mode(palette):
|
|
|
78
77
|
STYLE_ANNOT_KEY.setForeground(QtGui.QColor(179, 179, 179))
|
|
79
78
|
STYLE_ANNOT_VAL.setForeground(QtGui.QColor(171, 177, 205))
|
|
80
79
|
STYLE_KEYWORD_1.setForeground(QtGui.QColor(10, 195, 87))
|
|
81
|
-
STYLE_KEYWORD_1.setFontWeight(QtGui.QFont.Bold)
|
|
80
|
+
STYLE_KEYWORD_1.setFontWeight(QtGui.QFont.Weight.Bold)
|
|
82
81
|
STYLE_KEYWORD_2.setForeground(QtGui.QColor(10, 195, 87))
|
|
83
82
|
STYLE_LITERAL.setForeground(QtGui.QColor(255, 223, 12))
|
|
84
83
|
STYLE_INLINE_UNIT.setForeground(QtGui.QColor(168, 152, 33))
|
|
@@ -97,7 +96,7 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
97
96
|
status bar.
|
|
98
97
|
"""
|
|
99
98
|
def __init__(self, parent=None):
|
|
100
|
-
super(
|
|
99
|
+
super().__init__(parent)
|
|
101
100
|
|
|
102
101
|
# Current style
|
|
103
102
|
self._palette = QtGui.QGuiApplication.palette()
|
|
@@ -115,7 +114,12 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
115
114
|
self.cursor_changed()
|
|
116
115
|
|
|
117
116
|
# Line position
|
|
118
|
-
|
|
117
|
+
try:
|
|
118
|
+
# https://doc.qt.io/qt-5/qfontmetrics.html#horizontalAdvance
|
|
119
|
+
# Qt 5.5.11 and onwards
|
|
120
|
+
self._line_offset = self.fontMetrics().horizontalAdvance(' ' * 79)
|
|
121
|
+
except AttributeError:
|
|
122
|
+
self._line_offset = self.fontMetrics().width(' ' * 79)
|
|
119
123
|
|
|
120
124
|
# Number of blocks in page up/down
|
|
121
125
|
self._blocks_per_page = 1
|
|
@@ -131,7 +135,7 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
131
135
|
selection = QtWidgets.QTextEdit.ExtraSelection()
|
|
132
136
|
selection.format.setBackground(COLOR_SELECTED_LINE)
|
|
133
137
|
selection.format.setProperty(
|
|
134
|
-
QtGui.QTextFormat.FullWidthSelection, True)
|
|
138
|
+
QtGui.QTextFormat.Property.FullWidthSelection, True)
|
|
135
139
|
selection.cursor = self.textCursor()
|
|
136
140
|
selection.cursor.clearSelection()
|
|
137
141
|
extra_selections.append(selection)
|
|
@@ -143,13 +147,14 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
143
147
|
pos = cursor.position()
|
|
144
148
|
bracket = None
|
|
145
149
|
if not cursor.atEnd():
|
|
146
|
-
cursor.setPosition(
|
|
150
|
+
cursor.setPosition(
|
|
151
|
+
pos + 1, QtGui.QTextCursor.MoveMode.KeepAnchor)
|
|
147
152
|
text = cursor.selectedText()
|
|
148
153
|
if text in BRACKETS:
|
|
149
154
|
bracket = cursor
|
|
150
155
|
elif bracket is None and not cursor.atStart():
|
|
151
156
|
cursor.setPosition(pos - 1)
|
|
152
|
-
cursor.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
|
|
157
|
+
cursor.setPosition(pos, QtGui.QTextCursor.MoveMode.KeepAnchor)
|
|
153
158
|
text = cursor.selectedText()
|
|
154
159
|
if text in BRACKETS:
|
|
155
160
|
bracket = cursor
|
|
@@ -163,10 +168,10 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
163
168
|
if text in BRACKETS_CLOSE:
|
|
164
169
|
other = doc.find(
|
|
165
170
|
text, start - 1,
|
|
166
|
-
QtGui.QTextDocument.FindBackward)
|
|
171
|
+
QtGui.QTextDocument.FindFlag.FindBackward)
|
|
167
172
|
match = doc.find(
|
|
168
173
|
BRACKETS[text], start - 1,
|
|
169
|
-
QtGui.QTextDocument.FindBackward)
|
|
174
|
+
QtGui.QTextDocument.FindFlag.FindBackward)
|
|
170
175
|
else:
|
|
171
176
|
other = doc.find(text, start)
|
|
172
177
|
match = doc.find(BRACKETS[text], start)
|
|
@@ -222,11 +227,20 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
222
227
|
# Set font
|
|
223
228
|
self.setFont(FONT)
|
|
224
229
|
# Set frame
|
|
225
|
-
self.setFrameStyle(
|
|
230
|
+
self.setFrameStyle(
|
|
231
|
+
QtWidgets.QFrame.Shape.WinPanel | QtWidgets.QFrame.Shadow.Sunken)
|
|
226
232
|
# Disable wrapping
|
|
227
|
-
self.setLineWrapMode(
|
|
233
|
+
self.setLineWrapMode(QtWidgets.QPlainTextEdit.LineWrapMode.NoWrap)
|
|
228
234
|
# Set tab width (if ever seen) to 4 spaces
|
|
229
|
-
|
|
235
|
+
try:
|
|
236
|
+
# https://doc.qt.io/qt-5/qtextedit-obsolete.html
|
|
237
|
+
# https://doc.qt.io/qt-5/qfontmetrics.html#horizontalAdvance
|
|
238
|
+
# Qt 5.10/5.11 and onwards
|
|
239
|
+
ts = self.fontMetrics().horizontalAdvance(' ' * 4)
|
|
240
|
+
self.setTabStopDistance(ts)
|
|
241
|
+
except AttributeError:
|
|
242
|
+
ts = self.fontMetrics().width(' ' * 4)
|
|
243
|
+
self.setTabStopWidth(ts)
|
|
230
244
|
|
|
231
245
|
def get_text(self):
|
|
232
246
|
""" Returns the text in this editor. """
|
|
@@ -242,6 +256,11 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
242
256
|
|
|
243
257
|
def keyPressEvent(self, event):
|
|
244
258
|
""" Qt event: A key was pressed. """
|
|
259
|
+
K = Qt.Key
|
|
260
|
+
KM = Qt.KeyboardModifier
|
|
261
|
+
MM = QtGui.QTextCursor.MoveMode
|
|
262
|
+
MO = QtGui.QTextCursor.MoveOperation
|
|
263
|
+
|
|
245
264
|
# Get key and modifiers
|
|
246
265
|
key = event.key()
|
|
247
266
|
mod = event.modifiers()
|
|
@@ -251,11 +270,13 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
251
270
|
# MetaModifier (i.e. super key)
|
|
252
271
|
# KeyPadModifier (button is part of keypad)
|
|
253
272
|
# GroupSwitchModifier (x11 thing)
|
|
273
|
+
|
|
254
274
|
# Ignore the keypad modifier, we don't care!
|
|
255
|
-
if mod &
|
|
256
|
-
mod = mod ^
|
|
275
|
+
if mod & KM.KeypadModifier:
|
|
276
|
+
mod = mod ^ KM.KeypadModifier # xor!
|
|
277
|
+
|
|
257
278
|
# Actions per key/modifier combination
|
|
258
|
-
if key ==
|
|
279
|
+
if key == K.Key_Tab and mod == KM.NoModifier:
|
|
259
280
|
# Indent
|
|
260
281
|
cursor = self.textCursor()
|
|
261
282
|
start, end = cursor.selectionStart(), cursor.selectionEnd()
|
|
@@ -275,7 +296,7 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
275
296
|
pos = cursor.positionInBlock()
|
|
276
297
|
cursor.insertText((TABS - pos % TABS) * SPACE)
|
|
277
298
|
|
|
278
|
-
elif key ==
|
|
299
|
+
elif key == K.Key_Backtab and mod == KM.ShiftModifier:
|
|
279
300
|
# Dedent all lines in selection (or single line if no selection)
|
|
280
301
|
'''
|
|
281
302
|
cursor = self.textCursor()
|
|
@@ -295,11 +316,11 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
295
316
|
p2 = p1 + min(4, len(t) - len(t.lstrip()))
|
|
296
317
|
c = self.textCursor()
|
|
297
318
|
c.setPosition(p1)
|
|
298
|
-
c.setPosition(p2,
|
|
319
|
+
c.setPosition(p2, MM.KeepAnchor)
|
|
299
320
|
c.removeSelectedText()
|
|
300
321
|
cursor.endEditBlock()
|
|
301
322
|
'''
|
|
302
|
-
# This silly method is required because of a bug in
|
|
323
|
+
# This silly method is required because of a bug in qt5 (and 6?)
|
|
303
324
|
cursor = self.textCursor()
|
|
304
325
|
start, end = cursor.selectionStart(), cursor.selectionEnd()
|
|
305
326
|
first = self.document().findBlock(start)
|
|
@@ -324,22 +345,21 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
324
345
|
cursor.beginEditBlock()
|
|
325
346
|
cursor.setPosition(first.position())
|
|
326
347
|
cursor.setPosition(
|
|
327
|
-
last.position() + last.length() - 1,
|
|
328
|
-
QtGui.QTextCursor.KeepAnchor)
|
|
348
|
+
last.position() + last.length() - 1, MM.KeepAnchor)
|
|
329
349
|
cursor.removeSelectedText()
|
|
330
350
|
cursor.insertText('\n'.join(new_text))
|
|
331
351
|
cursor.endEditBlock()
|
|
332
352
|
# Set new cursor
|
|
333
353
|
cursor.setPosition(new_start)
|
|
334
|
-
cursor.setPosition(new_end,
|
|
354
|
+
cursor.setPosition(new_end, MM.KeepAnchor)
|
|
335
355
|
self.setTextCursor(cursor)
|
|
336
356
|
|
|
337
|
-
elif key ==
|
|
357
|
+
elif key == K.Key_Enter or key == K.Key_Return:
|
|
338
358
|
# Enter/Return with modifier is overruled here to mean nothing
|
|
339
359
|
# This is very important as the default for shift-enter is to
|
|
340
360
|
# start a new line within the same block (this can't happen with
|
|
341
361
|
# copy-pasting, so it's safe to just catch it here).
|
|
342
|
-
if mod ==
|
|
362
|
+
if mod == KM.NoModifier:
|
|
343
363
|
# "Smart" enter:
|
|
344
364
|
# - If selection, selection is deleted
|
|
345
365
|
# - Else, autoindenting is performed
|
|
@@ -361,8 +381,8 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
361
381
|
# Scroll if necessary
|
|
362
382
|
self.ensureCursorVisible()
|
|
363
383
|
|
|
364
|
-
elif key ==
|
|
365
|
-
mod ==
|
|
384
|
+
elif key == K.Key_Home and (
|
|
385
|
+
mod == KM.NoModifier or mod == KM.ShiftModifier):
|
|
366
386
|
# Plain home button: move to start of line
|
|
367
387
|
# If Control is used: Jump to start of document
|
|
368
388
|
# Ordinary home button: Jump to first column or first
|
|
@@ -385,25 +405,22 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
385
405
|
# Smart up/down:
|
|
386
406
|
self._last_column = indent
|
|
387
407
|
# If Shift is used: only move position (keep anchor, i.e. select)
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
else
|
|
391
|
-
cursor.setPosition(newpos, anchor)
|
|
408
|
+
cursor.setPosition(
|
|
409
|
+
newpos,
|
|
410
|
+
MM.KeepAnchor if mod == KM.ShiftModifier else MM.MoveAnchor)
|
|
392
411
|
self.setTextCursor(cursor)
|
|
393
412
|
|
|
394
|
-
elif key ==
|
|
395
|
-
mod ==
|
|
396
|
-
or mod ==
|
|
413
|
+
elif key == K.Key_Home and (
|
|
414
|
+
mod == KM.ControlModifier
|
|
415
|
+
or mod == KM.ControlModifier & KM.ShiftModifier):
|
|
397
416
|
# Move to start of document
|
|
398
417
|
# If Shift is used: only move position (keep anchor, i.e. select)
|
|
399
|
-
anchor = (
|
|
400
|
-
QtGui.QTextCursor.KeepAnchor if mod == Qt.ShiftModifier
|
|
401
|
-
else QtGui.QTextCursor.MoveAnchor)
|
|
402
418
|
cursor = self.textCursor()
|
|
403
|
-
cursor.setPosition(
|
|
419
|
+
cursor.setPosition(
|
|
420
|
+
0, MM.KeepAnchor if mod == KM.ShiftModifier else MM.MoveAnchor)
|
|
404
421
|
self.setTextCursor(cursor)
|
|
405
422
|
|
|
406
|
-
elif key in (
|
|
423
|
+
elif key in (K.Key_Up, K.Key_Down) and mod == KM.AltModifier:
|
|
407
424
|
# Move selected lines up or down
|
|
408
425
|
# Get current selection
|
|
409
426
|
doc = self.document()
|
|
@@ -420,7 +437,7 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
420
437
|
block2 = block2.previous() # always valid
|
|
421
438
|
block2 = block1 if start == end else doc.findBlock(end)
|
|
422
439
|
# Check if we can move
|
|
423
|
-
if key ==
|
|
440
|
+
if key == K.Key_Up:
|
|
424
441
|
if not block1.previous().isValid():
|
|
425
442
|
return
|
|
426
443
|
elif not block2.next().isValid():
|
|
@@ -429,30 +446,28 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
429
446
|
b1pos = block1.position()
|
|
430
447
|
cursor.beginEditBlock()
|
|
431
448
|
cursor.setPosition(b1pos)
|
|
432
|
-
cursor.setPosition(end,
|
|
433
|
-
cursor.movePosition(
|
|
434
|
-
QtGui.QTextCursor.EndOfLine, QtGui.QTextCursor.KeepAnchor)
|
|
449
|
+
cursor.setPosition(end, MM.KeepAnchor)
|
|
450
|
+
cursor.movePosition(MO.EndOfLine, MM.KeepAnchor)
|
|
435
451
|
line = cursor.selectedText()
|
|
436
452
|
size = cursor.selectionEnd() - cursor.selectionStart()
|
|
437
453
|
cursor.removeSelectedText()
|
|
438
|
-
if key ==
|
|
454
|
+
if key == K.Key_Up:
|
|
439
455
|
cursor.deletePreviousChar()
|
|
440
|
-
cursor.movePosition(
|
|
456
|
+
cursor.movePosition(MO.StartOfLine)
|
|
441
457
|
cursor.insertText(line + '\n')
|
|
442
|
-
cursor.movePosition(
|
|
458
|
+
cursor.movePosition(MO.Left)
|
|
443
459
|
else:
|
|
444
460
|
cursor.deleteChar()
|
|
445
|
-
cursor.movePosition(
|
|
461
|
+
cursor.movePosition(MO.EndOfLine)
|
|
446
462
|
cursor.insertText('\n' + line)
|
|
447
463
|
cursor.endEditBlock()
|
|
448
464
|
# Cursor is at the end of the moved lines.
|
|
449
465
|
# Set moved lines as selection
|
|
450
|
-
cursor.movePosition(
|
|
451
|
-
QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor, size)
|
|
466
|
+
cursor.movePosition(MO.Left, MM.KeepAnchor, size)
|
|
452
467
|
self.setTextCursor(cursor)
|
|
453
468
|
|
|
454
|
-
elif key in (
|
|
455
|
-
and (mod ==
|
|
469
|
+
elif key in (K.Key_Up, K.Key_Down, K.Key_PageUp, K.Key_PageDown) \
|
|
470
|
+
and (mod == KM.NoModifier or mod == KM.ShiftModifier):
|
|
456
471
|
# Move cursor up/down
|
|
457
472
|
# Maintain the column position, even when the current row doesn't
|
|
458
473
|
# have as many characters. Reset this behavior as soon as a
|
|
@@ -460,13 +475,12 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
460
475
|
# changed.
|
|
461
476
|
# Set up operation
|
|
462
477
|
anchor = (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
Qt.Key_Up, Qt.Key_PageUp) else QtGui.QTextCursor.NextBlock
|
|
468
|
-
n = 1 if key in (Qt.Key_Up, Qt.Key_Down) else (
|
|
478
|
+
MM.KeepAnchor if mod == KM.ShiftModifier else MM.MoveAnchor)
|
|
479
|
+
operation = (MO.PreviousBlock if key in (K.Key_Up, K.Key_PageUp)
|
|
480
|
+
else MO.NextBlock)
|
|
481
|
+
n = 1 if key in (K.Key_Up, K.Key_Down) else (
|
|
469
482
|
self._blocks_per_page - 3)
|
|
483
|
+
|
|
470
484
|
# Move
|
|
471
485
|
cursor = self.textCursor()
|
|
472
486
|
if self._last_column is None:
|
|
@@ -478,22 +492,22 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
478
492
|
else:
|
|
479
493
|
# Up/Down beyond document start/end? Move cursor to document
|
|
480
494
|
# start/end and update last column
|
|
481
|
-
if operation ==
|
|
482
|
-
cursor.movePosition(
|
|
495
|
+
if operation == MO.NextBlock:
|
|
496
|
+
cursor.movePosition(MO.EndOfBlock, anchor)
|
|
483
497
|
else:
|
|
484
|
-
cursor.movePosition(
|
|
498
|
+
cursor.movePosition(MO.StartOfBlock, anchor)
|
|
485
499
|
self._last_column = cursor.positionInBlock()
|
|
486
500
|
self.setTextCursor(cursor)
|
|
487
501
|
|
|
488
|
-
elif key in (
|
|
489
|
-
mod &
|
|
502
|
+
elif key in (K.Key_Left, K.Key_Right, K.Key_End) and not (
|
|
503
|
+
mod & KM.AltModifier):
|
|
490
504
|
# Allow all modifiers except alt
|
|
491
505
|
# Reset smart up/down behavior
|
|
492
506
|
self._last_column = None
|
|
493
507
|
# Pass to parent class
|
|
494
|
-
super(
|
|
508
|
+
super().keyPressEvent(event)
|
|
495
509
|
|
|
496
|
-
elif key ==
|
|
510
|
+
elif key == K.Key_Insert and mod == KM.NoModifier:
|
|
497
511
|
# Insert/replace
|
|
498
512
|
self.setOverwriteMode(not self.overwriteMode())
|
|
499
513
|
|
|
@@ -530,20 +544,26 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
530
544
|
# Shift-Enter Starts new line within the same block!
|
|
531
545
|
# Definitely removed
|
|
532
546
|
# Ctrl-i Undocumented, but inserts tab...
|
|
533
|
-
ctrl_ignore = (
|
|
534
|
-
if mod ==
|
|
547
|
+
ctrl_ignore = (K.Key_K, K.Key_I)
|
|
548
|
+
if mod == KM.ControlModifier and key in ctrl_ignore:
|
|
535
549
|
# Control-K: ignore
|
|
536
550
|
pass
|
|
537
|
-
elif key ==
|
|
551
|
+
elif key == K.Key_Up or key == K.Key_Down:
|
|
538
552
|
# Up/down with modifiers: ignore
|
|
539
553
|
pass
|
|
540
554
|
else:
|
|
541
555
|
# Let parent class handle it
|
|
542
|
-
super(
|
|
556
|
+
super().keyPressEvent(event)
|
|
543
557
|
|
|
544
558
|
def _line_number_area_width(self):
|
|
545
559
|
""" Returns the required width for the number area. """
|
|
546
|
-
|
|
560
|
+
text = str(max(1, self.blockCount()))
|
|
561
|
+
try:
|
|
562
|
+
# https://doc.qt.io/qt-5/qfontmetrics.html#horizontalAdvance
|
|
563
|
+
# Qt 5.5.11 and onwards
|
|
564
|
+
return 8 + self.fontMetrics().horizontalAdvance(text)
|
|
565
|
+
except AttributeError:
|
|
566
|
+
return 8 + self.fontMetrics().width(text)
|
|
547
567
|
|
|
548
568
|
def _line_number_area_paint(self, area, event):
|
|
549
569
|
""" Repaints the line number area. """
|
|
@@ -573,8 +593,8 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
573
593
|
while block.isValid() and btop <= ebot:
|
|
574
594
|
count += 1
|
|
575
595
|
if block.isVisible() and bbot >= etop:
|
|
576
|
-
painter.drawText(
|
|
577
|
-
|
|
596
|
+
painter.drawText(0, btop, width - 4, height,
|
|
597
|
+
Qt.AlignmentFlag.AlignRight, str(count))
|
|
578
598
|
block = block.next()
|
|
579
599
|
btop = bbot
|
|
580
600
|
bbot += int(self.blockBoundingRect(block).height())
|
|
@@ -583,7 +603,7 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
583
603
|
""" Paints this editor. """
|
|
584
604
|
|
|
585
605
|
# Paint the editor
|
|
586
|
-
super(
|
|
606
|
+
super().paintEvent(e)
|
|
587
607
|
|
|
588
608
|
# Paint a line between the editor and the line number area
|
|
589
609
|
x = int(
|
|
@@ -610,7 +630,7 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
610
630
|
|
|
611
631
|
def resizeEvent(self, event):
|
|
612
632
|
""" Qt event: Editor is resized. """
|
|
613
|
-
super(
|
|
633
|
+
super().resizeEvent(event)
|
|
614
634
|
# Update line number area
|
|
615
635
|
rect = self.contentsRect()
|
|
616
636
|
self._line_number_area.setGeometry(
|
|
@@ -677,7 +697,8 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
677
697
|
for block in blocks:
|
|
678
698
|
p = block.position() + indent
|
|
679
699
|
cursor.setPosition(p)
|
|
680
|
-
cursor.setPosition(
|
|
700
|
+
cursor.setPosition(
|
|
701
|
+
p + 1, QtGui.QTextCursor.MoveMode.KeepAnchor)
|
|
681
702
|
cursor.removeSelectedText()
|
|
682
703
|
else:
|
|
683
704
|
|
|
@@ -686,7 +707,8 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
686
707
|
n = len(block.text())
|
|
687
708
|
if len(block.text()) < indent:
|
|
688
709
|
cursor.setPosition(p)
|
|
689
|
-
cursor.setPosition(
|
|
710
|
+
cursor.setPosition(
|
|
711
|
+
p + n, QtGui.QTextCursor.MoveMode.KeepAnchor)
|
|
690
712
|
cursor.removeSelectedText()
|
|
691
713
|
cursor.insertText(' ' * indent + '#')
|
|
692
714
|
else:
|
|
@@ -705,8 +727,8 @@ class Editor(QtWidgets.QPlainTextEdit):
|
|
|
705
727
|
b = len(t.rstrip())
|
|
706
728
|
if a > b:
|
|
707
729
|
cursor.setPosition(block.position() + b)
|
|
708
|
-
cursor.setPosition(
|
|
709
|
-
|
|
730
|
+
cursor.setPosition(block.position() + a,
|
|
731
|
+
QtGui.QTextCursor.MoveMode.KeepAnchor)
|
|
710
732
|
cursor.removeSelectedText()
|
|
711
733
|
block = block.next()
|
|
712
734
|
cursor.endEditBlock()
|
|
@@ -722,7 +744,7 @@ class LineNumberArea(QtWidgets.QWidget):
|
|
|
722
744
|
"""
|
|
723
745
|
|
|
724
746
|
def __init__(self, editor):
|
|
725
|
-
super(
|
|
747
|
+
super().__init__(editor)
|
|
726
748
|
self._editor = editor
|
|
727
749
|
self._editor.blockCountChanged.connect(self.update_width)
|
|
728
750
|
self._editor.updateRequest.connect(self.update_contents)
|
|
@@ -766,7 +788,7 @@ class FindReplaceWidget(QtWidgets.QWidget):
|
|
|
766
788
|
find_action = QtCore.Signal(str)
|
|
767
789
|
|
|
768
790
|
def __init__(self, parent, editor):
|
|
769
|
-
super(
|
|
791
|
+
super().__init__(parent)
|
|
770
792
|
self._editor = editor
|
|
771
793
|
|
|
772
794
|
# Create widgets
|
|
@@ -789,7 +811,8 @@ class FindReplaceWidget(QtWidgets.QWidget):
|
|
|
789
811
|
text_layout.addWidget(self._search_field, 0, 1)
|
|
790
812
|
text_layout.addWidget(self._replace_label, 1, 0)
|
|
791
813
|
text_layout.addWidget(self._replace_field, 1, 1)
|
|
792
|
-
check_layout = QtWidgets.QBoxLayout(
|
|
814
|
+
check_layout = QtWidgets.QBoxLayout(
|
|
815
|
+
QtWidgets.QBoxLayout.Direction.TopToBottom)
|
|
793
816
|
check_layout.addWidget(self._case_check)
|
|
794
817
|
check_layout.addWidget(self._whole_check)
|
|
795
818
|
button_layout = QtWidgets.QGridLayout()
|
|
@@ -797,7 +820,8 @@ class FindReplaceWidget(QtWidgets.QWidget):
|
|
|
797
820
|
button_layout.addWidget(self._replace_button, 0, 2)
|
|
798
821
|
button_layout.addWidget(self._find_button, 0, 3)
|
|
799
822
|
|
|
800
|
-
layout = QtWidgets.QBoxLayout(
|
|
823
|
+
layout = QtWidgets.QBoxLayout(
|
|
824
|
+
QtWidgets.QBoxLayout.Direction.TopToBottom)
|
|
801
825
|
layout.addLayout(text_layout)
|
|
802
826
|
layout.addLayout(check_layout)
|
|
803
827
|
layout.addLayout(button_layout)
|
|
@@ -814,11 +838,11 @@ class FindReplaceWidget(QtWidgets.QWidget):
|
|
|
814
838
|
if query == '':
|
|
815
839
|
self.find_action.emit('No query set')
|
|
816
840
|
return
|
|
817
|
-
flags =
|
|
841
|
+
flags = QtGui.QTextDocument.FindFlag(0)
|
|
818
842
|
if self._case_check.isChecked():
|
|
819
|
-
flags |= QtGui.QTextDocument.FindCaseSensitively
|
|
843
|
+
flags |= QtGui.QTextDocument.FindFlag.FindCaseSensitively
|
|
820
844
|
if self._whole_check.isChecked():
|
|
821
|
-
flags |= QtGui.QTextDocument.FindWholeWords
|
|
845
|
+
flags |= QtGui.QTextDocument.FindFlag.FindWholeWords
|
|
822
846
|
if flags:
|
|
823
847
|
found = self._editor.find(query, flags)
|
|
824
848
|
else:
|
|
@@ -867,11 +891,11 @@ class FindReplaceWidget(QtWidgets.QWidget):
|
|
|
867
891
|
if query == '':
|
|
868
892
|
self.find_action.emit('No query set')
|
|
869
893
|
return
|
|
870
|
-
flags =
|
|
894
|
+
flags = QtGui.QTextDocument.FindFlag(0)
|
|
871
895
|
if self._case_check.isChecked():
|
|
872
|
-
flags |= QtGui.QTextDocument.FindCaseSensitively
|
|
896
|
+
flags |= QtGui.QTextDocument.FindFlag.FindCaseSensitively
|
|
873
897
|
if self._whole_check.isChecked():
|
|
874
|
-
flags |= QtGui.QTextDocument.FindWholeWords
|
|
898
|
+
flags |= QtGui.QTextDocument.FindFlag.FindWholeWords
|
|
875
899
|
n = 0
|
|
876
900
|
found = True
|
|
877
901
|
scrollpos = self._editor.verticalScrollBar().value()
|
|
@@ -917,10 +941,10 @@ class FindReplaceWidget(QtWidgets.QWidget):
|
|
|
917
941
|
def keyPressEvent(self, event):
|
|
918
942
|
""" Qt event: A key-press reaches the widget. """
|
|
919
943
|
key = event.key()
|
|
920
|
-
if key == Qt.Key_Enter or key == Qt.Key_Return:
|
|
944
|
+
if key == Qt.Key.Key_Enter or key == Qt.Key.Key_Return:
|
|
921
945
|
self.action_find()
|
|
922
946
|
else:
|
|
923
|
-
super(
|
|
947
|
+
super().keyPressEvent(event)
|
|
924
948
|
|
|
925
949
|
def load_config(self, config, section):
|
|
926
950
|
"""
|
|
@@ -956,144 +980,153 @@ class ModelHighlighter(QtGui.QSyntaxHighlighter):
|
|
|
956
980
|
ANNOT_KEYS = ['in', 'bind', 'label']
|
|
957
981
|
|
|
958
982
|
def __init__(self, document):
|
|
959
|
-
super(
|
|
983
|
+
super().__init__(document)
|
|
960
984
|
|
|
961
985
|
# Expressions used to find strings & comments
|
|
962
|
-
|
|
963
|
-
self.
|
|
964
|
-
self._comment_start = QtCore.QRegExp(r'#[^\n]*')
|
|
986
|
+
R = QtCore.QRegularExpression
|
|
987
|
+
self._string = R(r'"""')
|
|
965
988
|
|
|
966
989
|
# Headers
|
|
967
990
|
name = r'[a-zA-Z]+[a-zA-Z0-9_]*'
|
|
968
|
-
self._rule_head =
|
|
991
|
+
self._rule_head = R(r'^\s*(\[{1,2}' + name + '\]{1,2})')
|
|
969
992
|
|
|
970
993
|
# Simple rules
|
|
971
994
|
self._rules = []
|
|
972
995
|
|
|
973
996
|
# Numbers
|
|
974
|
-
pattern =
|
|
997
|
+
pattern = R(r'\b[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?\b')
|
|
975
998
|
self._rules.append((pattern, STYLE_LITERAL))
|
|
976
|
-
unit = r'\[[a-zA-Z0-9
|
|
977
|
-
self._rules.append((
|
|
999
|
+
unit = r'\[([a-zA-Z0-9/^-]|\*)+\]'
|
|
1000
|
+
self._rules.append((R(unit), STYLE_INLINE_UNIT))
|
|
978
1001
|
|
|
979
1002
|
# Keywords
|
|
980
1003
|
for keyword in self.KEYWORD_1:
|
|
981
|
-
|
|
982
|
-
self._rules.append((pattern, STYLE_KEYWORD_1))
|
|
1004
|
+
self._rules.append((R(r'\b' + keyword + r'\b'), STYLE_KEYWORD_1))
|
|
983
1005
|
for keyword in self.KEYWORD_2:
|
|
984
|
-
|
|
985
|
-
self._rules.append((pattern, STYLE_KEYWORD_2))
|
|
1006
|
+
self._rules.append((R(r'\b' + keyword + r'\b'), STYLE_KEYWORD_2))
|
|
986
1007
|
|
|
987
1008
|
# Meta-data coloring
|
|
988
1009
|
self._rules_labels = [
|
|
989
|
-
|
|
990
|
-
|
|
1010
|
+
R(r'(\s*)(bind)\s+(' + name + ')'),
|
|
1011
|
+
R(r'(\s*)(label)\s+(' + name + ')'),
|
|
991
1012
|
]
|
|
992
|
-
self.
|
|
993
|
-
self.
|
|
994
|
-
self._rule_var_unit = QtCore.QRegExp(r'^(\s*)(in)(\s*)(' + unit + ')')
|
|
1013
|
+
self._rule_meta = R(r'^\s*(' + name + r':)(\s*)(.+)')
|
|
1014
|
+
self._rule_var_unit = R(r'^(\s*)(in)(\s*)(' + unit + ')')
|
|
995
1015
|
|
|
996
|
-
#
|
|
997
|
-
|
|
998
|
-
|
|
1016
|
+
# Comment
|
|
1017
|
+
self._comment = R(r'#')
|
|
1018
|
+
|
|
1019
|
+
def _highlight_ok(self, strings, start, length):
|
|
1020
|
+
""" Checks if the string ``start`` to ``length`` needs formatted. """
|
|
1021
|
+
for lo, hi in strings:
|
|
1022
|
+
if lo <= start < hi or lo <= start + length < hi:
|
|
1023
|
+
return False
|
|
1024
|
+
return True
|
|
999
1025
|
|
|
1000
1026
|
def highlightBlock(self, text):
|
|
1001
1027
|
""" Qt: Called whenever a block should be highlighted. """
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
# Model and component headers
|
|
1013
|
-
i = self._rule_head.indexIn(text)
|
|
1014
|
-
while i >= 0:
|
|
1015
|
-
m = len(self._rule_head.cap(1))
|
|
1016
|
-
n = len(self._rule_head.cap(0))
|
|
1017
|
-
self.setFormat(i + m, n - m, STYLE_HEADER)
|
|
1018
|
-
i = self._rule_head.indexIn(text, i + n)
|
|
1019
|
-
|
|
1020
|
-
# Annotations
|
|
1021
|
-
# Labels
|
|
1022
|
-
for pattern in self._rules_labels:
|
|
1023
|
-
i = pattern.indexIn(text)
|
|
1024
|
-
while i >= 0:
|
|
1025
|
-
n0 = len(pattern.cap(0))
|
|
1026
|
-
n1 = len(pattern.cap(1))
|
|
1027
|
-
n2 = len(pattern.cap(2))
|
|
1028
|
-
n3 = len(pattern.cap(3))
|
|
1029
|
-
self.setFormat(i + n1, n2, STYLE_ANNOT_KEY)
|
|
1030
|
-
self.setFormat(i + n0 - n3, n3, STYLE_ANNOT_VAL)
|
|
1031
|
-
i = pattern.indexIn(text, i + n0)
|
|
1032
|
-
|
|
1033
|
-
# Units
|
|
1034
|
-
i = self._rule_var_unit.indexIn(text)
|
|
1035
|
-
if i == 0:
|
|
1036
|
-
n1 = len(self._rule_var_unit.cap(1))
|
|
1037
|
-
n2 = len(self._rule_var_unit.cap(2))
|
|
1038
|
-
n3 = len(self._rule_var_unit.cap(3))
|
|
1039
|
-
n4 = len(self._rule_var_unit.cap(4))
|
|
1040
|
-
self.setFormat(n1, n2, STYLE_ANNOT_KEY)
|
|
1041
|
-
self.setFormat(n1 + n2 + n3, n4, STYLE_ANNOT_VAL)
|
|
1042
|
-
|
|
1043
|
-
# Meta properties
|
|
1044
|
-
i = self._rule_meta_key.indexIn(text)
|
|
1045
|
-
if i >= 0:
|
|
1046
|
-
n0 = len(self._rule_meta_key.cap(0))
|
|
1047
|
-
self.setFormat(i, n0, STYLE_ANNOT_KEY)
|
|
1048
|
-
i = self._rule_meta_val.indexIn(text)
|
|
1049
|
-
if i >= 0:
|
|
1050
|
-
n1 = len(self._rule_meta_val.cap(1))
|
|
1051
|
-
n2 = len(self._rule_meta_val.cap(2))
|
|
1052
|
-
self.setFormat(i, 1, STYLE_ANNOT_KEY)
|
|
1053
|
-
self.setFormat(1 + i + n1, n2, STYLE_ANNOT_VAL)
|
|
1054
|
-
|
|
1055
|
-
# Comments (overrule all other formatting except multi-line strings)
|
|
1056
|
-
i = self._comments.indexIn(text)
|
|
1057
|
-
while i >= 0:
|
|
1058
|
-
n = len(self._comments.cap(0))
|
|
1059
|
-
self.setFormat(i, n, STYLE_COMMENT)
|
|
1060
|
-
i = self._comments.indexIn(text, i + n)
|
|
1061
|
-
|
|
1062
|
-
# Multi-line strings
|
|
1063
|
-
# Block states:
|
|
1064
|
-
# 0 Normal
|
|
1065
|
-
# 1 Multi-line string (meta)
|
|
1028
|
+
|
|
1029
|
+
# To avoid formatting within strings each is stored as a (start, end).
|
|
1030
|
+
strings = []
|
|
1031
|
+
# If the start has been handled, set the offset.
|
|
1032
|
+
offset = 0
|
|
1033
|
+
# If the end has been handled, chop it off the string
|
|
1034
|
+
|
|
1035
|
+
# Multi-line strings are done first, because they overrule a lot of
|
|
1036
|
+
# things and we can skip formatting if we're inside one.
|
|
1037
|
+
# Block states: 0=No string, 1=A """ string
|
|
1066
1038
|
self.setCurrentBlockState(0)
|
|
1067
1039
|
|
|
1068
|
-
#
|
|
1069
|
-
if self.previousBlockState()
|
|
1070
|
-
#
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1040
|
+
# Continuing a multi-line string?
|
|
1041
|
+
if self.previousBlockState() == 1:
|
|
1042
|
+
# Search for string stop
|
|
1043
|
+
ms = self._string.match(text)
|
|
1044
|
+
if ms.hasMatch():
|
|
1045
|
+
# Terminate the multi-line string
|
|
1046
|
+
offset = ms.capturedEnd(0)
|
|
1047
|
+
self.setFormat(0, offset, STYLE_ANNOT_VAL)
|
|
1075
1048
|
else:
|
|
1076
|
-
|
|
1049
|
+
# Whole line in the string
|
|
1050
|
+
self.setCurrentBlockState(1)
|
|
1051
|
+
self.setFormat(0, len(text), STYLE_ANNOT_VAL)
|
|
1052
|
+
return
|
|
1077
1053
|
else:
|
|
1078
|
-
|
|
1054
|
+
# Search for string start
|
|
1055
|
+
ms = self._string.match(text)
|
|
1056
|
+
if ms.hasMatch():
|
|
1057
|
+
# Potential start, but check that it's not commented out
|
|
1058
|
+
start = ms.capturedStart()
|
|
1059
|
+
mc = self._comment.match(text)
|
|
1060
|
+
if not (mc.hasMatch() and mc.capturedStart() < start):
|
|
1061
|
+
# Definitely a string start. See if it ends on this line
|
|
1062
|
+
me = self._string.match(text, offset=ms.capturedEnd())
|
|
1063
|
+
if me.hasMatch():
|
|
1064
|
+
# Terminate the single-line string
|
|
1065
|
+
end = me.capturedEnd()
|
|
1066
|
+
self.setFormat(start, end - start, STYLE_ANNOT_VAL)
|
|
1067
|
+
strings.append((start, end))
|
|
1068
|
+
else:
|
|
1069
|
+
# Multi-line string
|
|
1070
|
+
self.setCurrentBlockState(1)
|
|
1071
|
+
self.setFormat(start, len(text), STYLE_ANNOT_VAL)
|
|
1072
|
+
|
|
1073
|
+
# Comment
|
|
1074
|
+
i = self._comment.globalMatch(text, offset=offset)
|
|
1075
|
+
while i.hasNext():
|
|
1076
|
+
m = i.next()
|
|
1077
|
+
x = m.capturedStart()
|
|
1078
|
+
if self._highlight_ok(strings, x, 1):
|
|
1079
|
+
self.setFormat(x, len(text) - x, STYLE_COMMENT)
|
|
1080
|
+
text = text[:x]
|
|
1081
|
+
break
|
|
1079
1082
|
|
|
1080
|
-
#
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
self.
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1083
|
+
# Rule-based formatting
|
|
1084
|
+
for (pattern, style) in self._rules:
|
|
1085
|
+
i = pattern.globalMatch(text, offset=offset)
|
|
1086
|
+
while i.hasNext():
|
|
1087
|
+
m = i.next()
|
|
1088
|
+
x, w = m.capturedStart(), m.capturedLength()
|
|
1089
|
+
if self._highlight_ok(strings, x, w):
|
|
1090
|
+
self.setFormat(x, w, style)
|
|
1091
|
+
|
|
1092
|
+
# Model and component headers (must be at start of string)
|
|
1093
|
+
if offset == 0:
|
|
1094
|
+
m = self._rule_head.match(text)
|
|
1095
|
+
if m.hasMatch():
|
|
1096
|
+
x, w = m.capturedStart(1), m.capturedLength(1)
|
|
1097
|
+
self.setFormat(x, w, STYLE_HEADER)
|
|
1098
|
+
|
|
1099
|
+
# Variable units (must be at start of string)
|
|
1100
|
+
if offset == 0:
|
|
1101
|
+
m = self._rule_var_unit.match(text)
|
|
1102
|
+
if m.hasMatch():
|
|
1103
|
+
self.setFormat(
|
|
1104
|
+
m.capturedStart(2), m.capturedLength(2), STYLE_ANNOT_KEY)
|
|
1105
|
+
self.setFormat(
|
|
1106
|
+
m.capturedStart(4), m.capturedLength(4), STYLE_ANNOT_VAL)
|
|
1107
|
+
|
|
1108
|
+
# Binds and labels
|
|
1109
|
+
for pattern in self._rules_labels:
|
|
1110
|
+
i = pattern.globalMatch(text, offset=offset)
|
|
1111
|
+
while i.hasNext():
|
|
1112
|
+
m = i.next()
|
|
1113
|
+
x, w = m.capturedStart(), m.capturedLength()
|
|
1114
|
+
if self._highlight_ok(strings, x, w):
|
|
1115
|
+
self.setFormat(m.capturedStart(2), m.capturedLength(2),
|
|
1116
|
+
STYLE_ANNOT_KEY)
|
|
1117
|
+
self.setFormat(m.capturedStart(3), m.capturedLength(3),
|
|
1118
|
+
STYLE_ANNOT_VAL)
|
|
1119
|
+
|
|
1120
|
+
# Meta properties (must be at start of string)
|
|
1121
|
+
if offset == 0:
|
|
1122
|
+
m = self._rule_meta.match(text)
|
|
1123
|
+
if m.hasMatch():
|
|
1124
|
+
self.setFormat(
|
|
1125
|
+
m.capturedStart(1), m.capturedLength(1), STYLE_ANNOT_KEY)
|
|
1126
|
+
# Don't reformat strings (or bits after string end!)
|
|
1127
|
+
if m.captured(3)[:3] != '"""':
|
|
1128
|
+
self.setFormat(m.capturedStart(3), m.capturedLength(3),
|
|
1129
|
+
STYLE_ANNOT_VAL)
|
|
1097
1130
|
|
|
1098
1131
|
|
|
1099
1132
|
class ProtocolHighlighter(QtGui.QSyntaxHighlighter):
|
|
@@ -1101,43 +1134,40 @@ class ProtocolHighlighter(QtGui.QSyntaxHighlighter):
|
|
|
1101
1134
|
Syntax highlighter for ``mmt`` protocol definitions.
|
|
1102
1135
|
"""
|
|
1103
1136
|
def __init__(self, document):
|
|
1104
|
-
super(
|
|
1137
|
+
super().__init__(document)
|
|
1105
1138
|
|
|
1106
1139
|
# Headers and units
|
|
1107
|
-
|
|
1140
|
+
R = QtCore.QRegularExpression
|
|
1141
|
+
self._rule_head = R(r'^\s*(\[\[[a-zA-Z0-9_]+\]\])')
|
|
1108
1142
|
|
|
1109
1143
|
# Highlighting rules
|
|
1110
1144
|
self._rules = []
|
|
1111
1145
|
|
|
1112
1146
|
# Numbers
|
|
1113
|
-
|
|
1114
|
-
|
|
1147
|
+
self._rules.append(
|
|
1148
|
+
(R(r'\b[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?\b'), STYLE_LITERAL))
|
|
1115
1149
|
|
|
1116
1150
|
# Keyword "next"
|
|
1117
|
-
|
|
1118
|
-
self._rules.append((pattern, STYLE_KEYWORD_1))
|
|
1151
|
+
self._rules.append((R(r'\bnext\b'), STYLE_KEYWORD_1))
|
|
1119
1152
|
|
|
1120
1153
|
# Comments
|
|
1121
|
-
|
|
1122
|
-
self._rules.append((pattern, STYLE_COMMENT))
|
|
1154
|
+
self._rules.append((R(r'#[^\n]*'), STYLE_COMMENT))
|
|
1123
1155
|
|
|
1124
1156
|
def highlightBlock(self, text):
|
|
1125
1157
|
""" Qt: Called whenever a block should be highlighted. """
|
|
1158
|
+
|
|
1126
1159
|
# Rule based formatting
|
|
1127
1160
|
for (pattern, style) in self._rules:
|
|
1128
|
-
i = pattern.
|
|
1129
|
-
while i
|
|
1130
|
-
|
|
1131
|
-
self.setFormat(
|
|
1132
|
-
i = pattern.indexIn(text, i + n)
|
|
1161
|
+
i = pattern.globalMatch(text)
|
|
1162
|
+
while i.hasNext():
|
|
1163
|
+
m = i.next()
|
|
1164
|
+
self.setFormat(m.capturedStart(), m.capturedLength(), style)
|
|
1133
1165
|
|
|
1134
|
-
# Protocol header
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
self.setFormat(i + m, n - m, STYLE_HEADER)
|
|
1140
|
-
i = self._rule_head.indexIn(text, i + n)
|
|
1166
|
+
# Protocol header (must be at strart of string)
|
|
1167
|
+
m = self._rule_head.match(text)
|
|
1168
|
+
if m.hasMatch():
|
|
1169
|
+
self.setFormat(
|
|
1170
|
+
m.capturedStart(1), m.capturedLength(1), STYLE_HEADER)
|
|
1141
1171
|
|
|
1142
1172
|
|
|
1143
1173
|
class ScriptHighlighter(QtGui.QSyntaxHighlighter):
|
|
@@ -1145,10 +1175,11 @@ class ScriptHighlighter(QtGui.QSyntaxHighlighter):
|
|
|
1145
1175
|
Syntax highlighter for ``mmt`` script files.
|
|
1146
1176
|
"""
|
|
1147
1177
|
def __init__(self, document):
|
|
1148
|
-
super(
|
|
1178
|
+
super().__init__(document)
|
|
1149
1179
|
|
|
1150
|
-
#
|
|
1151
|
-
|
|
1180
|
+
# Script header
|
|
1181
|
+
R = QtCore.QRegularExpression
|
|
1182
|
+
self._rule_head = R(r'^\s*(\[\[[a-zA-Z0-9_]+\]\])')
|
|
1152
1183
|
|
|
1153
1184
|
# Highlighting rules
|
|
1154
1185
|
self._rules = []
|
|
@@ -1156,197 +1187,197 @@ class ScriptHighlighter(QtGui.QSyntaxHighlighter):
|
|
|
1156
1187
|
# Keywords
|
|
1157
1188
|
import keyword
|
|
1158
1189
|
for kw in keyword.kwlist:
|
|
1159
|
-
|
|
1160
|
-
self._rules.append((pattern, STYLE_KEYWORD_1))
|
|
1190
|
+
self._rules.append((R(r'\b' + kw + r'\b'), STYLE_KEYWORD_1))
|
|
1161
1191
|
|
|
1162
1192
|
# Built-in essential functions
|
|
1163
1193
|
for func in _PYFUNC:
|
|
1164
|
-
|
|
1165
|
-
self._rules.append((pattern, STYLE_KEYWORD_2))
|
|
1194
|
+
self._rules.append((R(r'\b' + str(func) + r'\b'), STYLE_KEYWORD_2))
|
|
1166
1195
|
|
|
1167
1196
|
# Literals: numbers, True, False, None
|
|
1168
1197
|
# Override some keywords
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
self._rules.append((
|
|
1173
|
-
|
|
1174
|
-
self._rules.append((pattern, STYLE_LITERAL))
|
|
1175
|
-
pattern = QtCore.QRegExp(r'\bNone\b')
|
|
1176
|
-
self._rules.append((pattern, STYLE_LITERAL))
|
|
1198
|
+
self._rules.append((R(r'\b[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?\b'),
|
|
1199
|
+
STYLE_LITERAL))
|
|
1200
|
+
self._rules.append((R(r'\bTrue\b'), STYLE_LITERAL))
|
|
1201
|
+
self._rules.append((R(r'\bFalse\b'), STYLE_LITERAL))
|
|
1202
|
+
self._rules.append((R(r'\bNone\b'), STYLE_LITERAL))
|
|
1177
1203
|
|
|
1178
1204
|
# Strings
|
|
1179
|
-
|
|
1180
|
-
self.
|
|
1181
|
-
|
|
1182
|
-
self.
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
self._string2 = QtCore.QRegExp(r'"""')
|
|
1205
|
+
self._s1 = R(r'"')
|
|
1206
|
+
self._s2 = R(r"'")
|
|
1207
|
+
self._ms1 = R(r'"""')
|
|
1208
|
+
self._ms2 = R(r"'''")
|
|
1209
|
+
self._s_start = R(r'"""|\'\'\'|"|\'')
|
|
1210
|
+
self._s_end = {
|
|
1211
|
+
'"': self._s1, "'": self._s2, '"""': self._ms1, "'''": self._ms2}
|
|
1187
1212
|
|
|
1188
1213
|
# Comments
|
|
1189
|
-
|
|
1190
|
-
|
|
1214
|
+
self._comment = R(r'#')
|
|
1215
|
+
|
|
1216
|
+
def _highlight_ok(self, strings, start, length):
|
|
1217
|
+
""" Checks if the string ``start`` to ``length`` needs formatted. """
|
|
1218
|
+
for lo, hi in strings:
|
|
1219
|
+
if lo <= start < hi or lo <= start + length < hi:
|
|
1220
|
+
return False
|
|
1221
|
+
return True
|
|
1191
1222
|
|
|
1192
1223
|
def highlightBlock(self, text):
|
|
1193
1224
|
""" Qt: Called whenever a block should be highlighted. """
|
|
1194
|
-
# Rule based formatting
|
|
1195
|
-
for (pattern, style) in self._rules:
|
|
1196
|
-
i = pattern.indexIn(text)
|
|
1197
|
-
while i >= 0:
|
|
1198
|
-
# Note: Can't use matchedLength() here because it does quirky
|
|
1199
|
-
# things with the subgroup for the numbers regex.
|
|
1200
|
-
n = len(pattern.cap(0))
|
|
1201
|
-
self.setFormat(i, n, style)
|
|
1202
|
-
i = pattern.indexIn(text, i + n)
|
|
1203
1225
|
|
|
1204
|
-
#
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
# Block states:
|
|
1213
|
-
# 0 Normal
|
|
1214
|
-
# 1 Multi-line string 1
|
|
1215
|
-
# 2 Multi-line string 2
|
|
1226
|
+
# To avoid formatting within strings each is stored as a (start, end).
|
|
1227
|
+
strings = []
|
|
1228
|
+
# If the start has been handled, set the offset.
|
|
1229
|
+
offset = 0
|
|
1230
|
+
# If the end has been handled, chop it off the string
|
|
1231
|
+
|
|
1232
|
+
# Multi-line strings are done first, because they overrule a lot of
|
|
1233
|
+
# things and we can skip formatting if we're inside one.
|
|
1234
|
+
# Block states: 0=No string, 1=A " " " string, 2=A ' ' ' string
|
|
1216
1235
|
self.setCurrentBlockState(0)
|
|
1217
1236
|
|
|
1218
|
-
#
|
|
1219
|
-
def find_start(text, next):
|
|
1220
|
-
s1 = self._string1.indexIn(text, next)
|
|
1221
|
-
s2 = self._string2.indexIn(text, next)
|
|
1222
|
-
if s1 < 0 and s2 < 0:
|
|
1223
|
-
current = 0
|
|
1224
|
-
start = -1
|
|
1225
|
-
next = -1
|
|
1226
|
-
else:
|
|
1227
|
-
if s1 >= 0 and s2 >= 0:
|
|
1228
|
-
current = 1 if s1 < s2 else 2
|
|
1229
|
-
start = min(s1, s2)
|
|
1230
|
-
elif s1 >= 0:
|
|
1231
|
-
current = 1
|
|
1232
|
-
start = s1
|
|
1233
|
-
else: # (s2 >= 0)
|
|
1234
|
-
current = 2
|
|
1235
|
-
start = s2
|
|
1236
|
-
next = start + 3
|
|
1237
|
-
|
|
1238
|
-
# Check we're not in a comment
|
|
1239
|
-
i = text.rfind('\n', start) + 1
|
|
1240
|
-
if text[i:i + 1] == '#':
|
|
1241
|
-
current = 0
|
|
1242
|
-
start = next = -1
|
|
1243
|
-
|
|
1244
|
-
return current, start, next
|
|
1245
|
-
|
|
1246
|
-
# Check state of previous block
|
|
1237
|
+
# Continuing a multi-line string?
|
|
1247
1238
|
previous = self.previousBlockState()
|
|
1248
1239
|
if previous == 1 or previous == 2:
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
stop = self._string1.indexIn(text, next)
|
|
1240
|
+
# Search for string stop
|
|
1241
|
+
r = self._ms1 if previous == 1 else self._ms2
|
|
1242
|
+
ms = r.match(text)
|
|
1243
|
+
if ms.hasMatch():
|
|
1244
|
+
# Terminate the multi-line string, and increase global offset
|
|
1245
|
+
offset = ms.capturedEnd(0)
|
|
1246
|
+
self.setFormat(0, offset, STYLE_LITERAL)
|
|
1257
1247
|
else:
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1248
|
+
# Whole line in the string
|
|
1249
|
+
self.setCurrentBlockState(previous)
|
|
1250
|
+
self.setFormat(0, len(text), STYLE_LITERAL)
|
|
1251
|
+
return
|
|
1252
|
+
|
|
1253
|
+
# Search for string starts (single or multi-line)
|
|
1254
|
+
stroff = offset # Offset for string start/end searching
|
|
1255
|
+
m1 = self._s_start.match(text, offset=stroff)
|
|
1256
|
+
while m1.hasMatch():
|
|
1257
|
+
stroff = m1.capturedEnd()
|
|
1258
|
+
start = m1.capturedStart()
|
|
1259
|
+
# Are we in a comment?
|
|
1260
|
+
mc = self._comment.match(text)
|
|
1261
|
+
if (mc.hasMatch() and mc.capturedStart() < start):
|
|
1262
|
+
# No point searching for further string starts
|
|
1263
|
+
stroff = len(text)
|
|
1264
1264
|
else:
|
|
1265
|
-
#
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1265
|
+
# Find string end
|
|
1266
|
+
m2 = self._s_end[m1.captured()].match(text, offset=stroff)
|
|
1267
|
+
if m2.hasMatch():
|
|
1268
|
+
stroff = m2.capturedEnd()
|
|
1269
|
+
# Ignore if escaped
|
|
1270
|
+
if text[m2.capturedStart() - 1] != '\\':
|
|
1271
|
+
# Terminate the single line string and move on
|
|
1272
|
+
self.setFormat(start, stroff - start, STYLE_LITERAL)
|
|
1273
|
+
strings.append((start, stroff))
|
|
1274
|
+
elif m1.capturedLength() > 1:
|
|
1275
|
+
# Multi-line string start. Block finished!
|
|
1276
|
+
self.setCurrentBlockState(
|
|
1277
|
+
1 if m1.captured() == '"""' else 2)
|
|
1278
|
+
self.setFormat(start, len(text) - start, STYLE_LITERAL)
|
|
1279
|
+
return
|
|
1280
|
+
# No Match? Then not a string so ignore and continue
|
|
1281
|
+
m1 = self._s_start.match(text, offset=stroff)
|
|
1282
|
+
|
|
1283
|
+
# Comment
|
|
1284
|
+
i = self._comment.globalMatch(text, offset=offset)
|
|
1285
|
+
while i.hasNext():
|
|
1286
|
+
m = i.next()
|
|
1287
|
+
x = m.capturedStart()
|
|
1288
|
+
if self._highlight_ok(strings, x, 1):
|
|
1289
|
+
self.setFormat(x, len(text) - x, STYLE_COMMENT)
|
|
1290
|
+
text = text[:x]
|
|
1291
|
+
break
|
|
1292
|
+
|
|
1293
|
+
# Script header (must be at start of string)
|
|
1294
|
+
if offset == 0:
|
|
1295
|
+
m = self._rule_head.match(text)
|
|
1296
|
+
if m.hasMatch():
|
|
1297
|
+
self.setFormat(
|
|
1298
|
+
m.capturedStart(1), m.capturedLength(1), STYLE_HEADER)
|
|
1299
|
+
|
|
1300
|
+
# Rule based formatting
|
|
1301
|
+
for (pattern, style) in self._rules:
|
|
1302
|
+
i = pattern.globalMatch(text, offset=offset)
|
|
1303
|
+
while i.hasNext():
|
|
1304
|
+
m = i.next()
|
|
1305
|
+
x, w = m.capturedStart(), m.capturedLength()
|
|
1306
|
+
if self._highlight_ok(strings, x, w):
|
|
1307
|
+
self.setFormat(x, w, style)
|
|
1272
1308
|
|
|
1273
1309
|
|
|
1274
1310
|
# List of essential built-in python functions
|
|
1275
1311
|
_PYFUNC = [
|
|
1276
1312
|
'abs()',
|
|
1277
|
-
'
|
|
1278
|
-
'input()',
|
|
1279
|
-
'open()',
|
|
1280
|
-
'staticmethod()',
|
|
1313
|
+
'aiter()',
|
|
1281
1314
|
'all()',
|
|
1282
|
-
'enumerate()',
|
|
1283
|
-
'int()',
|
|
1284
|
-
'ord()',
|
|
1285
|
-
'str()',
|
|
1286
1315
|
'any()',
|
|
1287
|
-
'
|
|
1288
|
-
'
|
|
1289
|
-
'pow()',
|
|
1290
|
-
'sum()',
|
|
1291
|
-
'basestring()',
|
|
1292
|
-
'execfile()',
|
|
1293
|
-
'issubclass()',
|
|
1294
|
-
'print()',
|
|
1295
|
-
'super()',
|
|
1316
|
+
'anext()',
|
|
1317
|
+
'ascii()',
|
|
1296
1318
|
'bin()',
|
|
1297
|
-
'file()',
|
|
1298
|
-
'iter()',
|
|
1299
|
-
'property()',
|
|
1300
|
-
'tuple()',
|
|
1301
1319
|
'bool()',
|
|
1302
|
-
'
|
|
1303
|
-
'len()',
|
|
1304
|
-
'range()',
|
|
1305
|
-
'type()',
|
|
1320
|
+
'breakpoint()',
|
|
1306
1321
|
'bytearray()',
|
|
1307
|
-
'
|
|
1308
|
-
'list()',
|
|
1309
|
-
'raw_input()',
|
|
1310
|
-
'unichr()',
|
|
1322
|
+
'bytes()',
|
|
1311
1323
|
'callable()',
|
|
1312
|
-
'format()',
|
|
1313
|
-
'locals()',
|
|
1314
|
-
'reduce()',
|
|
1315
|
-
'unicode()',
|
|
1316
1324
|
'chr()',
|
|
1317
|
-
'frozenset()',
|
|
1318
|
-
'long()',
|
|
1319
|
-
'reload()',
|
|
1320
|
-
'vars()',
|
|
1321
1325
|
'classmethod()',
|
|
1326
|
+
'compile()',
|
|
1327
|
+
'complex()',
|
|
1328
|
+
'delattr()',
|
|
1329
|
+
'dict()',
|
|
1330
|
+
'dir()',
|
|
1331
|
+
'divmod()',
|
|
1332
|
+
'enumerate()',
|
|
1333
|
+
'eval()',
|
|
1334
|
+
'exec()',
|
|
1335
|
+
'filter()',
|
|
1336
|
+
'float()',
|
|
1337
|
+
'format()',
|
|
1338
|
+
'frozenset()',
|
|
1322
1339
|
'getattr()',
|
|
1323
|
-
'map()',
|
|
1324
|
-
'repr()',
|
|
1325
|
-
'range()',
|
|
1326
|
-
'cmp()',
|
|
1327
1340
|
'globals()',
|
|
1328
|
-
'max()',
|
|
1329
|
-
'reversed()',
|
|
1330
|
-
'zip()',
|
|
1331
|
-
'compile()',
|
|
1332
1341
|
'hasattr()',
|
|
1333
|
-
'memoryview()',
|
|
1334
|
-
'round()',
|
|
1335
|
-
'__import__()',
|
|
1336
|
-
'complex()',
|
|
1337
1342
|
'hash()',
|
|
1338
|
-
'min()',
|
|
1339
|
-
'set()',
|
|
1340
|
-
'delattr()',
|
|
1341
1343
|
'help()',
|
|
1342
|
-
'next()',
|
|
1343
|
-
'setattr()',
|
|
1344
|
-
'dict()',
|
|
1345
1344
|
'hex()',
|
|
1346
|
-
'object()',
|
|
1347
|
-
'slice()',
|
|
1348
|
-
'dir()',
|
|
1349
1345
|
'id()',
|
|
1346
|
+
'input()',
|
|
1347
|
+
'int()',
|
|
1348
|
+
'isinstance()',
|
|
1349
|
+
'issubclass()',
|
|
1350
|
+
'iter()',
|
|
1351
|
+
'len()',
|
|
1352
|
+
'list()',
|
|
1353
|
+
'locals()',
|
|
1354
|
+
'map()',
|
|
1355
|
+
'max()',
|
|
1356
|
+
'memoryview()',
|
|
1357
|
+
'min()',
|
|
1358
|
+
'next()',
|
|
1359
|
+
'object()',
|
|
1350
1360
|
'oct()',
|
|
1361
|
+
'open()',
|
|
1362
|
+
'ord()',
|
|
1363
|
+
'pow()',
|
|
1364
|
+
'print()',
|
|
1365
|
+
'property()',
|
|
1366
|
+
'range()',
|
|
1367
|
+
'repr()',
|
|
1368
|
+
'reversed()',
|
|
1369
|
+
'round()',
|
|
1370
|
+
'set()',
|
|
1371
|
+
'setattr()',
|
|
1372
|
+
'slice()',
|
|
1351
1373
|
'sorted()',
|
|
1374
|
+
'staticmethod()',
|
|
1375
|
+
'str()',
|
|
1376
|
+
'sum()',
|
|
1377
|
+
'super()',
|
|
1378
|
+
'tuple()',
|
|
1379
|
+
'type()',
|
|
1380
|
+
'vars()',
|
|
1381
|
+
'zip()',
|
|
1382
|
+
'__import__()',
|
|
1352
1383
|
]
|