PrEditor 2.1.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.
- preditor/__init__.py +315 -0
- preditor/__main__.py +13 -0
- preditor/about_module.py +165 -0
- preditor/cli.py +192 -0
- preditor/config.py +318 -0
- preditor/constants.py +13 -0
- preditor/contexts.py +210 -0
- preditor/cores/__init__.py +0 -0
- preditor/cores/core.py +20 -0
- preditor/dccs/.hab.json +10 -0
- preditor/dccs/maya/PrEditor_maya.mod +1 -0
- preditor/dccs/maya/README.md +22 -0
- preditor/dccs/maya/plug-ins/PrEditor_maya.py +141 -0
- 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 +149 -0
- preditor/delayable_engine/__init__.py +302 -0
- preditor/delayable_engine/delayables.py +85 -0
- preditor/enum.py +728 -0
- preditor/excepthooks.py +165 -0
- preditor/gui/__init__.py +56 -0
- preditor/gui/app.py +163 -0
- preditor/gui/codehighlighter.py +289 -0
- preditor/gui/completer.py +237 -0
- preditor/gui/console.py +605 -0
- preditor/gui/console_base.py +911 -0
- preditor/gui/dialog.py +181 -0
- preditor/gui/drag_tab_bar.py +625 -0
- preditor/gui/editor_chooser.py +57 -0
- preditor/gui/errordialog.py +69 -0
- preditor/gui/find_files.py +137 -0
- preditor/gui/fuzzy_search/__init__.py +0 -0
- preditor/gui/fuzzy_search/fuzzy_search.py +97 -0
- preditor/gui/group_tab_widget/__init__.py +0 -0
- preditor/gui/group_tab_widget/group_tab_widget.py +528 -0
- preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
- preditor/gui/group_tab_widget/grouped_tab_models.py +107 -0
- preditor/gui/group_tab_widget/grouped_tab_widget.py +223 -0
- preditor/gui/group_tab_widget/one_tab_widget.py +96 -0
- preditor/gui/level_buttons.py +358 -0
- preditor/gui/logger_window_handler.py +77 -0
- preditor/gui/logger_window_plugin.py +35 -0
- preditor/gui/loggerwindow.py +2405 -0
- preditor/gui/newtabwidget.py +69 -0
- preditor/gui/output_console.py +11 -0
- preditor/gui/qtdesigner/__init__.py +21 -0
- preditor/gui/qtdesigner/_log_plugin.py +29 -0
- preditor/gui/qtdesigner/console_base_plugin.py +48 -0
- preditor/gui/qtdesigner/console_predit_plugin.py +48 -0
- preditor/gui/set_text_editor_path_dialog.py +61 -0
- preditor/gui/status_label.py +99 -0
- preditor/gui/suggest_path_quotes_dialog.py +50 -0
- preditor/gui/ui/editor_chooser.ui +93 -0
- preditor/gui/ui/errordialog.ui +74 -0
- preditor/gui/ui/find_files.ui +140 -0
- preditor/gui/ui/loggerwindow.ui +1909 -0
- preditor/gui/ui/set_text_editor_path_dialog.ui +189 -0
- preditor/gui/ui/suggest_path_quotes_dialog.ui +225 -0
- preditor/gui/window.py +161 -0
- preditor/gui/workbox_mixin.py +1139 -0
- preditor/gui/workbox_text_edit.py +136 -0
- preditor/gui/workboxwidget.py +315 -0
- preditor/logging_config.py +55 -0
- preditor/osystem.py +401 -0
- preditor/plugins.py +118 -0
- preditor/prefs.py +381 -0
- preditor/resource/environment_variables.html +26 -0
- preditor/resource/error_mail.html +85 -0
- preditor/resource/error_mail_inline.html +41 -0
- preditor/resource/img/README.md +17 -0
- preditor/resource/img/arrow_forward.png +0 -0
- preditor/resource/img/check-bold.png +0 -0
- preditor/resource/img/chevron-down.png +0 -0
- preditor/resource/img/chevron-up.png +0 -0
- preditor/resource/img/close-thick.png +0 -0
- preditor/resource/img/comment-edit.png +0 -0
- preditor/resource/img/content-copy.png +0 -0
- preditor/resource/img/content-cut.png +0 -0
- preditor/resource/img/content-duplicate.png +0 -0
- preditor/resource/img/content-paste.png +0 -0
- preditor/resource/img/content-save.png +0 -0
- preditor/resource/img/debug_disabled.png +0 -0
- preditor/resource/img/eye-check.png +0 -0
- preditor/resource/img/file-plus.png +0 -0
- preditor/resource/img/file-remove.png +0 -0
- preditor/resource/img/format-align-left.png +0 -0
- preditor/resource/img/format-letter-case-lower.png +0 -0
- preditor/resource/img/format-letter-case-upper.png +0 -0
- preditor/resource/img/format-letter-case.svg +1 -0
- preditor/resource/img/information.png +0 -0
- preditor/resource/img/logging_critical.png +0 -0
- preditor/resource/img/logging_custom.png +0 -0
- preditor/resource/img/logging_debug.png +0 -0
- preditor/resource/img/logging_error.png +0 -0
- preditor/resource/img/logging_info.png +0 -0
- preditor/resource/img/logging_not_set.png +0 -0
- preditor/resource/img/logging_warning.png +0 -0
- preditor/resource/img/marker.png +0 -0
- preditor/resource/img/play.png +0 -0
- preditor/resource/img/playlist-play.png +0 -0
- preditor/resource/img/plus-minus-variant.png +0 -0
- preditor/resource/img/preditor.ico +0 -0
- preditor/resource/img/preditor.png +0 -0
- preditor/resource/img/preditor.psd +0 -0
- preditor/resource/img/preditor.svg +44 -0
- preditor/resource/img/regex.svg +1 -0
- preditor/resource/img/restart.svg +1 -0
- preditor/resource/img/skip-forward-outline.png +0 -0
- preditor/resource/img/skip-next-outline.png +0 -0
- preditor/resource/img/skip-next.png +0 -0
- preditor/resource/img/skip-previous.png +0 -0
- preditor/resource/img/subdirectory-arrow-right.png +0 -0
- preditor/resource/img/text-search-variant.png +0 -0
- preditor/resource/img/warning-big.png +0 -0
- preditor/resource/lang/python.json +30 -0
- preditor/resource/pref_updates/pref_updates.json +17 -0
- preditor/resource/settings.ini +25 -0
- preditor/resource/stylesheet/Bright.css +76 -0
- preditor/resource/stylesheet/Dark.css +210 -0
- preditor/scintilla/__init__.py +40 -0
- preditor/scintilla/delayables/__init__.py +11 -0
- preditor/scintilla/delayables/smart_highlight.py +97 -0
- preditor/scintilla/delayables/spell_check.py +174 -0
- preditor/scintilla/documenteditor.py +1924 -0
- preditor/scintilla/finddialog.py +68 -0
- preditor/scintilla/lang/__init__.py +80 -0
- preditor/scintilla/lang/config/bash.ini +15 -0
- preditor/scintilla/lang/config/batch.ini +14 -0
- preditor/scintilla/lang/config/cpp.ini +19 -0
- preditor/scintilla/lang/config/css.ini +19 -0
- preditor/scintilla/lang/config/eyeonscript.ini +17 -0
- preditor/scintilla/lang/config/html.ini +21 -0
- preditor/scintilla/lang/config/javascript.ini +24 -0
- preditor/scintilla/lang/config/lua.ini +16 -0
- preditor/scintilla/lang/config/maxscript.ini +20 -0
- preditor/scintilla/lang/config/mel.ini +18 -0
- preditor/scintilla/lang/config/mu.ini +22 -0
- preditor/scintilla/lang/config/nsi.ini +19 -0
- preditor/scintilla/lang/config/perl.ini +19 -0
- preditor/scintilla/lang/config/puppet.ini +19 -0
- preditor/scintilla/lang/config/python.ini +28 -0
- preditor/scintilla/lang/config/ruby.ini +19 -0
- preditor/scintilla/lang/config/sql.ini +7 -0
- preditor/scintilla/lang/config/xml.ini +21 -0
- preditor/scintilla/lang/config/yaml.ini +18 -0
- preditor/scintilla/lang/language.py +240 -0
- preditor/scintilla/lexers/__init__.py +0 -0
- preditor/scintilla/lexers/cpplexer.py +22 -0
- preditor/scintilla/lexers/javascriptlexer.py +27 -0
- preditor/scintilla/lexers/maxscriptlexer.py +235 -0
- preditor/scintilla/lexers/mellexer.py +369 -0
- preditor/scintilla/lexers/mulexer.py +33 -0
- preditor/scintilla/lexers/pythonlexer.py +42 -0
- preditor/scintilla/ui/finddialog.ui +160 -0
- preditor/settings.py +71 -0
- preditor/stream/__init__.py +72 -0
- preditor/stream/console_handler.py +169 -0
- preditor/stream/director.py +144 -0
- preditor/stream/manager.py +97 -0
- preditor/streamhandler_helper.py +46 -0
- preditor/utils/__init__.py +191 -0
- preditor/utils/call_stack.py +86 -0
- preditor/utils/cute.py +106 -0
- preditor/utils/stylesheets.py +54 -0
- preditor/utils/text_search.py +338 -0
- preditor/version.py +34 -0
- preditor/weakref.py +363 -0
- preditor-2.1.0.dist-info/METADATA +308 -0
- preditor-2.1.0.dist-info/RECORD +179 -0
- preditor-2.1.0.dist-info/WHEEL +5 -0
- preditor-2.1.0.dist-info/entry_points.txt +19 -0
- preditor-2.1.0.dist-info/licenses/LICENSE +165 -0
- preditor-2.1.0.dist-info/top_level.txt +3 -0
- tests/encodings/test_ecoding.py +33 -0
- tests/find_files/test_find_files.py +74 -0
- tests/ide/test_delayable_engine.py +171 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from Qt.QtGui import QFont, QFontMetrics, QTextCursor
|
|
6
|
+
from Qt.QtWidgets import QTextEdit
|
|
7
|
+
|
|
8
|
+
from .codehighlighter import CodeHighlighter
|
|
9
|
+
from .workbox_mixin import WorkboxMixin
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WorkboxTextEdit(WorkboxMixin, QTextEdit):
|
|
15
|
+
"""A very simple multi-line text editor without any bells and whistles.
|
|
16
|
+
|
|
17
|
+
It's better than nothing, but not by much.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
_warning_text = (
|
|
21
|
+
"This is a bare bones workbox, if you have another option, it's probably"
|
|
22
|
+
"a better option."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
console=None,
|
|
28
|
+
core_name=None,
|
|
29
|
+
delayable_engine='default',
|
|
30
|
+
parent=None,
|
|
31
|
+
**kwargs,
|
|
32
|
+
):
|
|
33
|
+
super(WorkboxTextEdit, self).__init__(
|
|
34
|
+
parent=parent, core_name=core_name, **kwargs
|
|
35
|
+
)
|
|
36
|
+
self.__set_console__(console)
|
|
37
|
+
self._encoding = None
|
|
38
|
+
highlight = CodeHighlighter(self, 'Python')
|
|
39
|
+
self.uiCodeHighlighter = highlight
|
|
40
|
+
|
|
41
|
+
def __auto_complete_enabled__(self):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def __set_auto_complete_enabled__(self, state):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
def __clear__(self):
|
|
48
|
+
self.clear()
|
|
49
|
+
self.__set_last_saved_text__(self.__text__())
|
|
50
|
+
|
|
51
|
+
def __copy_indents_as_spaces__(self):
|
|
52
|
+
"""When copying code, should it convert leading tabs to spaces?"""
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
def __set_copy_indents_as_spaces__(self, state):
|
|
56
|
+
logger.info(
|
|
57
|
+
"WorkboxTextEdit does not support converting indents to spaces on copy."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def __cursor_position__(self):
|
|
61
|
+
"""Returns the line and index of the cursor."""
|
|
62
|
+
cursor = self.textCursor()
|
|
63
|
+
sc = QTextCursor(self.document())
|
|
64
|
+
sc.setPosition(cursor.selectionStart())
|
|
65
|
+
return sc.blockNumber(), sc.positionInBlock()
|
|
66
|
+
|
|
67
|
+
def __font__(self):
|
|
68
|
+
return self.font()
|
|
69
|
+
|
|
70
|
+
def __set_font__(self, font):
|
|
71
|
+
metrics = QFontMetrics(font)
|
|
72
|
+
self.setTabStopDistance(metrics.horizontalAdvance(" ") * 4)
|
|
73
|
+
super(WorkboxTextEdit, self).setFont(font)
|
|
74
|
+
|
|
75
|
+
def __goto_line__(self, line):
|
|
76
|
+
cursor = QTextCursor(self.document().findBlockByLineNumber(line - 1))
|
|
77
|
+
self.setTextCursor(cursor)
|
|
78
|
+
|
|
79
|
+
def __indentations_use_tabs__(self):
|
|
80
|
+
return True
|
|
81
|
+
|
|
82
|
+
def __set_indentations_use_tabs__(self, state):
|
|
83
|
+
logger.info("WorkboxTextEdit does not support using spaces for tabs.")
|
|
84
|
+
|
|
85
|
+
def __margins_font__(self):
|
|
86
|
+
return QFont()
|
|
87
|
+
|
|
88
|
+
def __set_margins_font__(self, font):
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
def __tab_width__(self):
|
|
92
|
+
# TODO: Implement custom tab widths
|
|
93
|
+
return 4
|
|
94
|
+
|
|
95
|
+
def __text__(self):
|
|
96
|
+
"""Returns the text in this widget
|
|
97
|
+
Returns:
|
|
98
|
+
str: Returns the text in this widget
|
|
99
|
+
"""
|
|
100
|
+
return self.toPlainText()
|
|
101
|
+
|
|
102
|
+
def __selected_text__(self, start_of_line=False, selectText=False):
|
|
103
|
+
cursor = self.textCursor()
|
|
104
|
+
|
|
105
|
+
# Get starting line number. Must set the cursor's position to the start of the
|
|
106
|
+
# selection, otherwise we may instead get the ending line number.
|
|
107
|
+
tempCursor = self.textCursor()
|
|
108
|
+
tempCursor.setPosition(tempCursor.selectionStart())
|
|
109
|
+
line = tempCursor.block().firstLineNumber()
|
|
110
|
+
|
|
111
|
+
# If no selection, return the current line
|
|
112
|
+
if cursor.selection().isEmpty():
|
|
113
|
+
text = cursor.block().text()
|
|
114
|
+
|
|
115
|
+
if selectText:
|
|
116
|
+
cursor.select(QTextCursor.SelectionType.LineUnderCursor)
|
|
117
|
+
self.setTextCursor(cursor)
|
|
118
|
+
|
|
119
|
+
return text, line
|
|
120
|
+
|
|
121
|
+
# Otherwise return the selected text
|
|
122
|
+
if start_of_line:
|
|
123
|
+
sc = QTextCursor(self.document())
|
|
124
|
+
sc.setPosition(cursor.selectionStart())
|
|
125
|
+
sc.movePosition(cursor.StartOfLine, sc.MoveAnchor)
|
|
126
|
+
sc.setPosition(cursor.selectionEnd(), sc.KeepAnchor)
|
|
127
|
+
|
|
128
|
+
return sc.selection().toPlainText(), line
|
|
129
|
+
|
|
130
|
+
return self.textCursor().selection().toPlainText(), line
|
|
131
|
+
|
|
132
|
+
def keyPressEvent(self, event):
|
|
133
|
+
if self.process_shortcut(event):
|
|
134
|
+
return
|
|
135
|
+
else:
|
|
136
|
+
super(WorkboxTextEdit, self).keyPressEvent(event)
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
from __future__ import absolute_import, print_function
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from Qt.QtCore import QEvent, Qt
|
|
8
|
+
from Qt.QtGui import QIcon
|
|
9
|
+
from Qt.QtWidgets import QAction, QMessageBox
|
|
10
|
+
|
|
11
|
+
from .. import core, resourcePath
|
|
12
|
+
from ..gui.workbox_mixin import WorkboxMixin
|
|
13
|
+
from ..scintilla import QsciScintilla
|
|
14
|
+
from ..scintilla.documenteditor import DocumentEditor, SearchOptions
|
|
15
|
+
from ..scintilla.finddialog import FindDialog
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
parent=None,
|
|
22
|
+
console=None,
|
|
23
|
+
delayable_engine='default',
|
|
24
|
+
core_name=None,
|
|
25
|
+
**kwargs,
|
|
26
|
+
):
|
|
27
|
+
self.__set_console__(console)
|
|
28
|
+
self._searchFlags = 0
|
|
29
|
+
self._searchText = ''
|
|
30
|
+
self._searchDialog = None
|
|
31
|
+
|
|
32
|
+
# initialize the super class
|
|
33
|
+
super(WorkboxWidget, self).__init__(
|
|
34
|
+
parent, delayable_engine=delayable_engine, core_name=core_name, **kwargs
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Store the software name so we can handle custom keyboard shortcuts based on
|
|
38
|
+
# software
|
|
39
|
+
self._software = core.objectName()
|
|
40
|
+
# Used to remove any trailing whitespace when running selected text
|
|
41
|
+
self.regex = re.compile(r'\s+$')
|
|
42
|
+
self.initShortcuts()
|
|
43
|
+
|
|
44
|
+
self._defaultLanguage = "Python"
|
|
45
|
+
self.setLanguage(self._defaultLanguage)
|
|
46
|
+
# Default to unix newlines
|
|
47
|
+
self.setEolMode(QsciScintilla.EolMode.EolUnix)
|
|
48
|
+
if hasattr(self.window(), "setWorkboxFontBasedOnConsole"):
|
|
49
|
+
self.window().setWorkboxFontBasedOnConsole()
|
|
50
|
+
|
|
51
|
+
def __auto_complete_enabled__(self):
|
|
52
|
+
return self.autoCompletionSource() == QsciScintilla.AutoCompletionSource.AcsAll
|
|
53
|
+
|
|
54
|
+
def __set_auto_complete_enabled__(self, state):
|
|
55
|
+
state = (
|
|
56
|
+
QsciScintilla.AutoCompletionSource.AcsAll
|
|
57
|
+
if state
|
|
58
|
+
else QsciScintilla.AutoCompletionSource.AcsNone
|
|
59
|
+
)
|
|
60
|
+
self.setAutoCompletionSource(state)
|
|
61
|
+
|
|
62
|
+
def __clear__(self):
|
|
63
|
+
self.clear()
|
|
64
|
+
self.__set_last_saved_text__(self.__text__())
|
|
65
|
+
|
|
66
|
+
def __comment_toggle__(self):
|
|
67
|
+
self.commentToggle()
|
|
68
|
+
|
|
69
|
+
def __copy_indents_as_spaces__(self):
|
|
70
|
+
return self.copyIndentsAsSpaces
|
|
71
|
+
|
|
72
|
+
def __set_copy_indents_as_spaces__(self, state):
|
|
73
|
+
self.copyIndentsAsSpaces = state
|
|
74
|
+
|
|
75
|
+
def __cursor_position__(self):
|
|
76
|
+
"""Returns the line and index of the cursor."""
|
|
77
|
+
return self.getCursorPosition()
|
|
78
|
+
|
|
79
|
+
def __set_cursor_position__(self, line, index):
|
|
80
|
+
"""Set the cursor to this line number and index"""
|
|
81
|
+
self.setCursorPosition(line, index)
|
|
82
|
+
|
|
83
|
+
def __check_for_save__(self):
|
|
84
|
+
if self.isModified():
|
|
85
|
+
result = QMessageBox.question(
|
|
86
|
+
self.window(),
|
|
87
|
+
'Save changes to...',
|
|
88
|
+
'Do you want to save your changes?',
|
|
89
|
+
QMessageBox.StandardButton.Yes
|
|
90
|
+
| QMessageBox.StandardButton.No
|
|
91
|
+
| QMessageBox.StandardButton.Cancel,
|
|
92
|
+
)
|
|
93
|
+
if result == QMessageBox.StandardButton.Yes:
|
|
94
|
+
return self.save()
|
|
95
|
+
elif result == QMessageBox.StandardButton.Cancel:
|
|
96
|
+
return False
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
def eventFilter(self, object, event):
|
|
100
|
+
if event.type() == QEvent.Type.Close and not self.__check_for_save__():
|
|
101
|
+
event.ignore()
|
|
102
|
+
return True
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
def execStandalone(self):
|
|
106
|
+
if self.__save__():
|
|
107
|
+
os.startfile(str(self.filename()))
|
|
108
|
+
|
|
109
|
+
def __filename__(self):
|
|
110
|
+
return self.filename()
|
|
111
|
+
|
|
112
|
+
def __set_filename__(self, filename):
|
|
113
|
+
self.set_filename(filename)
|
|
114
|
+
|
|
115
|
+
def __font__(self):
|
|
116
|
+
if self.lexer():
|
|
117
|
+
return self.lexer().font(0)
|
|
118
|
+
else:
|
|
119
|
+
return self.font()
|
|
120
|
+
|
|
121
|
+
def __set_font__(self, font):
|
|
122
|
+
self.documentFont = font
|
|
123
|
+
if self.lexer():
|
|
124
|
+
self.lexer().setFont(font)
|
|
125
|
+
else:
|
|
126
|
+
self.setFont(font)
|
|
127
|
+
|
|
128
|
+
def __goto_line__(self, line):
|
|
129
|
+
self.goToLine(line)
|
|
130
|
+
|
|
131
|
+
def __indentations_use_tabs__(self):
|
|
132
|
+
return self.indentationsUseTabs()
|
|
133
|
+
|
|
134
|
+
def __set_indentations_use_tabs__(self, state):
|
|
135
|
+
self.setIndentationsUseTabs(state)
|
|
136
|
+
|
|
137
|
+
def __insert_text__(self, txt):
|
|
138
|
+
self.insert(txt)
|
|
139
|
+
|
|
140
|
+
def __load__(self, filename):
|
|
141
|
+
if filename and Path(filename).is_file():
|
|
142
|
+
# This is overriding WorkboxMixin.__load__, make sure to base class
|
|
143
|
+
# method.
|
|
144
|
+
super().__load__(filename)
|
|
145
|
+
|
|
146
|
+
# DocumentEditor specific calls
|
|
147
|
+
font = self.__font__()
|
|
148
|
+
self.updateFilename(str(filename))
|
|
149
|
+
self.__set_font__(font)
|
|
150
|
+
self.setEolMode(self.detectEndLine(self.__text__()))
|
|
151
|
+
|
|
152
|
+
def __save__(self):
|
|
153
|
+
font = self.__font__()
|
|
154
|
+
super().__save__()
|
|
155
|
+
filename = self.__filename__()
|
|
156
|
+
if filename:
|
|
157
|
+
self.updateFilename(filename)
|
|
158
|
+
self.__set_font__(font)
|
|
159
|
+
|
|
160
|
+
def __margins_font__(self):
|
|
161
|
+
return self.marginsFont()
|
|
162
|
+
|
|
163
|
+
def __set_margins_font__(self, font):
|
|
164
|
+
self.setMarginsFont(font)
|
|
165
|
+
|
|
166
|
+
def __marker_add__(self, line):
|
|
167
|
+
try:
|
|
168
|
+
marker = self._marker
|
|
169
|
+
except AttributeError:
|
|
170
|
+
self._marker = self.markerDefine(QsciScintilla.MarkerSymbol.Circle)
|
|
171
|
+
marker = self._marker
|
|
172
|
+
self.markerAdd(line, marker)
|
|
173
|
+
|
|
174
|
+
def __marker_clear_all__(self):
|
|
175
|
+
try:
|
|
176
|
+
self.markerDeleteAll(self._marker)
|
|
177
|
+
except AttributeError:
|
|
178
|
+
# self._marker has not been created yet
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
def __remove_selected_text__(self):
|
|
182
|
+
self.removeSelectedText()
|
|
183
|
+
|
|
184
|
+
def __selected_text__(self, start_of_line=False, selectText=False):
|
|
185
|
+
line, s, end, e = self.getSelection()
|
|
186
|
+
|
|
187
|
+
# Sometime self.getSelection returns values that equate to a non-existent
|
|
188
|
+
# selection, ie start and end are the same, so let's process it as if there is
|
|
189
|
+
# no selection
|
|
190
|
+
selectionIsEmpty = line == end and s == e
|
|
191
|
+
if line == -1 or selectionIsEmpty:
|
|
192
|
+
# Nothing is selected, return the current line of text
|
|
193
|
+
line, index = self.getCursorPosition()
|
|
194
|
+
txt = self.__text_part__(lineNum=line)
|
|
195
|
+
|
|
196
|
+
if selectText:
|
|
197
|
+
lineLength = len(txt.rstrip())
|
|
198
|
+
self.setSelection(line, 0, line, lineLength)
|
|
199
|
+
|
|
200
|
+
elif start_of_line:
|
|
201
|
+
ss = self.positionFromLineIndex(line, 0)
|
|
202
|
+
ee = self.positionFromLineIndex(end, e)
|
|
203
|
+
txt = self.__text_part__(start=ss, end=ee)
|
|
204
|
+
else:
|
|
205
|
+
txt = self.selectedText()
|
|
206
|
+
return self.regex.split(txt)[0], line
|
|
207
|
+
|
|
208
|
+
def __tab_width__(self):
|
|
209
|
+
return self.tabWidth()
|
|
210
|
+
|
|
211
|
+
def __set_tab_width__(self, width):
|
|
212
|
+
self.setTabWidth(width)
|
|
213
|
+
|
|
214
|
+
def __text__(self):
|
|
215
|
+
"""Returns the text in this widget
|
|
216
|
+
Returns:
|
|
217
|
+
str: Returns the text in this widget
|
|
218
|
+
"""
|
|
219
|
+
return self.text()
|
|
220
|
+
|
|
221
|
+
def keyPressEvent(self, event):
|
|
222
|
+
"""Check for certain keyboard shortcuts, and handle them as needed,
|
|
223
|
+
otherwise pass the keyPress to the superclass.
|
|
224
|
+
|
|
225
|
+
NOTE! We handle the "shift+return" shortcut here, rather than the
|
|
226
|
+
QAction's shortcut, because the workbox will always intercept that
|
|
227
|
+
shortcut. So, we handle it here, and call the main window's
|
|
228
|
+
execSelected, which ultimately calls this workbox's __exec_selected__.
|
|
229
|
+
|
|
230
|
+
Also note, it would make sense to have ctrl+Enter also execute without
|
|
231
|
+
truncation, but no modifiers are registered when Enter is pressed (unlike
|
|
232
|
+
when Return is pressed), so this combination is not detectable.
|
|
233
|
+
"""
|
|
234
|
+
tab_widget = self.__tab_widget__()
|
|
235
|
+
if tab_widget is not None:
|
|
236
|
+
tab_widget.tabBar().update()
|
|
237
|
+
|
|
238
|
+
if self.process_shortcut(event):
|
|
239
|
+
return
|
|
240
|
+
else:
|
|
241
|
+
# Send regular keystroke
|
|
242
|
+
super(WorkboxWidget, self).keyPressEvent(event)
|
|
243
|
+
|
|
244
|
+
def initShortcuts(self):
|
|
245
|
+
"""Use this to set up shortcuts when the DocumentEditor"""
|
|
246
|
+
icon = QIcon(resourcePath('img/text-search-variant.png'))
|
|
247
|
+
self.uiFindACT = QAction(icon, 'Find...', self)
|
|
248
|
+
self.uiFindACT.setShortcut("Ctrl+F")
|
|
249
|
+
self.addAction(self.uiFindACT)
|
|
250
|
+
|
|
251
|
+
icon = QIcon(resourcePath('img/skip-previous.png'))
|
|
252
|
+
self.uiFindPrevACT = QAction(icon, 'Find Prev', self)
|
|
253
|
+
self.uiFindPrevACT.setShortcut("Ctrl+F3")
|
|
254
|
+
self.addAction(self.uiFindPrevACT)
|
|
255
|
+
|
|
256
|
+
icon = QIcon(resourcePath('img/skip-next.png'))
|
|
257
|
+
self.uiFindNextACT = QAction(icon, 'Find Next', self)
|
|
258
|
+
self.uiFindNextACT.setShortcut("F3")
|
|
259
|
+
self.addAction(self.uiFindNextACT)
|
|
260
|
+
|
|
261
|
+
self.uiSelectCurrentLineACT = QAction(icon, 'Select Line', self)
|
|
262
|
+
self.uiSelectCurrentLineACT.triggered.connect(self.expandCursorToLineSelection)
|
|
263
|
+
self.uiSelectCurrentLineACT.setShortcut('Ctrl+L')
|
|
264
|
+
self.addAction(self.uiSelectCurrentLineACT)
|
|
265
|
+
|
|
266
|
+
# create the search dialog and connect actions
|
|
267
|
+
self._searchDialog = FindDialog(self)
|
|
268
|
+
self._searchDialog.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False)
|
|
269
|
+
self.uiFindACT.triggered.connect(
|
|
270
|
+
lambda: self._searchDialog.search(self.searchText())
|
|
271
|
+
)
|
|
272
|
+
self.uiFindPrevACT.triggered.connect(
|
|
273
|
+
lambda: self.findPrev(self.searchText(), self.searchFlags())
|
|
274
|
+
)
|
|
275
|
+
self.uiFindNextACT.triggered.connect(
|
|
276
|
+
lambda: self.findNext(self.searchText(), self.searchFlags())
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
def searchFlags(self):
|
|
280
|
+
return self._searchFlags
|
|
281
|
+
|
|
282
|
+
def searchText(self):
|
|
283
|
+
if not self._searchDialog:
|
|
284
|
+
return ''
|
|
285
|
+
# refresh the search text unless we are using regular expressions
|
|
286
|
+
if (
|
|
287
|
+
not self._searchDialog.isVisible()
|
|
288
|
+
and not self._searchFlags & SearchOptions.QRegExp
|
|
289
|
+
):
|
|
290
|
+
txt = self.selectedText()
|
|
291
|
+
if txt:
|
|
292
|
+
self._searchText = txt
|
|
293
|
+
return self._searchText
|
|
294
|
+
|
|
295
|
+
def setSearchFlags(self, flags):
|
|
296
|
+
self._searchFlags = flags
|
|
297
|
+
|
|
298
|
+
def setSearchText(self, txt):
|
|
299
|
+
self._searchText = txt
|
|
300
|
+
|
|
301
|
+
def showMenu(self, pos):
|
|
302
|
+
menu = super(WorkboxWidget, self).showMenu(pos, popup=False)
|
|
303
|
+
menu.addSeparator()
|
|
304
|
+
submenu = menu.addMenu('Options')
|
|
305
|
+
act = submenu.addAction('Toggle end line visibility')
|
|
306
|
+
act.setCheckable(True)
|
|
307
|
+
act.setChecked(self.eolVisibility())
|
|
308
|
+
act.triggered.connect(self.setEolVisibility)
|
|
309
|
+
|
|
310
|
+
act = submenu.addAction('Show Whitespace')
|
|
311
|
+
act.setCheckable(True)
|
|
312
|
+
act.setChecked(self.showWhitespaces())
|
|
313
|
+
act.triggered.connect(self.setShowWhitespaces)
|
|
314
|
+
|
|
315
|
+
menu.popup(self._clickPos)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import logging.config
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
from . import utils
|
|
9
|
+
from .prefs import prefs_path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LoggingConfig(object):
|
|
13
|
+
def __init__(self, core_name, version=1, disable_existing_loggers=False):
|
|
14
|
+
self._filename = None
|
|
15
|
+
self.cfg = {
|
|
16
|
+
'version': version,
|
|
17
|
+
'disable_existing_loggers': disable_existing_loggers,
|
|
18
|
+
}
|
|
19
|
+
self.core_name = core_name
|
|
20
|
+
|
|
21
|
+
def add_logger(self, name, logger):
|
|
22
|
+
if not logger.level:
|
|
23
|
+
# No need to record a logger that is inheriting its logging level
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
# Build the required dictionaries
|
|
27
|
+
loggers = self.cfg.setdefault('loggers', {})
|
|
28
|
+
log = loggers.setdefault(name, {})
|
|
29
|
+
log['level'] = logger.level
|
|
30
|
+
|
|
31
|
+
def build(self):
|
|
32
|
+
self.add_logger("", logging.root)
|
|
33
|
+
for name, logger in logging.root.manager.loggerDict.items():
|
|
34
|
+
if not isinstance(logger, logging.PlaceHolder):
|
|
35
|
+
self.add_logger(name, logger)
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def filename(self):
|
|
39
|
+
if self._filename:
|
|
40
|
+
return self._filename
|
|
41
|
+
|
|
42
|
+
self._filename = prefs_path('logging_prefs.json', core_name=self.core_name)
|
|
43
|
+
return self._filename
|
|
44
|
+
|
|
45
|
+
def load(self):
|
|
46
|
+
if not os.path.exists(self.filename):
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
self.cfg = utils.Json(self.filename).load()
|
|
50
|
+
logging.config.dictConfig(self.cfg)
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
def save(self):
|
|
54
|
+
with open(self.filename, 'w') as fle:
|
|
55
|
+
json.dump(self.cfg, fle, indent=4)
|