PrEditor 1.0.0__py3-none-any.whl → 1.2.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.
Potentially problematic release.
This version of PrEditor might be problematic. Click here for more details.
- preditor/__init__.py +4 -1
- preditor/about_module.py +6 -2
- preditor/config.py +16 -0
- preditor/dccs/.hab.json +10 -0
- preditor/dccs/maya/PrEditor_maya.mod +0 -1
- preditor/dccs/maya/README.md +22 -0
- preditor/dccs/maya/plug-ins/PrEditor_maya.py +32 -1
- preditor/dccs/studiomax/PackageContents.xml +32 -0
- preditor/dccs/studiomax/PrEditor-PrEditor_Show.mcr +8 -0
- preditor/dccs/studiomax/README.md +17 -0
- preditor/dccs/studiomax/preditor.ms +16 -0
- preditor/dccs/studiomax/preditor_menu.mnx +7 -0
- preditor/debug.py +7 -3
- preditor/excepthooks.py +15 -6
- preditor/gui/app.py +2 -2
- preditor/gui/codehighlighter.py +10 -24
- preditor/gui/completer.py +17 -6
- preditor/gui/console.py +77 -47
- preditor/gui/dialog.py +10 -7
- preditor/gui/drag_tab_bar.py +7 -7
- preditor/gui/errordialog.py +2 -2
- preditor/gui/find_files.py +7 -5
- preditor/gui/fuzzy_search/fuzzy_search.py +8 -4
- preditor/gui/group_tab_widget/__init__.py +4 -4
- preditor/gui/group_tab_widget/grouped_tab_models.py +4 -4
- preditor/gui/group_tab_widget/grouped_tab_widget.py +6 -4
- preditor/gui/level_buttons.py +16 -1
- preditor/gui/loggerwindow.py +51 -28
- preditor/gui/set_text_editor_path_dialog.py +3 -1
- preditor/gui/window.py +4 -4
- preditor/gui/workbox_mixin.py +40 -11
- preditor/gui/workbox_text_edit.py +5 -3
- preditor/gui/workboxwidget.py +16 -12
- preditor/logging_config.py +5 -2
- preditor/scintilla/__init__.py +19 -1
- preditor/scintilla/delayables/smart_highlight.py +7 -4
- preditor/scintilla/delayables/spell_check.py +5 -4
- preditor/scintilla/documenteditor.py +165 -116
- preditor/scintilla/finddialog.py +3 -3
- preditor/scintilla/lang/language.py +1 -1
- preditor/scintilla/lexers/cpplexer.py +3 -2
- preditor/scintilla/lexers/javascriptlexer.py +6 -4
- preditor/scintilla/lexers/maxscriptlexer.py +8 -7
- preditor/scintilla/lexers/mellexer.py +3 -2
- preditor/scintilla/lexers/mulexer.py +3 -2
- preditor/scintilla/lexers/pythonlexer.py +7 -6
- preditor/utils/cute.py +9 -8
- preditor/version.py +16 -3
- {preditor-1.0.0.dist-info → preditor-1.2.0.dist-info}/METADATA +69 -32
- {preditor-1.0.0.dist-info → preditor-1.2.0.dist-info}/RECORD +56 -47
- preditor-1.2.0.dist-info/top_level.txt +3 -0
- tests/find_files/test_find_files.py +74 -0
- tests/ide/test_delayable_engine.py +171 -0
- preditor-1.0.0.dist-info/top_level.txt +0 -1
- {preditor-1.0.0.dist-info → preditor-1.2.0.dist-info}/WHEEL +0 -0
- {preditor-1.0.0.dist-info → preditor-1.2.0.dist-info}/entry_points.txt +0 -0
- {preditor-1.0.0.dist-info → preditor-1.2.0.dist-info}/licenses/LICENSE +0 -0
preditor/gui/loggerwindow.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import absolute_import, print_function
|
|
|
2
2
|
|
|
3
3
|
import itertools
|
|
4
4
|
import json
|
|
5
|
+
import logging
|
|
5
6
|
import os
|
|
6
7
|
import re
|
|
7
8
|
import sys
|
|
@@ -11,15 +12,17 @@ from datetime import datetime, timedelta
|
|
|
11
12
|
from functools import partial
|
|
12
13
|
|
|
13
14
|
import __main__
|
|
15
|
+
import Qt as Qt_py
|
|
14
16
|
from Qt import QtCompat, QtCore, QtWidgets
|
|
15
17
|
from Qt.QtCore import QByteArray, Qt, QTimer, Signal, Slot
|
|
16
|
-
from Qt.QtGui import QCursor, QFont, QIcon, QTextCursor
|
|
18
|
+
from Qt.QtGui import QCursor, QFont, QIcon, QKeySequence, QTextCursor
|
|
17
19
|
from Qt.QtWidgets import (
|
|
18
20
|
QApplication,
|
|
19
21
|
QFontDialog,
|
|
20
22
|
QInputDialog,
|
|
21
23
|
QMessageBox,
|
|
22
24
|
QTextBrowser,
|
|
25
|
+
QTextEdit,
|
|
23
26
|
QToolTip,
|
|
24
27
|
QVBoxLayout,
|
|
25
28
|
)
|
|
@@ -27,7 +30,7 @@ from Qt.QtWidgets import (
|
|
|
27
30
|
from .. import (
|
|
28
31
|
DEFAULT_CORE_NAME,
|
|
29
32
|
about_preditor,
|
|
30
|
-
|
|
33
|
+
config,
|
|
31
34
|
debug,
|
|
32
35
|
get_core_name,
|
|
33
36
|
osystem,
|
|
@@ -46,6 +49,8 @@ from .level_buttons import LoggingLevelButton
|
|
|
46
49
|
from .set_text_editor_path_dialog import SetTextEditorPathDialog
|
|
47
50
|
from .status_label import StatusLabel
|
|
48
51
|
|
|
52
|
+
logger = logging.getLogger(__name__)
|
|
53
|
+
|
|
49
54
|
|
|
50
55
|
class WorkboxPages:
|
|
51
56
|
"""Nice names for the uiWorkboxSTACK indexes."""
|
|
@@ -195,7 +200,7 @@ class LoggerWindow(Window):
|
|
|
195
200
|
self.uiCompleterModeMENU.addSeparator()
|
|
196
201
|
action = self.uiCompleterModeMENU.addAction('Cycle mode')
|
|
197
202
|
action.setObjectName('uiCycleModeACT')
|
|
198
|
-
action.setShortcut(Qt.CTRL | Qt.Key_M)
|
|
203
|
+
action.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_M))
|
|
199
204
|
action.triggered.connect(self.cycleCompleterMode)
|
|
200
205
|
self.uiCompleterModeMENU.hovered.connect(self.handleMenuHovered)
|
|
201
206
|
|
|
@@ -487,7 +492,7 @@ class LoggerWindow(Window):
|
|
|
487
492
|
|
|
488
493
|
def openSetPreferredTextEditorDialog(self):
|
|
489
494
|
dlg = SetTextEditorPathDialog(parent=self)
|
|
490
|
-
dlg.
|
|
495
|
+
dlg.exec()
|
|
491
496
|
|
|
492
497
|
def focusToConsole(self):
|
|
493
498
|
"""Move focus to the console"""
|
|
@@ -526,7 +531,7 @@ class LoggerWindow(Window):
|
|
|
526
531
|
|
|
527
532
|
cursor = console.textCursor()
|
|
528
533
|
if not cursor.hasSelection():
|
|
529
|
-
cursor.select(QTextCursor.LineUnderCursor)
|
|
534
|
+
cursor.select(QTextCursor.SelectionType.LineUnderCursor)
|
|
530
535
|
text = cursor.selectedText()
|
|
531
536
|
prompt = console.prompt()
|
|
532
537
|
if text.startswith(prompt):
|
|
@@ -562,7 +567,7 @@ class LoggerWindow(Window):
|
|
|
562
567
|
|
|
563
568
|
def wheelEvent(self, event):
|
|
564
569
|
"""adjust font size on ctrl+scrollWheel"""
|
|
565
|
-
if event.modifiers() == Qt.ControlModifier:
|
|
570
|
+
if event.modifiers() == Qt.KeyboardModifier.ControlModifier:
|
|
566
571
|
# WheelEvents can be emitted in a cluster, but we only want one at a time
|
|
567
572
|
# (ie to change font size by 1, rather than 2 or 3). Let's bail if previous
|
|
568
573
|
# font-resize wheel event was within a certain threshhold.
|
|
@@ -602,7 +607,10 @@ class LoggerWindow(Window):
|
|
|
602
607
|
else:
|
|
603
608
|
text = action.toolTip()
|
|
604
609
|
|
|
605
|
-
|
|
610
|
+
if Qt_py.IsPyQt4:
|
|
611
|
+
menu = action.parentWidget()
|
|
612
|
+
else:
|
|
613
|
+
menu = action.parent()
|
|
606
614
|
QToolTip.showText(QCursor.pos(), text, menu)
|
|
607
615
|
|
|
608
616
|
def selectFont(self, monospace=False, proportional=False):
|
|
@@ -617,13 +625,16 @@ class LoggerWindow(Window):
|
|
|
617
625
|
curFontFamily = origFont.family()
|
|
618
626
|
|
|
619
627
|
if monospace and proportional:
|
|
620
|
-
options =
|
|
628
|
+
options = (
|
|
629
|
+
QFontDialog.FontDialogOption.MonospacedFonts
|
|
630
|
+
| QFontDialog.FontDialogOption.ProportionalFonts
|
|
631
|
+
)
|
|
621
632
|
kind = "monospace or proportional "
|
|
622
633
|
elif monospace:
|
|
623
|
-
options = QFontDialog.MonospacedFonts
|
|
634
|
+
options = QFontDialog.FontDialogOption.MonospacedFonts
|
|
624
635
|
kind = "monospace "
|
|
625
636
|
elif proportional:
|
|
626
|
-
options = QFontDialog.ProportionalFonts
|
|
637
|
+
options = QFontDialog.FontDialogOption.ProportionalFonts
|
|
627
638
|
kind = "proportional "
|
|
628
639
|
|
|
629
640
|
# Present a QFontDialog for user to choose a font
|
|
@@ -683,9 +694,9 @@ class LoggerWindow(Window):
|
|
|
683
694
|
|
|
684
695
|
def adjustWorkboxOrientation(self, state):
|
|
685
696
|
if state:
|
|
686
|
-
self.uiSplitterSPLIT.setOrientation(Qt.Horizontal)
|
|
697
|
+
self.uiSplitterSPLIT.setOrientation(Qt.Orientation.Horizontal)
|
|
687
698
|
else:
|
|
688
|
-
self.uiSplitterSPLIT.setOrientation(Qt.Vertical)
|
|
699
|
+
self.uiSplitterSPLIT.setOrientation(Qt.Orientation.Vertical)
|
|
689
700
|
|
|
690
701
|
def backupPreferences(self):
|
|
691
702
|
"""Saves a copy of the current preferences to a zip archive."""
|
|
@@ -754,7 +765,11 @@ class LoggerWindow(Window):
|
|
|
754
765
|
|
|
755
766
|
def keyPressEvent(self, event):
|
|
756
767
|
# Fix 'Maya : Qt tools lose focus' https://redmine.blur.com/issues/34430
|
|
757
|
-
if event.modifiers() & (
|
|
768
|
+
if event.modifiers() & (
|
|
769
|
+
Qt.KeyboardModifier.AltModifier
|
|
770
|
+
| Qt.KeyboardModifier.ControlModifier
|
|
771
|
+
| Qt.KeyboardModifier.ShiftModifier
|
|
772
|
+
):
|
|
758
773
|
pass
|
|
759
774
|
else:
|
|
760
775
|
super(LoggerWindow, self).keyPressEvent(event)
|
|
@@ -778,7 +793,7 @@ class LoggerWindow(Window):
|
|
|
778
793
|
pref.update(
|
|
779
794
|
{
|
|
780
795
|
'loggergeom': [geo.x(), geo.y(), geo.width(), geo.height()],
|
|
781
|
-
'windowState':
|
|
796
|
+
'windowState': QtCompat.enumValue(self.windowState()),
|
|
782
797
|
'SplitterVertical': self.uiEditorVerticalACT.isChecked(),
|
|
783
798
|
'SplitterSize': self.uiSplitterSPLIT.sizes(),
|
|
784
799
|
'tabIndent': self.uiIndentationsTabsACT.isChecked(),
|
|
@@ -860,7 +875,7 @@ class LoggerWindow(Window):
|
|
|
860
875
|
if dialog.objectName() in self.dont_ask_again:
|
|
861
876
|
return
|
|
862
877
|
|
|
863
|
-
dialog.
|
|
878
|
+
dialog.exec()
|
|
864
879
|
|
|
865
880
|
def restartLogger(self):
|
|
866
881
|
"""Closes this PrEditor instance and starts a new process with the same
|
|
@@ -908,7 +923,7 @@ class LoggerWindow(Window):
|
|
|
908
923
|
sizes = pref.get('SplitterSize')
|
|
909
924
|
if sizes:
|
|
910
925
|
self.uiSplitterSPLIT.setSizes(sizes)
|
|
911
|
-
self.setWindowState(Qt.
|
|
926
|
+
self.setWindowState(Qt.WindowState(pref.get('windowState', 0)))
|
|
912
927
|
self.uiIndentationsTabsACT.setChecked(pref.get('tabIndent', True))
|
|
913
928
|
self.uiCopyTabsToSpacesACT.setChecked(pref.get('copyIndentsAsSpaces', False))
|
|
914
929
|
|
|
@@ -980,7 +995,7 @@ class LoggerWindow(Window):
|
|
|
980
995
|
_font = pref.get('consoleFont', None)
|
|
981
996
|
if _font:
|
|
982
997
|
font = QFont()
|
|
983
|
-
if
|
|
998
|
+
if QtCompat.QFont.fromString(font, _font):
|
|
984
999
|
self.console().setConsoleFont(font)
|
|
985
1000
|
|
|
986
1001
|
self.dont_ask_again = pref.get('dont_ask_again', [])
|
|
@@ -1163,9 +1178,9 @@ class LoggerWindow(Window):
|
|
|
1163
1178
|
|
|
1164
1179
|
def setWordWrap(self, state):
|
|
1165
1180
|
if state:
|
|
1166
|
-
self.uiConsoleTXT.setLineWrapMode(
|
|
1181
|
+
self.uiConsoleTXT.setLineWrapMode(QTextEdit.LineWrapMode.WidgetWidth)
|
|
1167
1182
|
else:
|
|
1168
|
-
self.uiConsoleTXT.setLineWrapMode(
|
|
1183
|
+
self.uiConsoleTXT.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
|
|
1169
1184
|
|
|
1170
1185
|
def show_about(self):
|
|
1171
1186
|
"""Shows `preditor.about_preditor()`'s output in a message box."""
|
|
@@ -1245,7 +1260,7 @@ class LoggerWindow(Window):
|
|
|
1245
1260
|
|
|
1246
1261
|
# if this is the global instance, then allow it to be deleted on close
|
|
1247
1262
|
if self == LoggerWindow._instance:
|
|
1248
|
-
self.setAttribute(Qt.WA_DeleteOnClose, True)
|
|
1263
|
+
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
|
|
1249
1264
|
LoggerWindow._instance = None
|
|
1250
1265
|
|
|
1251
1266
|
# clear out the system
|
|
@@ -1335,18 +1350,16 @@ class LoggerWindow(Window):
|
|
|
1335
1350
|
parent, name=name, run_workbox=run_workbox, standalone=standalone
|
|
1336
1351
|
)
|
|
1337
1352
|
|
|
1338
|
-
# RV has a Unique window structure. It makes more sense to not parent a
|
|
1339
|
-
# singleton window than to parent it to a specific top level window.
|
|
1340
|
-
if core.objectName() == 'rv':
|
|
1341
|
-
inst.setParent(None)
|
|
1342
|
-
inst.setAttribute(Qt.WA_QuitOnClose, False)
|
|
1343
|
-
|
|
1344
1353
|
# protect the memory
|
|
1345
|
-
inst.setAttribute(Qt.WA_DeleteOnClose, False)
|
|
1354
|
+
inst.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False)
|
|
1346
1355
|
|
|
1347
1356
|
# cache the instance
|
|
1348
1357
|
LoggerWindow._instance = inst
|
|
1349
1358
|
|
|
1359
|
+
# Allow customization when the instance is first created.
|
|
1360
|
+
if config.on_create_callback:
|
|
1361
|
+
config.on_create_callback(inst)
|
|
1362
|
+
|
|
1350
1363
|
return LoggerWindow._instance
|
|
1351
1364
|
|
|
1352
1365
|
def installLogToFile(self):
|
|
@@ -1380,6 +1393,16 @@ class LoggerWindow(Window):
|
|
|
1380
1393
|
bool: If a shutdown was required
|
|
1381
1394
|
"""
|
|
1382
1395
|
if cls._instance:
|
|
1383
|
-
|
|
1396
|
+
try:
|
|
1397
|
+
cls._instance.shutdown()
|
|
1398
|
+
except RuntimeError as error:
|
|
1399
|
+
# If called after the host Qt application has been closed then
|
|
1400
|
+
# the instance has been deleted and we can't save preferences
|
|
1401
|
+
# without getting a RuntimeError about C/C++ being deleted.
|
|
1402
|
+
logger.warning(
|
|
1403
|
+
f"instance_shutdown failed PrEditor prefs likely not saved: {error}"
|
|
1404
|
+
)
|
|
1405
|
+
return False
|
|
1406
|
+
|
|
1384
1407
|
return True
|
|
1385
1408
|
return False
|
|
@@ -56,4 +56,6 @@ class SetTextEditorPathDialog(QDialog):
|
|
|
56
56
|
else:
|
|
57
57
|
msg = "That path doesn't exists or isn't an executable file."
|
|
58
58
|
label = 'Incorrect Path'
|
|
59
|
-
QMessageBox.warning(
|
|
59
|
+
QMessageBox.warning(
|
|
60
|
+
self.window(), label, msg, QMessageBox.StandardButton.Ok
|
|
61
|
+
)
|
preditor/gui/window.py
CHANGED
|
@@ -25,7 +25,7 @@ class Window(QMainWindow):
|
|
|
25
25
|
if not cls._instance:
|
|
26
26
|
cls._instance = cls(parent=parent)
|
|
27
27
|
# protect the memory
|
|
28
|
-
cls._instance.setAttribute(Qt.WA_DeleteOnClose, False)
|
|
28
|
+
cls._instance.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False)
|
|
29
29
|
return cls._instance
|
|
30
30
|
|
|
31
31
|
def __init__(self, parent=None, flags=0):
|
|
@@ -67,7 +67,7 @@ class Window(QMainWindow):
|
|
|
67
67
|
# dead dialogs
|
|
68
68
|
|
|
69
69
|
# set the delete attribute to clean up the window once it is closed
|
|
70
|
-
self.setAttribute(Qt.WA_DeleteOnClose, True)
|
|
70
|
+
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
|
|
71
71
|
# If this value is set to False calling setGeometry on this window will not
|
|
72
72
|
# adjust the geometry to ensure the window is on a valid screen.
|
|
73
73
|
self.checkScreenGeo = True
|
|
@@ -103,7 +103,7 @@ class Window(QMainWindow):
|
|
|
103
103
|
def closeEvent(self, event):
|
|
104
104
|
# ensure this object gets deleted
|
|
105
105
|
wwidget = None
|
|
106
|
-
if self.testAttribute(Qt.WA_DeleteOnClose):
|
|
106
|
+
if self.testAttribute(Qt.WidgetAttribute.WA_DeleteOnClose):
|
|
107
107
|
# collect the win widget to uncache it
|
|
108
108
|
if self.parent() and self.parent().inherits('QWinWidget'):
|
|
109
109
|
wwidget = self.parent()
|
|
@@ -141,7 +141,7 @@ class Window(QMainWindow):
|
|
|
141
141
|
# allow the global instance to be cleared
|
|
142
142
|
if this == cls._instance:
|
|
143
143
|
cls._instance = None
|
|
144
|
-
this.setAttribute(Qt.WA_DeleteOnClose, True)
|
|
144
|
+
this.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
|
|
145
145
|
try:
|
|
146
146
|
this.close()
|
|
147
147
|
except RuntimeError:
|
preditor/gui/workbox_mixin.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import absolute_import, print_function
|
|
2
2
|
|
|
3
|
+
import io
|
|
3
4
|
import os
|
|
4
5
|
import tempfile
|
|
5
6
|
import textwrap
|
|
6
7
|
|
|
8
|
+
import chardet
|
|
7
9
|
from Qt.QtCore import Qt
|
|
8
10
|
from Qt.QtWidgets import QStackedWidget
|
|
9
11
|
|
|
@@ -317,14 +319,37 @@ class WorkboxMixin(object):
|
|
|
317
319
|
os.remove(tempfile)
|
|
318
320
|
|
|
319
321
|
@classmethod
|
|
320
|
-
def __open_file__(cls, filename):
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
def __open_file__(cls, filename, strict=True):
|
|
323
|
+
"""Open a file and try to detect the text encoding it was saved as.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
encoding(str): The detected encoding, Defaults to "utf-8" if unable
|
|
327
|
+
to detect encoding.
|
|
328
|
+
text(str): The contents of the file decoded to a str.
|
|
329
|
+
"""
|
|
330
|
+
with open(filename, "rb") as f:
|
|
331
|
+
text_bytes = f.read()
|
|
332
|
+
|
|
333
|
+
# Open file, detect source encoding and convert to utf-8
|
|
334
|
+
encoding = chardet.detect(text_bytes)['encoding'] or 'utf-8'
|
|
335
|
+
try:
|
|
336
|
+
text = text_bytes.decode(encoding)
|
|
337
|
+
except UnicodeDecodeError as e:
|
|
338
|
+
if strict:
|
|
339
|
+
raise UnicodeDecodeError( # noqa: B904
|
|
340
|
+
e.encoding,
|
|
341
|
+
e.object,
|
|
342
|
+
e.start,
|
|
343
|
+
e.end,
|
|
344
|
+
f"{e.reason}, Filename: {filename}",
|
|
345
|
+
)
|
|
346
|
+
encoding = 'utf-8'
|
|
347
|
+
text = text_bytes.decode(encoding, errors="ignore")
|
|
348
|
+
return encoding, text
|
|
324
349
|
|
|
325
350
|
@classmethod
|
|
326
|
-
def __write_file__(cls, filename, txt):
|
|
327
|
-
with open(filename, 'w') as fle:
|
|
351
|
+
def __write_file__(cls, filename, txt, encoding=None):
|
|
352
|
+
with io.open(filename, 'w', newline='\n', encoding=encoding) as fle:
|
|
328
353
|
fle.write(txt)
|
|
329
354
|
|
|
330
355
|
def __show__(self):
|
|
@@ -335,7 +360,7 @@ class WorkboxMixin(object):
|
|
|
335
360
|
if self._filename_pref:
|
|
336
361
|
self.__load__(self._filename_pref)
|
|
337
362
|
elif self._tempfile:
|
|
338
|
-
txt = self.__open_file__(self.__tempfile__())
|
|
363
|
+
_, txt = self.__open_file__(self.__tempfile__(), strict=False)
|
|
339
364
|
self.__set_text__(txt)
|
|
340
365
|
|
|
341
366
|
def process_shortcut(self, event, run=True):
|
|
@@ -365,10 +390,14 @@ class WorkboxMixin(object):
|
|
|
365
390
|
modifiers = event.modifiers()
|
|
366
391
|
|
|
367
392
|
# Determine which relevant combos are pressed
|
|
368
|
-
ret = key == Qt.Key_Return
|
|
369
|
-
enter = key == Qt.Key_Enter
|
|
370
|
-
shift = modifiers == Qt.ShiftModifier
|
|
371
|
-
ctrlShift =
|
|
393
|
+
ret = key == Qt.Key.Key_Return
|
|
394
|
+
enter = key == Qt.Key.Key_Enter
|
|
395
|
+
shift = modifiers == Qt.KeyboardModifier.ShiftModifier
|
|
396
|
+
ctrlShift = (
|
|
397
|
+
modifiers
|
|
398
|
+
== Qt.KeyboardModifier.ControlModifier
|
|
399
|
+
| Qt.KeyboardModifier.ShiftModifier
|
|
400
|
+
)
|
|
372
401
|
|
|
373
402
|
# Determine which actions to take
|
|
374
403
|
evalTrunc = enter or (ret and shift)
|
|
@@ -27,6 +27,7 @@ class WorkboxTextEdit(WorkboxMixin, QTextEdit):
|
|
|
27
27
|
):
|
|
28
28
|
super(WorkboxTextEdit, self).__init__(parent=parent, core_name=core_name)
|
|
29
29
|
self._filename = None
|
|
30
|
+
self._encoding = None
|
|
30
31
|
self.__set_console__(console)
|
|
31
32
|
highlight = CodeHighlighter(self)
|
|
32
33
|
highlight.setLanguage('Python')
|
|
@@ -64,7 +65,7 @@ class WorkboxTextEdit(WorkboxMixin, QTextEdit):
|
|
|
64
65
|
|
|
65
66
|
def __set_font__(self, font):
|
|
66
67
|
metrics = QFontMetrics(font)
|
|
67
|
-
self.setTabStopDistance(metrics.
|
|
68
|
+
self.setTabStopDistance(metrics.horizontalAdvance(" ") * 4)
|
|
68
69
|
super(WorkboxTextEdit, self).setFont(font)
|
|
69
70
|
|
|
70
71
|
def __goto_line__(self, line):
|
|
@@ -79,7 +80,8 @@ class WorkboxTextEdit(WorkboxMixin, QTextEdit):
|
|
|
79
80
|
|
|
80
81
|
def __load__(self, filename):
|
|
81
82
|
self._filename = filename
|
|
82
|
-
txt = self.__open_file__(self._filename)
|
|
83
|
+
enc, txt = self.__open_file__(self._filename)
|
|
84
|
+
self._encoding = enc
|
|
83
85
|
self.__set_text__(txt)
|
|
84
86
|
|
|
85
87
|
def __margins_font__(self):
|
|
@@ -114,7 +116,7 @@ class WorkboxTextEdit(WorkboxMixin, QTextEdit):
|
|
|
114
116
|
|
|
115
117
|
selectText = self.window().uiSelectTextACT.isChecked() or selectText
|
|
116
118
|
if selectText:
|
|
117
|
-
cursor.select(QTextCursor.LineUnderCursor)
|
|
119
|
+
cursor.select(QTextCursor.SelectionType.LineUnderCursor)
|
|
118
120
|
self.setTextCursor(cursor)
|
|
119
121
|
|
|
120
122
|
return text, line
|
preditor/gui/workboxwidget.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import absolute_import, print_function
|
|
2
2
|
|
|
3
|
-
import io
|
|
4
3
|
import re
|
|
5
4
|
import time
|
|
6
5
|
|
|
@@ -10,6 +9,7 @@ from Qt.QtWidgets import QAction
|
|
|
10
9
|
|
|
11
10
|
from .. import core, resourcePath
|
|
12
11
|
from ..gui.workbox_mixin import WorkboxMixin
|
|
12
|
+
from ..scintilla import QsciScintilla
|
|
13
13
|
from ..scintilla.documenteditor import DocumentEditor, SearchOptions
|
|
14
14
|
from ..scintilla.finddialog import FindDialog
|
|
15
15
|
|
|
@@ -36,15 +36,19 @@ class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
|
36
36
|
self.initShortcuts()
|
|
37
37
|
self.setLanguage('Python')
|
|
38
38
|
# Default to unix newlines
|
|
39
|
-
self.setEolMode(
|
|
39
|
+
self.setEolMode(QsciScintilla.EolMode.EolUnix)
|
|
40
40
|
if hasattr(self.window(), "setWorkboxFontBasedOnConsole"):
|
|
41
41
|
self.window().setWorkboxFontBasedOnConsole()
|
|
42
42
|
|
|
43
43
|
def __auto_complete_enabled__(self):
|
|
44
|
-
return self.autoCompletionSource() ==
|
|
44
|
+
return self.autoCompletionSource() == QsciScintilla.AutoCompletionSource.AcsAll
|
|
45
45
|
|
|
46
46
|
def __set_auto_complete_enabled__(self, state):
|
|
47
|
-
state =
|
|
47
|
+
state = (
|
|
48
|
+
QsciScintilla.AutoCompletionSource.AcsAll
|
|
49
|
+
if state
|
|
50
|
+
else QsciScintilla.AutoCompletionSource.AcsNone
|
|
51
|
+
)
|
|
48
52
|
self.setAutoCompletionSource(state)
|
|
49
53
|
|
|
50
54
|
def __clear__(self):
|
|
@@ -120,7 +124,7 @@ class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
|
120
124
|
try:
|
|
121
125
|
marker = self._marker
|
|
122
126
|
except AttributeError:
|
|
123
|
-
self._marker = self.markerDefine(
|
|
127
|
+
self._marker = self.markerDefine(QsciScintilla.MarkerSymbol.Circle)
|
|
124
128
|
marker = self._marker
|
|
125
129
|
self.markerAdd(line, marker)
|
|
126
130
|
|
|
@@ -197,10 +201,10 @@ class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
|
197
201
|
self.setText(txt)
|
|
198
202
|
|
|
199
203
|
@classmethod
|
|
200
|
-
def __write_file__(cls, filename, txt):
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
+
def __write_file__(cls, filename, txt, encoding=None):
|
|
205
|
+
# Save unix newlines for simplicity
|
|
206
|
+
txt = cls.__unix_end_lines__(txt)
|
|
207
|
+
super(WorkboxWidget, cls).__write_file__(filename, txt, encoding=encoding)
|
|
204
208
|
|
|
205
209
|
def keyPressEvent(self, event):
|
|
206
210
|
"""Check for certain keyboard shortcuts, and handle them as needed,
|
|
@@ -216,13 +220,13 @@ class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
|
216
220
|
when Return is pressed), so this combination is not detectable.
|
|
217
221
|
"""
|
|
218
222
|
if self._software == 'softimage':
|
|
219
|
-
|
|
223
|
+
super(WorkboxWidget, self).keyPressEvent(event)
|
|
220
224
|
else:
|
|
221
225
|
if self.process_shortcut(event):
|
|
222
226
|
return
|
|
223
227
|
else:
|
|
224
228
|
# Send regular keystroke
|
|
225
|
-
|
|
229
|
+
super(WorkboxWidget, self).keyPressEvent(event)
|
|
226
230
|
|
|
227
231
|
def initShortcuts(self):
|
|
228
232
|
"""Use this to set up shortcuts when the DocumentEditor"""
|
|
@@ -248,7 +252,7 @@ class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
|
248
252
|
|
|
249
253
|
# create the search dialog and connect actions
|
|
250
254
|
self._searchDialog = FindDialog(self)
|
|
251
|
-
self._searchDialog.setAttribute(Qt.WA_DeleteOnClose, False)
|
|
255
|
+
self._searchDialog.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False)
|
|
252
256
|
self.uiFindACT.triggered.connect(
|
|
253
257
|
lambda: self._searchDialog.search(self.searchText())
|
|
254
258
|
)
|
preditor/logging_config.py
CHANGED
|
@@ -9,9 +9,12 @@ from .prefs import prefs_path
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class LoggingConfig(object):
|
|
12
|
-
def __init__(self, core_name, version=1):
|
|
12
|
+
def __init__(self, core_name, version=1, disable_existing_loggers=False):
|
|
13
13
|
self._filename = None
|
|
14
|
-
self.cfg = {
|
|
14
|
+
self.cfg = {
|
|
15
|
+
'version': version,
|
|
16
|
+
'disable_existing_loggers': disable_existing_loggers,
|
|
17
|
+
}
|
|
15
18
|
self.core_name = core_name
|
|
16
19
|
|
|
17
20
|
def add_logger(self, name, logger):
|
preditor/scintilla/__init__.py
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
|
|
3
|
+
__all__ = ["delayables", "FindState", "Qsci", "QsciScintilla"]
|
|
4
|
+
|
|
5
|
+
import Qt
|
|
6
|
+
|
|
7
|
+
if Qt.IsPyQt6:
|
|
8
|
+
from PyQt6 import Qsci
|
|
9
|
+
from PyQt6.Qsci import QsciScintilla
|
|
10
|
+
elif Qt.IsPyQt5:
|
|
11
|
+
from PyQt5 import Qsci
|
|
12
|
+
from PyQt5.Qsci import QsciScintilla
|
|
13
|
+
elif Qt.IsPyQt4:
|
|
14
|
+
from PyQt4 import Qsci
|
|
15
|
+
from PyQt4.Qsci import QsciScintilla
|
|
16
|
+
else:
|
|
17
|
+
raise ImportError(
|
|
18
|
+
"QScintilla library is not supported by {}".format(Qt.__binding__)
|
|
19
|
+
)
|
|
20
|
+
|
|
3
21
|
|
|
4
22
|
class FindState(object):
|
|
5
23
|
"""
|
|
@@ -19,4 +37,4 @@ class FindState(object):
|
|
|
19
37
|
self.end_pos = None
|
|
20
38
|
|
|
21
39
|
|
|
22
|
-
from . import delayables # noqa:
|
|
40
|
+
from . import delayables # noqa: E402
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
from __future__ import absolute_import, print_function
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Qt
|
|
4
4
|
from Qt.QtCore import QSignalMapper
|
|
5
5
|
from Qt.QtWidgets import QWidget
|
|
6
6
|
|
|
7
7
|
from ...delayable_engine.delayables import SearchDelayable
|
|
8
|
-
from .. import FindState
|
|
8
|
+
from .. import FindState, QsciScintilla
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class SmartHighlight(SearchDelayable):
|
|
12
12
|
key = 'smart_highlight'
|
|
13
13
|
indicator_number = 30
|
|
14
|
-
indicator_style = QsciScintilla.StraightBoxIndicator
|
|
14
|
+
indicator_style = QsciScintilla.IndicatorStyle.StraightBoxIndicator
|
|
15
15
|
border_alpha = 255
|
|
16
16
|
|
|
17
17
|
def __init__(self, engine):
|
|
@@ -36,7 +36,10 @@ class SmartHighlight(SearchDelayable):
|
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
self.signal_mapper.setMapping(document, document)
|
|
39
|
-
|
|
39
|
+
if Qt.IsPyQt4:
|
|
40
|
+
self.signal_mapper.mapped[QWidget].connect(self.update_highlighter)
|
|
41
|
+
else:
|
|
42
|
+
self.signal_mapper.mappedObject.connect(self.update_highlighter)
|
|
40
43
|
document.selectionChanged.connect(self.signal_mapper.map)
|
|
41
44
|
|
|
42
45
|
def clear_markings(self, document):
|
|
@@ -4,12 +4,11 @@ import logging
|
|
|
4
4
|
import re
|
|
5
5
|
import string
|
|
6
6
|
|
|
7
|
-
from PyQt5.Qsci import QsciScintilla
|
|
8
7
|
from Qt.QtCore import Qt
|
|
9
8
|
from Qt.QtGui import QColor
|
|
10
9
|
|
|
11
10
|
from ...delayable_engine.delayables import RangeDelayable
|
|
12
|
-
from .. import lang
|
|
11
|
+
from .. import QsciScintilla, lang
|
|
13
12
|
|
|
14
13
|
logger = logging.getLogger(__name__)
|
|
15
14
|
|
|
@@ -49,12 +48,14 @@ else:
|
|
|
49
48
|
# https://www.scintilla.org/ScintillaDox.html#SCI_INDICSETSTYLE
|
|
50
49
|
# https://qscintilla.com/#clickable_text/indicators
|
|
51
50
|
document.indicatorDefine(
|
|
52
|
-
QsciScintilla.SquiggleLowIndicator, self.indicator_number
|
|
51
|
+
QsciScintilla.IndicatorStyle.SquiggleLowIndicator, self.indicator_number
|
|
53
52
|
)
|
|
54
53
|
document.SendScintilla(
|
|
55
54
|
QsciScintilla.SCI_SETINDICATORCURRENT, self.indicator_number
|
|
56
55
|
)
|
|
57
|
-
document.setIndicatorForegroundColor(
|
|
56
|
+
document.setIndicatorForegroundColor(
|
|
57
|
+
QColor(Qt.GlobalColor.red), self.indicator_number
|
|
58
|
+
)
|
|
58
59
|
|
|
59
60
|
document.SCN_MODIFIED.connect(document.onTextModified)
|
|
60
61
|
|