PrEditor 0.0.0.dev1__py2.py3-none-any.whl → 0.1.0__py2.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-0.1.0.dist-info/LICENSE +165 -0
- PrEditor-0.1.0.dist-info/METADATA +212 -0
- PrEditor-0.1.0.dist-info/RECORD +149 -0
- {PrEditor-0.0.0.dev1.dist-info → PrEditor-0.1.0.dist-info}/WHEEL +1 -1
- PrEditor-0.1.0.dist-info/entry_points.txt +18 -0
- PrEditor-0.1.0.dist-info/top_level.txt +1 -0
- preditor/__init__.py +301 -0
- {blurdev → preditor}/__main__.py +13 -13
- preditor/about_module.py +166 -0
- preditor/cli.py +192 -0
- {blurdev → preditor}/contexts.py +119 -119
- preditor/cores/core.py +65 -0
- preditor/dccs/maya/PrEditor_maya.mod +2 -0
- preditor/dccs/maya/plug-ins/PrEditor_maya.py +108 -0
- preditor/debug.py +294 -0
- blurdev/scintilla/delayable_engine.py → preditor/delayable_engine/__init__.py +310 -299
- blurdev/scintilla/delayables/base.py → preditor/delayable_engine/delayables.py +85 -85
- {blurdev → preditor}/enum.py +728 -1003
- {blurdev → preditor}/gui/__init__.py +84 -125
- preditor/gui/app.py +159 -0
- {blurdev → preditor}/gui/codehighlighter.py +209 -219
- {blurdev → preditor}/gui/completer.py +226 -236
- {blurdev → preditor}/gui/console.py +801 -858
- {blurdev → preditor}/gui/dialog.py +200 -216
- preditor/gui/drag_tab_bar.py +190 -0
- preditor/gui/editor_chooser.py +57 -0
- {blurdev → preditor}/gui/errordialog.py +100 -97
- preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
- preditor/gui/group_tab_widget/__init__.py +319 -0
- preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
- preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
- preditor/gui/group_tab_widget/grouped_tab_widget.py +75 -0
- preditor/gui/group_tab_widget/one_tab_widget.py +54 -0
- preditor/gui/level_buttons.py +349 -0
- {blurdev → preditor}/gui/logger_window_handler.py +46 -45
- {blurdev → preditor}/gui/loggerwindow.py +1205 -1417
- {blurdev → preditor}/gui/newtabwidget.py +69 -68
- {blurdev → preditor}/gui/redmine_login_dialog.py +63 -61
- {blurdev → preditor}/gui/set_text_editor_path_dialog.py +59 -57
- preditor/gui/ui/editor_chooser.ui +93 -0
- {blurdev → preditor}/gui/ui/errordialog.ui +81 -81
- {blurdev → preditor}/gui/ui/loggerwindow.ui +1030 -864
- {blurdev → preditor}/gui/ui/redmine_login_dialog.ui +124 -124
- {blurdev → preditor}/gui/ui/set_text_editor_path_dialog.ui +149 -149
- {blurdev → preditor}/gui/window.py +183 -199
- preditor/gui/workbox_mixin.py +357 -0
- preditor/gui/workbox_text_edit.py +117 -0
- preditor/gui/workboxwidget.py +276 -0
- preditor/logging_config.py +52 -0
- preditor/osystem.py +401 -0
- preditor/plugins.py +65 -0
- preditor/prefs.py +74 -0
- {blurdev → preditor}/resource/environment_variables.html +26 -38
- {blurdev → preditor}/resource/error_mail.html +85 -85
- {blurdev → preditor}/resource/error_mail_inline.html +41 -41
- preditor/resource/img/README.md +7 -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/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/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
- {blurdev → preditor}/resource/lang/python.json +30 -30
- preditor/resource/settings.ini +25 -0
- {blurdev/resource/stylesheet/logger → preditor/resource/stylesheet}/Bright.css +56 -61
- {blurdev → preditor}/resource/stylesheet/Dark.css +190 -132
- {blurdev → preditor}/scintilla/__init__.py +22 -28
- preditor/scintilla/delayables/__init__.py +11 -0
- {blurdev → preditor}/scintilla/delayables/smart_highlight.py +94 -93
- {blurdev → preditor}/scintilla/delayables/spell_check.py +173 -172
- {blurdev → preditor}/scintilla/documenteditor.py +2039 -2115
- {blurdev → preditor}/scintilla/finddialog.py +68 -81
- {blurdev → preditor}/scintilla/lang/__init__.py +80 -93
- {blurdev → preditor}/scintilla/lang/config/bash.ini +15 -15
- {blurdev → preditor}/scintilla/lang/config/batch.ini +14 -14
- {blurdev → preditor}/scintilla/lang/config/cpp.ini +19 -19
- {blurdev → preditor}/scintilla/lang/config/css.ini +19 -19
- {blurdev → preditor}/scintilla/lang/config/eyeonscript.ini +17 -17
- {blurdev → preditor}/scintilla/lang/config/html.ini +21 -21
- {blurdev → preditor}/scintilla/lang/config/javascript.ini +24 -24
- {blurdev → preditor}/scintilla/lang/config/lua.ini +16 -16
- {blurdev → preditor}/scintilla/lang/config/maxscript.ini +20 -20
- {blurdev → preditor}/scintilla/lang/config/mel.ini +18 -18
- {blurdev → preditor}/scintilla/lang/config/mu.ini +22 -22
- {blurdev → preditor}/scintilla/lang/config/nsi.ini +5 -5
- {blurdev → preditor}/scintilla/lang/config/perl.ini +19 -19
- {blurdev → preditor}/scintilla/lang/config/puppet.ini +19 -19
- {blurdev → preditor}/scintilla/lang/config/python.ini +28 -28
- {blurdev → preditor}/scintilla/lang/config/ruby.ini +19 -19
- {blurdev → preditor}/scintilla/lang/config/sql.ini +7 -7
- {blurdev → preditor}/scintilla/lang/config/xml.ini +21 -21
- {blurdev → preditor}/scintilla/lang/config/yaml.ini +18 -18
- {blurdev → preditor}/scintilla/lang/language.py +240 -250
- preditor/scintilla/lexers/__init__.py +0 -0
- {blurdev → preditor}/scintilla/lexers/cpplexer.py +21 -30
- {blurdev → preditor}/scintilla/lexers/javascriptlexer.py +25 -34
- {blurdev → preditor}/scintilla/lexers/maxscriptlexer.py +234 -253
- {blurdev → preditor}/scintilla/lexers/mellexer.py +368 -376
- {blurdev → preditor}/scintilla/lexers/mulexer.py +32 -41
- {blurdev → preditor}/scintilla/lexers/pythonlexer.py +41 -50
- {blurdev → preditor}/scintilla/ui/finddialog.ui +160 -160
- preditor/settings.py +71 -0
- preditor/stream/__init__.py +80 -0
- preditor/stream/director.py +56 -0
- preditor/stream/manager.py +74 -0
- preditor/streamhandler_helper.py +46 -0
- preditor/utils/__init__.py +0 -0
- preditor/utils/cute.py +30 -0
- preditor/utils/stylesheets.py +54 -0
- {blurdev → preditor}/version.py +5 -5
- preditor/weakref.py +363 -0
- PrEditor-0.0.0.dev1.dist-info/METADATA +0 -51
- PrEditor-0.0.0.dev1.dist-info/RECORD +0 -279
- PrEditor-0.0.0.dev1.dist-info/top_level.txt +0 -1
- blurdev/__init__.py +0 -356
- blurdev/cores/__init__.py +0 -98
- blurdev/cores/application.py +0 -26
- blurdev/cores/core.py +0 -634
- blurdev/debug.py +0 -593
- blurdev/external.py +0 -391
- blurdev/gui/level_buttons.py +0 -585
- blurdev/gui/workboxwidget.py +0 -205
- blurdev/logger.py +0 -238
- blurdev/osystem.py +0 -813
- blurdev/prefs.py +0 -33
- blurdev/protocols/__init__.py +0 -71
- blurdev/protocols/write_std_output_handler.py +0 -83
- blurdev/resource/designer_plugins.xml +0 -9
- blurdev/resource/error_email_old.html +0 -41
- blurdev/resource/img/add.png +0 -0
- blurdev/resource/img/ajax-loader.gif +0 -0
- blurdev/resource/img/application.png +0 -0
- blurdev/resource/img/applications.png +0 -0
- blurdev/resource/img/assburner.png +0 -0
- blurdev/resource/img/assfreezer.png +0 -0
- blurdev/resource/img/bar.gif +0 -0
- blurdev/resource/img/blank.png +0 -0
- blurdev/resource/img/blurdev.png +0 -0
- blurdev/resource/img/calendar_disabled.png +0 -0
- blurdev/resource/img/calendar_enabled.png +0 -0
- blurdev/resource/img/cancel.png +0 -0
- blurdev/resource/img/custom.png +0 -0
- blurdev/resource/img/debug_high.png +0 -0
- blurdev/resource/img/debug_low.png +0 -0
- blurdev/resource/img/debug_mid.png +0 -0
- blurdev/resource/img/debug_off.png +0 -0
- blurdev/resource/img/django.png +0 -0
- blurdev/resource/img/doc.png +0 -0
- blurdev/resource/img/edit.png +0 -0
- blurdev/resource/img/elemental.png +0 -0
- blurdev/resource/img/explore.png +0 -0
- blurdev/resource/img/favorite.png +0 -0
- blurdev/resource/img/file.png +0 -0
- blurdev/resource/img/folder.png +0 -0
- blurdev/resource/img/ide/add.png +0 -0
- blurdev/resource/img/ide/add_note.png +0 -0
- blurdev/resource/img/ide/arrow_down.png +0 -0
- blurdev/resource/img/ide/arrow_up.png +0 -0
- blurdev/resource/img/ide/check.png +0 -0
- blurdev/resource/img/ide/class.png +0 -0
- blurdev/resource/img/ide/clean.png +0 -0
- blurdev/resource/img/ide/clearlog.png +0 -0
- blurdev/resource/img/ide/close.png +0 -0
- blurdev/resource/img/ide/comment_add.png +0 -0
- blurdev/resource/img/ide/comment_remove.png +0 -0
- blurdev/resource/img/ide/comment_toggle.png +0 -0
- blurdev/resource/img/ide/console.png +0 -0
- blurdev/resource/img/ide/copy.png +0 -0
- blurdev/resource/img/ide/copylstrip.png +0 -0
- blurdev/resource/img/ide/cut.png +0 -0
- blurdev/resource/img/ide/edit.png +0 -0
- blurdev/resource/img/ide/find.png +0 -0
- blurdev/resource/img/ide/find_replace.png +0 -0
- blurdev/resource/img/ide/findnext.png +0 -0
- blurdev/resource/img/ide/findprev.png +0 -0
- blurdev/resource/img/ide/folder_find.png +0 -0
- blurdev/resource/img/ide/function.png +0 -0
- blurdev/resource/img/ide/git-bash.png +0 -0
- blurdev/resource/img/ide/git-gui.png +0 -0
- blurdev/resource/img/ide/gitk.png +0 -0
- blurdev/resource/img/ide/goto.png +0 -0
- blurdev/resource/img/ide/goto_def.png +0 -0
- blurdev/resource/img/ide/help.png +0 -0
- blurdev/resource/img/ide/highlighter.png +0 -0
- blurdev/resource/img/ide/lowercase.png +0 -0
- blurdev/resource/img/ide/newfile.png +0 -0
- blurdev/resource/img/ide/newfolder.png +0 -0
- blurdev/resource/img/ide/newproject.png +0 -0
- blurdev/resource/img/ide/newwizard.png +0 -0
- blurdev/resource/img/ide/open.png +0 -0
- blurdev/resource/img/ide/paste.png +0 -0
- blurdev/resource/img/ide/pdb_continue.png +0 -0
- blurdev/resource/img/ide/pdb_down.png +0 -0
- blurdev/resource/img/ide/pdb_next.png +0 -0
- blurdev/resource/img/ide/pdb_step.png +0 -0
- blurdev/resource/img/ide/pdb_up.png +0 -0
- blurdev/resource/img/ide/plus_minus.png +0 -0
- blurdev/resource/img/ide/preferences.png +0 -0
- blurdev/resource/img/ide/project_find.png +0 -0
- blurdev/resource/img/ide/python.png +0 -0
- blurdev/resource/img/ide/pyular.png +0 -0
- blurdev/resource/img/ide/qt.png +0 -0
- blurdev/resource/img/ide/quit.png +0 -0
- blurdev/resource/img/ide/redo.png +0 -0
- blurdev/resource/img/ide/refresh.png +0 -0
- blurdev/resource/img/ide/remove.png +0 -0
- blurdev/resource/img/ide/ruler.png +0 -0
- blurdev/resource/img/ide/run.png +0 -0
- blurdev/resource/img/ide/runall.png +0 -0
- blurdev/resource/img/ide/runallclear.png +0 -0
- blurdev/resource/img/ide/runselected.png +0 -0
- blurdev/resource/img/ide/runselectedclear.png +0 -0
- blurdev/resource/img/ide/save.png +0 -0
- blurdev/resource/img/ide/saveas.png +0 -0
- blurdev/resource/img/ide/sdk.png +0 -0
- blurdev/resource/img/ide/separator.png +0 -0
- blurdev/resource/img/ide/tabbed.png +0 -0
- blurdev/resource/img/ide/tile.png +0 -0
- blurdev/resource/img/ide/toolbar.png +0 -0
- blurdev/resource/img/ide/undo.png +0 -0
- blurdev/resource/img/ide/uppercase.png +0 -0
- blurdev/resource/img/ide/view_as.png +0 -0
- blurdev/resource/img/ide/windowed.png +0 -0
- blurdev/resource/img/ide.ico +0 -0
- blurdev/resource/img/ide.png +0 -0
- blurdev/resource/img/ide48.png +0 -0
- blurdev/resource/img/info.png +0 -0
- blurdev/resource/img/legacy tool.png +0 -0
- blurdev/resource/img/library.png +0 -0
- blurdev/resource/img/logger/about.png +0 -0
- blurdev/resource/img/logger/arrow_forward.png +0 -0
- blurdev/resource/img/logger/clear.png +0 -0
- blurdev/resource/img/logger/close.png +0 -0
- blurdev/resource/img/logger/debug_disabled.png +0 -0
- blurdev/resource/img/logger/debug_high.png +0 -0
- blurdev/resource/img/logger/debug_low.png +0 -0
- blurdev/resource/img/logger/debug_mid.png +0 -0
- blurdev/resource/img/logger/down.png +0 -0
- blurdev/resource/img/logger/find.png +0 -0
- blurdev/resource/img/logger/logging_critical.png +0 -0
- blurdev/resource/img/logger/logging_debug.png +0 -0
- blurdev/resource/img/logger/logging_error.png +0 -0
- blurdev/resource/img/logger/logging_info.png +0 -0
- blurdev/resource/img/logger/logging_not_set.png +0 -0
- blurdev/resource/img/logger/logging_warning.png +0 -0
- blurdev/resource/img/logger/next.png +0 -0
- blurdev/resource/img/logger/play.png +0 -0
- blurdev/resource/img/logger/playlist_play.png +0 -0
- blurdev/resource/img/logger/previous.png +0 -0
- blurdev/resource/img/logger/return.png +0 -0
- blurdev/resource/img/logger/save.png +0 -0
- blurdev/resource/img/logger/subdirectory_arrow_right.png +0 -0
- blurdev/resource/img/logger/up.png +0 -0
- blurdev/resource/img/lovebar.png +0 -0
- blurdev/resource/img/new.png +0 -0
- blurdev/resource/img/new_selected.png +0 -0
- blurdev/resource/img/node.png +0 -0
- blurdev/resource/img/ok.png +0 -0
- blurdev/resource/img/options.png +0 -0
- blurdev/resource/img/packages.png +0 -0
- blurdev/resource/img/preview/add.png +0 -0
- blurdev/resource/img/preview/brush.png +0 -0
- blurdev/resource/img/preview/delete.png +0 -0
- blurdev/resource/img/preview/delte.png +0 -0
- blurdev/resource/img/preview/fill.png +0 -0
- blurdev/resource/img/preview/layers.png +0 -0
- blurdev/resource/img/preview/media.png +0 -0
- blurdev/resource/img/preview/navigate.png +0 -0
- blurdev/resource/img/preview/pencil.png +0 -0
- blurdev/resource/img/preview/select.png +0 -0
- blurdev/resource/img/preview/type.png +0 -0
- blurdev/resource/img/preview/visible.png +0 -0
- blurdev/resource/img/project.png +0 -0
- blurdev/resource/img/python_logger.ico +0 -0
- blurdev/resource/img/python_logger.png +0 -0
- blurdev/resource/img/refresh.png +0 -0
- blurdev/resource/img/remove.png +0 -0
- blurdev/resource/img/reset.png +0 -0
- blurdev/resource/img/richtext/font_bold.png +0 -0
- blurdev/resource/img/richtext/font_italic.png +0 -0
- blurdev/resource/img/richtext/link_image.png +0 -0
- blurdev/resource/img/richtext/spell_check.png +0 -0
- blurdev/resource/img/richtext/unordered_list.png +0 -0
- blurdev/resource/img/save.png +0 -0
- blurdev/resource/img/savesettings.png +0 -0
- blurdev/resource/img/settings.png +0 -0
- blurdev/resource/img/tool.png +0 -0
- blurdev/resource/img/toolbarHandleHorizontal.png +0 -0
- blurdev/resource/img/toolbarHandleVertical.png +0 -0
- blurdev/resource/img/trash.png +0 -0
- blurdev/resource/img/trax.png +0 -0
- blurdev/resource/img/tree.png +0 -0
- blurdev/resource/img/treegrunt.ico +0 -0
- blurdev/resource/img/treegrunt.png +0 -0
- blurdev/resource/img/treegruntedit.png +0 -0
- blurdev/resource/img/user interface.png +0 -0
- blurdev/resource/img/warning.png +0 -0
- blurdev/resource/img/watermark.png +0 -0
- blurdev/resource/sdk/blurdev.sdk +0 -3
- blurdev/resource/settings.ini +0 -82
- blurdev/resource/softimage/BlurApplication.dll +0 -0
- blurdev/resource/softimage/BlurApplication64.dll +0 -0
- blurdev/resource/stylesheet/Carbon.css +0 -35
- blurdev/resource/stylesheet/logger/Dark.css +0 -62
- blurdev/resource/templ/py_comment.templ +0 -1
- blurdev/resource/templ/py_debug_raise_error.templ +0 -7
- blurdev/resource/templ/py_doc_string.templ +0 -10
- blurdev/resource/templ/py_header.templ +0 -9
- blurdev/resource/templ/py_line_comment.templ +0 -1
- blurdev/resource/templ/py_log_to_file.templ +0 -22
- blurdev/resource/templ/py_module_path.templ +0 -1
- blurdev/resource/templ/py_pyqt_core.templ +0 -1
- blurdev/resource/templ/py_pyqt_gui.templ +0 -1
- blurdev/resource/templ/py_splashscreen.templ +0 -6
- blurdev/resource/templ/py_testing_note.templ +0 -1
- blurdev/resource/templ/py_testing_note_end.templ +0 -1
- blurdev/resource/tools_environments.json +0 -72
- blurdev/resource/tools_environments.xml +0 -11
- blurdev/resource/tools_environments_linux.xml +0 -11
- blurdev/resource/tools_environments_offline.xml +0 -7
- blurdev/runtimes/__init__.py +0 -2
- blurdev/runtimes/logger.py +0 -44
- blurdev/scintilla/delayables/__init__.py +0 -9
- blurdev/settings.py +0 -312
- blurdev/utils/error.py +0 -389
- {blurdev/scintilla/lexers → preditor/cores}/__init__.py +0 -0
- {blurdev/utils → preditor/gui/fuzzy_search}/__init__.py +0 -0
- {blurdev → preditor}/resource/img/warning-big.png +0 -0
|
@@ -1,858 +1,801 @@
|
|
|
1
|
-
""" LoggerWindow class is an overloaded python interpreter for
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
from Qt import
|
|
17
|
-
from Qt.
|
|
18
|
-
|
|
19
|
-
from
|
|
20
|
-
|
|
21
|
-
import
|
|
22
|
-
from
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
self.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
self.
|
|
44
|
-
|
|
45
|
-
self.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
self.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
self.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#
|
|
64
|
-
self.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
self.
|
|
72
|
-
|
|
73
|
-
#
|
|
74
|
-
self.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
self.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
#
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"""
|
|
125
|
-
self.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
self.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return super(
|
|
144
|
-
|
|
145
|
-
def
|
|
146
|
-
"""
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if
|
|
152
|
-
self.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
"""
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
self.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
def
|
|
267
|
-
"""
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
cursor
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
cursor.
|
|
277
|
-
self.setTextCursor(cursor)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
#
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
cursor
|
|
289
|
-
cursor.movePosition(cursor.End)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
self.
|
|
309
|
-
|
|
310
|
-
def
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
def
|
|
314
|
-
self.
|
|
315
|
-
|
|
316
|
-
def
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
#
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
if self.
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
#
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
hasText
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
#
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
self.
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
elif event.key()
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
completer.
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
completer.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
mode
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
self.
|
|
624
|
-
|
|
625
|
-
def
|
|
626
|
-
"""
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
def
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
self.
|
|
643
|
-
|
|
644
|
-
def
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
def
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if line and line[0] not in string.printable:
|
|
803
|
-
line = line[1:]
|
|
804
|
-
|
|
805
|
-
info = self.parseErrorHyperLinkInfo(line)
|
|
806
|
-
if info:
|
|
807
|
-
cursor.insertText("\n")
|
|
808
|
-
msg = "{}\n".format(line)
|
|
809
|
-
|
|
810
|
-
# If showing Error Hyperlinks, display underline output, otherwise
|
|
811
|
-
# display normal output. Exclude ConsoleEdits
|
|
812
|
-
info = info if info else self.parseErrorHyperLinkInfo(msg)
|
|
813
|
-
filename = info.get("filename", "") if info else ""
|
|
814
|
-
isConsoleEdit = '<ConsoleEdit>' in filename
|
|
815
|
-
|
|
816
|
-
if info and doHyperlink and not isConsoleEdit:
|
|
817
|
-
fileStart = info.get("fileStart")
|
|
818
|
-
fileEnd = info.get("fileEnd")
|
|
819
|
-
lineNum = info.get("lineNum")
|
|
820
|
-
|
|
821
|
-
isWorkbox = (
|
|
822
|
-
'<WorkboxSelection>' in filename
|
|
823
|
-
or '<WorkboxWidget>' in filename
|
|
824
|
-
)
|
|
825
|
-
if isWorkbox:
|
|
826
|
-
split = filename.split(':')
|
|
827
|
-
workboxIdx = split[-1]
|
|
828
|
-
filename = ''
|
|
829
|
-
else:
|
|
830
|
-
filename = filename
|
|
831
|
-
workboxIdx = ''
|
|
832
|
-
href = '{}, {}, {}'.format(filename, workboxIdx, lineNum)
|
|
833
|
-
|
|
834
|
-
# Insert initial, non-underlined text
|
|
835
|
-
cursor.insertText(msg[:fileStart])
|
|
836
|
-
|
|
837
|
-
# Insert hyperlink
|
|
838
|
-
fmt = cursor.charFormat()
|
|
839
|
-
fmt.setAnchor(True)
|
|
840
|
-
fmt.setAnchorHref(href)
|
|
841
|
-
fmt.setFontUnderline(True)
|
|
842
|
-
toolTip = "Open {} at line number {}".format(filename, lineNum)
|
|
843
|
-
fmt.setToolTip(toolTip)
|
|
844
|
-
cursor.insertText(msg[fileStart:fileEnd], fmt)
|
|
845
|
-
|
|
846
|
-
# Insert the rest of the msg
|
|
847
|
-
fmt.setAnchor(False)
|
|
848
|
-
fmt.setAnchorHref('')
|
|
849
|
-
fmt.setFontUnderline(False)
|
|
850
|
-
fmt.setToolTip('')
|
|
851
|
-
cursor.insertText(msg[fileEnd:], fmt)
|
|
852
|
-
else:
|
|
853
|
-
# Non-hyperlink output
|
|
854
|
-
self.insertPlainText(msg)
|
|
855
|
-
|
|
856
|
-
# if a outputPipe was provided, write the message to that pipe
|
|
857
|
-
if self.outputPipe:
|
|
858
|
-
self.outputPipe(msg, error=error)
|
|
1
|
+
""" LoggerWindow class is an overloaded python interpreter for preditor"""
|
|
2
|
+
from __future__ import absolute_import, print_function
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
import string
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
import traceback
|
|
11
|
+
from builtins import str as text
|
|
12
|
+
|
|
13
|
+
import __main__
|
|
14
|
+
from Qt import QtCompat
|
|
15
|
+
from Qt.QtCore import QPoint, Qt
|
|
16
|
+
from Qt.QtGui import QColor, QFontMetrics, QTextCharFormat, QTextCursor, QTextDocument
|
|
17
|
+
from Qt.QtWidgets import QAction, QApplication, QTextEdit
|
|
18
|
+
|
|
19
|
+
from .. import debug, settings, stream
|
|
20
|
+
from ..streamhandler_helper import StreamHandlerHelper
|
|
21
|
+
from .codehighlighter import CodeHighlighter
|
|
22
|
+
from .completer import PythonCompleter
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ConsolePrEdit(QTextEdit):
|
|
26
|
+
# Ensure the error prompt only shows up once.
|
|
27
|
+
_errorPrompted = False
|
|
28
|
+
# the color error messages are displayed in, can be set by stylesheets
|
|
29
|
+
_errorMessageColor = QColor(Qt.red)
|
|
30
|
+
|
|
31
|
+
def __init__(self, parent):
|
|
32
|
+
super(ConsolePrEdit, self).__init__(parent)
|
|
33
|
+
# store the error buffer
|
|
34
|
+
self._completer = None
|
|
35
|
+
|
|
36
|
+
# If populated, also write to this interface
|
|
37
|
+
self.outputPipe = None
|
|
38
|
+
|
|
39
|
+
self._stdoutColor = QColor(17, 154, 255)
|
|
40
|
+
self._commentColor = QColor(0, 206, 52)
|
|
41
|
+
self._keywordColor = QColor(17, 154, 255)
|
|
42
|
+
self._stringColor = QColor(255, 128, 0)
|
|
43
|
+
self._resultColor = QColor(128, 128, 128)
|
|
44
|
+
|
|
45
|
+
self._consolePrompt = '>>> '
|
|
46
|
+
# Note: Changing _outputPrompt may require updating resource\lang\python.xml
|
|
47
|
+
# If still using a #
|
|
48
|
+
self._outputPrompt = '#Result: '
|
|
49
|
+
# Method used to update the gui when code is executed
|
|
50
|
+
self.reportExecutionTime = None
|
|
51
|
+
|
|
52
|
+
self._firstShow = True
|
|
53
|
+
|
|
54
|
+
# When executing code, that takes longer than this seconds, flash the window
|
|
55
|
+
self.flash_time = 1.0
|
|
56
|
+
self.flash_window = None
|
|
57
|
+
|
|
58
|
+
# Store previous commands to retrieve easily
|
|
59
|
+
self._prevCommands = []
|
|
60
|
+
self._prevCommandIndex = 0
|
|
61
|
+
self._prevCommandsMax = 100
|
|
62
|
+
|
|
63
|
+
# create the completer
|
|
64
|
+
self.setCompleter(PythonCompleter(self))
|
|
65
|
+
|
|
66
|
+
# sys.__stdout__ doesn't work if some third party has implemented their own
|
|
67
|
+
# override. Use these to backup the current logger so the logger displays
|
|
68
|
+
# output, but application specific consoles also get the info.
|
|
69
|
+
self.stdout = None
|
|
70
|
+
self.stderr = None
|
|
71
|
+
self._errorLog = None
|
|
72
|
+
|
|
73
|
+
# overload the sys logger
|
|
74
|
+
self.stream_manager = stream.install_to_std()
|
|
75
|
+
# Redirect future writes directly to the console, add any previous writes
|
|
76
|
+
# to the console and free up the memory consumed by previous writes as we
|
|
77
|
+
# assume this is likely to be the only callback added to the manager.
|
|
78
|
+
self.stream_manager.add_callback(
|
|
79
|
+
self.write, replay=True, disable_writes=True, clear=True
|
|
80
|
+
)
|
|
81
|
+
# Store the current outputs
|
|
82
|
+
self.stdout = sys.stdout
|
|
83
|
+
self.stderr = sys.stderr
|
|
84
|
+
self._errorLog = sys.stderr
|
|
85
|
+
debug.BlurExcepthook.install()
|
|
86
|
+
|
|
87
|
+
# Update any StreamHandler's that were setup using the old stdout/err
|
|
88
|
+
StreamHandlerHelper.replace_stream(self.stdout, sys.stdout)
|
|
89
|
+
StreamHandlerHelper.replace_stream(self.stderr, sys.stderr)
|
|
90
|
+
|
|
91
|
+
# create the highlighter
|
|
92
|
+
highlight = CodeHighlighter(self)
|
|
93
|
+
highlight.setLanguage('Python')
|
|
94
|
+
self.uiCodeHighlighter = highlight
|
|
95
|
+
|
|
96
|
+
self.uiClearToLastPromptACT = QAction('Clear to Last', self)
|
|
97
|
+
self.uiClearToLastPromptACT.triggered.connect(self.clearToLastPrompt)
|
|
98
|
+
self.uiClearToLastPromptACT.setShortcut(Qt.CTRL | Qt.SHIFT | Qt.Key_Backspace)
|
|
99
|
+
self.addAction(self.uiClearToLastPromptACT)
|
|
100
|
+
|
|
101
|
+
self.x = 0
|
|
102
|
+
self.clickPos = None
|
|
103
|
+
self.anchor = None
|
|
104
|
+
|
|
105
|
+
def setConsoleFont(self, font):
|
|
106
|
+
"""Set the console's font and adjust the tabStopWidth"""
|
|
107
|
+
self.setFont(font)
|
|
108
|
+
|
|
109
|
+
# Set the setTabStopWidth for the console's font
|
|
110
|
+
tab_width = 4
|
|
111
|
+
# TODO: Make tab_width a general user setting
|
|
112
|
+
if hasattr(self, "window") and "LoggerWindow" in str(type(self.window())):
|
|
113
|
+
# If parented to a LoggerWindow, get the tab_width from it's workboxes
|
|
114
|
+
workbox = self.window().current_workbox()
|
|
115
|
+
if workbox:
|
|
116
|
+
tab_width = workbox.__tab_width__()
|
|
117
|
+
fontPixelWidth = QFontMetrics(font).width(" ")
|
|
118
|
+
self.setTabStopWidth(fontPixelWidth * tab_width)
|
|
119
|
+
|
|
120
|
+
def mousePressEvent(self, event):
|
|
121
|
+
"""Overload of mousePressEvent to capture click position, so on release, we can
|
|
122
|
+
check release position. If it's the same (ie user clicked vs click-drag to
|
|
123
|
+
select text), we check if user clicked an error hyperlink.
|
|
124
|
+
"""
|
|
125
|
+
self.clickPos = event.pos()
|
|
126
|
+
self.anchor = self.anchorAt(event.pos())
|
|
127
|
+
if self.anchor:
|
|
128
|
+
QApplication.setOverrideCursor(Qt.PointingHandCursor)
|
|
129
|
+
return super(ConsolePrEdit, self).mousePressEvent(event)
|
|
130
|
+
|
|
131
|
+
def mouseReleaseEvent(self, event):
|
|
132
|
+
"""Overload of mouseReleaseEvent to capture if user has left clicked... Check if
|
|
133
|
+
click position is the same as release position, if so, call errorHyperlink.
|
|
134
|
+
"""
|
|
135
|
+
samePos = event.pos() == self.clickPos
|
|
136
|
+
left = event.button() == Qt.LeftButton
|
|
137
|
+
if samePos and left and self.anchor:
|
|
138
|
+
self.errorHyperlink()
|
|
139
|
+
|
|
140
|
+
self.clickPos = None
|
|
141
|
+
self.anchor = None
|
|
142
|
+
QApplication.restoreOverrideCursor()
|
|
143
|
+
return super(ConsolePrEdit, self).mouseReleaseEvent(event)
|
|
144
|
+
|
|
145
|
+
def wheelEvent(self, event):
|
|
146
|
+
"""Override of wheelEvent to allow for font resizing by holding ctrl while"""
|
|
147
|
+
# scrolling. If used in LoggerWindow, use that wheel event
|
|
148
|
+
# May not want to import LoggerWindow, so perhaps
|
|
149
|
+
# check by str(type())
|
|
150
|
+
ctrlPressed = event.modifiers() == Qt.ControlModifier
|
|
151
|
+
if ctrlPressed and "LoggerWindow" in str(type(self.window())):
|
|
152
|
+
self.window().wheelEvent(event)
|
|
153
|
+
else:
|
|
154
|
+
QTextEdit.wheelEvent(self, event)
|
|
155
|
+
|
|
156
|
+
def keyReleaseEvent(self, event):
|
|
157
|
+
"""Override of keyReleaseEvent to determine when to end navigation of
|
|
158
|
+
previous commands
|
|
159
|
+
"""
|
|
160
|
+
if event.key() == Qt.Key_Alt:
|
|
161
|
+
self._prevCommandIndex = 0
|
|
162
|
+
else:
|
|
163
|
+
event.ignore()
|
|
164
|
+
|
|
165
|
+
def errorHyperlink(self):
|
|
166
|
+
"""Determine if chosen line is an error traceback file-info line, if so, parse
|
|
167
|
+
the filepath and line number, and attempt to open the module file in the user's
|
|
168
|
+
chosen text editor at the relevant line, using specified Command Prompt pattern.
|
|
169
|
+
|
|
170
|
+
The text editor defaults to SublimeText3, in the normal install directory
|
|
171
|
+
"""
|
|
172
|
+
window = self.window()
|
|
173
|
+
|
|
174
|
+
# Bail if Error Hyperlinks setting is not turned on or we don't have an anchor.
|
|
175
|
+
doHyperlink = (
|
|
176
|
+
hasattr(window, 'uiErrorHyperlinksACT')
|
|
177
|
+
and window.uiErrorHyperlinksACT.isChecked()
|
|
178
|
+
and self.anchor
|
|
179
|
+
)
|
|
180
|
+
if not doHyperlink:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# info is a comma separated string, in the form: "filename, workboxIdx, lineNum"
|
|
184
|
+
info = self.anchor.split(', ')
|
|
185
|
+
modulePath = info[0]
|
|
186
|
+
workboxIndex = info[1]
|
|
187
|
+
lineNum = info[2]
|
|
188
|
+
|
|
189
|
+
# fetch info from LoggerWindow
|
|
190
|
+
exePath = ''
|
|
191
|
+
cmdTempl = ''
|
|
192
|
+
if hasattr(window, 'textEditorPath'):
|
|
193
|
+
exePath = window.textEditorPath
|
|
194
|
+
cmdTempl = window.textEditorCmdTempl
|
|
195
|
+
|
|
196
|
+
# Bail if not setup properly
|
|
197
|
+
msg = "Cannot use traceback hyperlink. "
|
|
198
|
+
if not exePath:
|
|
199
|
+
msg += "No text editor path defined."
|
|
200
|
+
print(msg)
|
|
201
|
+
return
|
|
202
|
+
if not os.path.exists(exePath):
|
|
203
|
+
msg += "Text editor executable does not exist: {}".format(exePath)
|
|
204
|
+
print(msg)
|
|
205
|
+
return
|
|
206
|
+
if not cmdTempl:
|
|
207
|
+
msg += "No text editor Command Prompt command template defined."
|
|
208
|
+
print(msg)
|
|
209
|
+
return
|
|
210
|
+
if modulePath and not os.path.exists(modulePath):
|
|
211
|
+
msg += "Specified module path does not exist: {}".format(modulePath)
|
|
212
|
+
print(msg)
|
|
213
|
+
return
|
|
214
|
+
|
|
215
|
+
if modulePath:
|
|
216
|
+
# Attempt to create command from template and run the command
|
|
217
|
+
try:
|
|
218
|
+
command = cmdTempl.format(
|
|
219
|
+
exePath=exePath, modulePath=modulePath, lineNum=lineNum
|
|
220
|
+
)
|
|
221
|
+
subprocess.Popen(command)
|
|
222
|
+
except (ValueError, OSError):
|
|
223
|
+
msg = "The provided text editor command template is not valid:\n {}"
|
|
224
|
+
msg = msg.format(cmdTempl)
|
|
225
|
+
print(msg)
|
|
226
|
+
elif workboxIndex is not None:
|
|
227
|
+
group, editor = workboxIndex.split(',')
|
|
228
|
+
lineNum = int(lineNum)
|
|
229
|
+
workbox = window.uiWorkboxTAB.set_current_groups_from_index(
|
|
230
|
+
int(group), int(editor)
|
|
231
|
+
)
|
|
232
|
+
workbox.__goto_line__(lineNum)
|
|
233
|
+
workbox.setFocus()
|
|
234
|
+
|
|
235
|
+
def getPrevCommand(self):
|
|
236
|
+
"""Find and display the previous command in stack"""
|
|
237
|
+
self._prevCommandIndex -= 1
|
|
238
|
+
|
|
239
|
+
if abs(self._prevCommandIndex) > len(self._prevCommands):
|
|
240
|
+
self._prevCommandIndex += 1
|
|
241
|
+
|
|
242
|
+
if self._prevCommands:
|
|
243
|
+
self.setCommand()
|
|
244
|
+
|
|
245
|
+
def getNextCommand(self):
|
|
246
|
+
"""Find and display the next command in stack"""
|
|
247
|
+
self._prevCommandIndex += 1
|
|
248
|
+
self._prevCommandIndex = min(self._prevCommandIndex, 0)
|
|
249
|
+
|
|
250
|
+
if self._prevCommands:
|
|
251
|
+
self.setCommand()
|
|
252
|
+
|
|
253
|
+
def setCommand(self):
|
|
254
|
+
"""Do the displaying of currently chosen command"""
|
|
255
|
+
prevCommand = ''
|
|
256
|
+
if self._prevCommandIndex:
|
|
257
|
+
prevCommand = self._prevCommands[self._prevCommandIndex]
|
|
258
|
+
|
|
259
|
+
cursor = self.textCursor()
|
|
260
|
+
cursor.select(QTextCursor.LineUnderCursor)
|
|
261
|
+
if cursor.selectedText().startswith(self._consolePrompt):
|
|
262
|
+
prevCommand = "{}{}".format(self._consolePrompt, prevCommand)
|
|
263
|
+
cursor.insertText(prevCommand)
|
|
264
|
+
self.setTextCursor(cursor)
|
|
265
|
+
|
|
266
|
+
def clear(self):
|
|
267
|
+
"""clears the text in the editor"""
|
|
268
|
+
QTextEdit.clear(self)
|
|
269
|
+
self.startInputLine()
|
|
270
|
+
|
|
271
|
+
def clearToLastPrompt(self):
|
|
272
|
+
# store the current cursor position so we can restore when we are done
|
|
273
|
+
currentCursor = self.textCursor()
|
|
274
|
+
# move to the end of the document so we can search backwards
|
|
275
|
+
cursor = self.textCursor()
|
|
276
|
+
cursor.movePosition(cursor.End)
|
|
277
|
+
self.setTextCursor(cursor)
|
|
278
|
+
# Check if the last line is a empty prompt. If so, then preform two finds so we
|
|
279
|
+
# find the prompt we are looking for instead of this empty prompt
|
|
280
|
+
findCount = (
|
|
281
|
+
2 if self.toPlainText()[-len(self.prompt()) :] == self.prompt() else 1
|
|
282
|
+
)
|
|
283
|
+
for _ in range(findCount):
|
|
284
|
+
self.find(self.prompt(), QTextDocument.FindBackward)
|
|
285
|
+
# move to the end of the found line, select the rest of the text and remove it
|
|
286
|
+
# preserving history if there is anything to remove.
|
|
287
|
+
cursor = self.textCursor()
|
|
288
|
+
cursor.movePosition(cursor.EndOfLine)
|
|
289
|
+
cursor.movePosition(cursor.End, cursor.KeepAnchor)
|
|
290
|
+
txt = cursor.selectedText()
|
|
291
|
+
if txt:
|
|
292
|
+
self.setTextCursor(cursor)
|
|
293
|
+
self.insertPlainText('')
|
|
294
|
+
# Restore the cursor position to its original location
|
|
295
|
+
self.setTextCursor(currentCursor)
|
|
296
|
+
|
|
297
|
+
def commentColor(self):
|
|
298
|
+
return self._commentColor
|
|
299
|
+
|
|
300
|
+
def setCommentColor(self, color):
|
|
301
|
+
self._commentColor = color
|
|
302
|
+
|
|
303
|
+
def completer(self):
|
|
304
|
+
"""returns the completer instance that is associated with this editor"""
|
|
305
|
+
return self._completer
|
|
306
|
+
|
|
307
|
+
def errorMessageColor(self):
|
|
308
|
+
return self.__class__._errorMessageColor
|
|
309
|
+
|
|
310
|
+
def setErrorMessageColor(self, color):
|
|
311
|
+
self.__class__._errorMessageColor = color
|
|
312
|
+
|
|
313
|
+
def foregroundColor(self):
|
|
314
|
+
return self._foregroundColor
|
|
315
|
+
|
|
316
|
+
def setForegroundColor(self, color):
|
|
317
|
+
self._foregroundColor = color
|
|
318
|
+
|
|
319
|
+
def executeString(self, commandText, filename='<ConsolePrEdit>', extraPrint=True):
|
|
320
|
+
cursor = self.textCursor()
|
|
321
|
+
cursor.select(QTextCursor.BlockUnderCursor)
|
|
322
|
+
line = cursor.selectedText()
|
|
323
|
+
if line and line[0] not in string.printable:
|
|
324
|
+
line = line[1:]
|
|
325
|
+
|
|
326
|
+
if line.startswith(self.prompt()) and extraPrint:
|
|
327
|
+
print("")
|
|
328
|
+
|
|
329
|
+
cmdresult = None
|
|
330
|
+
# https://stackoverflow.com/a/29456463
|
|
331
|
+
# If you want to get the result of the code, you have to call eval
|
|
332
|
+
# however eval does not accept multiple statements. For that you need
|
|
333
|
+
# exec which has no Return.
|
|
334
|
+
wasEval = False
|
|
335
|
+
startTime = time.time()
|
|
336
|
+
try:
|
|
337
|
+
compiled = compile(commandText, filename, 'eval')
|
|
338
|
+
wasEval = True
|
|
339
|
+
except Exception:
|
|
340
|
+
compiled = compile(commandText, filename, 'exec')
|
|
341
|
+
if wasEval:
|
|
342
|
+
cmdresult = eval(compiled, __main__.__dict__, __main__.__dict__)
|
|
343
|
+
else:
|
|
344
|
+
exec(compiled, __main__.__dict__, __main__.__dict__)
|
|
345
|
+
|
|
346
|
+
# Provide user feedback when running long code execution.
|
|
347
|
+
delta = time.time() - startTime
|
|
348
|
+
if self.flash_window and self.flash_time and delta >= self.flash_time:
|
|
349
|
+
if settings.OS_TYPE == "Windows":
|
|
350
|
+
try:
|
|
351
|
+
from casement import utils
|
|
352
|
+
except ImportError:
|
|
353
|
+
# If casement is not installed, flash window is disabled
|
|
354
|
+
pass
|
|
355
|
+
else:
|
|
356
|
+
hwnd = int(self.flash_window.winId())
|
|
357
|
+
utils.flash_window(hwnd)
|
|
358
|
+
|
|
359
|
+
# Report the total time it took to execute this code.
|
|
360
|
+
if self.reportExecutionTime is not None:
|
|
361
|
+
self.reportExecutionTime(delta)
|
|
362
|
+
return cmdresult, wasEval
|
|
363
|
+
|
|
364
|
+
def executeCommand(self):
|
|
365
|
+
"""executes the current line of code"""
|
|
366
|
+
# grab the command from the line
|
|
367
|
+
block = self.textCursor().block().text()
|
|
368
|
+
p = '{prompt}(.*)'.format(prompt=re.escape(self.prompt()))
|
|
369
|
+
results = re.search(p, block)
|
|
370
|
+
if results:
|
|
371
|
+
commandText = results.groups()[0]
|
|
372
|
+
# if the cursor position is at the end of the line
|
|
373
|
+
if self.textCursor().atEnd():
|
|
374
|
+
# insert a new line
|
|
375
|
+
self.insertPlainText('\n')
|
|
376
|
+
|
|
377
|
+
# update prevCommands list, but only if commandText is not the most
|
|
378
|
+
# recent prevCommand, or there are no previous commands
|
|
379
|
+
hasText = len(commandText) > 0
|
|
380
|
+
prevCmds = self._prevCommands
|
|
381
|
+
notPrevCmd = not prevCmds or prevCmds[-1] != commandText
|
|
382
|
+
if hasText and notPrevCmd:
|
|
383
|
+
self._prevCommands.append(commandText)
|
|
384
|
+
# limit length of prevCommand list to max number of prev commands
|
|
385
|
+
self._prevCommands = self._prevCommands[-1 * self._prevCommandsMax :]
|
|
386
|
+
|
|
387
|
+
# evaluate the command
|
|
388
|
+
cmdresult, wasEval = self.executeString(commandText)
|
|
389
|
+
|
|
390
|
+
# print the resulting commands
|
|
391
|
+
if cmdresult is not None:
|
|
392
|
+
# When writing to additional stdout's not including a new line
|
|
393
|
+
# makes the output not match the formatting you get inside the
|
|
394
|
+
# console.
|
|
395
|
+
self.write(u'{}\n'.format(cmdresult))
|
|
396
|
+
# NOTE: I am using u'' above so unicode strings in python 2
|
|
397
|
+
# don't get converted to str objects.
|
|
398
|
+
|
|
399
|
+
self.startInputLine()
|
|
400
|
+
|
|
401
|
+
# otherwise, move the command to the end of the line
|
|
402
|
+
else:
|
|
403
|
+
self.startInputLine()
|
|
404
|
+
self.insertPlainText(commandText)
|
|
405
|
+
|
|
406
|
+
# if no command, then start a new line
|
|
407
|
+
else:
|
|
408
|
+
self.startInputLine()
|
|
409
|
+
|
|
410
|
+
def flush(self):
|
|
411
|
+
pass
|
|
412
|
+
|
|
413
|
+
def focusInEvent(self, event):
|
|
414
|
+
"""overload the focus in event to ensure the completer has the proper widget"""
|
|
415
|
+
if self.completer():
|
|
416
|
+
self.completer().setWidget(self)
|
|
417
|
+
QTextEdit.focusInEvent(self, event)
|
|
418
|
+
|
|
419
|
+
def insertCompletion(self, completion):
|
|
420
|
+
"""inserts the completion text into the editor"""
|
|
421
|
+
if self.completer().widget() == self:
|
|
422
|
+
cursor = self.textCursor()
|
|
423
|
+
cursor.select(QTextCursor.WordUnderCursor)
|
|
424
|
+
cursor.insertText(completion)
|
|
425
|
+
self.setTextCursor(cursor)
|
|
426
|
+
|
|
427
|
+
def insertFromMimeData(self, mimeData):
|
|
428
|
+
html = False
|
|
429
|
+
if mimeData.hasHtml():
|
|
430
|
+
txt = mimeData.html()
|
|
431
|
+
html = True
|
|
432
|
+
else:
|
|
433
|
+
txt = mimeData.text()
|
|
434
|
+
|
|
435
|
+
doc = QTextDocument()
|
|
436
|
+
|
|
437
|
+
if html:
|
|
438
|
+
doc.setHtml(txt)
|
|
439
|
+
else:
|
|
440
|
+
doc.setPlainText(txt)
|
|
441
|
+
|
|
442
|
+
txt = doc.toPlainText()
|
|
443
|
+
|
|
444
|
+
exp = re.compile(
|
|
445
|
+
(
|
|
446
|
+
r'[^A-Za-z0-9\~\!\@\#\$\%\^\&\*\(\)\_\+\{\}\|\:'
|
|
447
|
+
r'\"\<\>\?\`\-\=\[\]\\\;\'\,\.\/ \t\n]'
|
|
448
|
+
)
|
|
449
|
+
)
|
|
450
|
+
newText = text(txt)
|
|
451
|
+
for each in exp.findall(newText):
|
|
452
|
+
newText = newText.replace(each, '?')
|
|
453
|
+
|
|
454
|
+
self.insertPlainText(newText)
|
|
455
|
+
|
|
456
|
+
def isatty(self):
|
|
457
|
+
"""Return True if the stream is interactive (i.e., connected to a terminal/tty
|
|
458
|
+
device).
|
|
459
|
+
"""
|
|
460
|
+
# This method is required for pytest to run in a DCC. Returns False so the
|
|
461
|
+
# output does not contain cursor control characters that disrupt the visual
|
|
462
|
+
# display of the output.
|
|
463
|
+
return False
|
|
464
|
+
|
|
465
|
+
def lastError(self):
|
|
466
|
+
try:
|
|
467
|
+
return ''.join(
|
|
468
|
+
traceback.format_exception(
|
|
469
|
+
sys.last_type, sys.last_value, sys.last_traceback
|
|
470
|
+
)
|
|
471
|
+
)
|
|
472
|
+
except AttributeError:
|
|
473
|
+
# last_traceback, last_type and last_value do not always exist
|
|
474
|
+
return ''
|
|
475
|
+
|
|
476
|
+
def keyPressEvent(self, event):
|
|
477
|
+
"""overload the key press event to handle custom events"""
|
|
478
|
+
|
|
479
|
+
completer = self.completer()
|
|
480
|
+
|
|
481
|
+
if completer and event.key() in (
|
|
482
|
+
Qt.Key_Backspace,
|
|
483
|
+
Qt.Key_Delete,
|
|
484
|
+
Qt.Key_Escape,
|
|
485
|
+
):
|
|
486
|
+
completer.hideDocumentation()
|
|
487
|
+
|
|
488
|
+
# enter || return keys will execute the command
|
|
489
|
+
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
|
490
|
+
if completer.popup().isVisible():
|
|
491
|
+
completer.clear()
|
|
492
|
+
event.ignore()
|
|
493
|
+
else:
|
|
494
|
+
self.executeCommand()
|
|
495
|
+
|
|
496
|
+
# home key will move the cursor to home
|
|
497
|
+
elif event.key() == Qt.Key_Home:
|
|
498
|
+
self.moveToHome()
|
|
499
|
+
|
|
500
|
+
# otherwise, ignore the event for completion events
|
|
501
|
+
elif event.key() in (Qt.Key_Tab, Qt.Key_Backtab):
|
|
502
|
+
if not completer.popup().isVisible():
|
|
503
|
+
# The completer does not get updated if its not visible while typing.
|
|
504
|
+
# We are about to complete the text using it so ensure its updated.
|
|
505
|
+
completer.refreshList(scope=__main__.__dict__)
|
|
506
|
+
completer.popup().setCurrentIndex(
|
|
507
|
+
completer.completionModel().index(0, 0)
|
|
508
|
+
)
|
|
509
|
+
# Insert the correct text and clear the completion model
|
|
510
|
+
index = completer.popup().currentIndex()
|
|
511
|
+
self.insertCompletion(index.data(Qt.DisplayRole))
|
|
512
|
+
completer.clear()
|
|
513
|
+
|
|
514
|
+
elif event.key() == Qt.Key_Escape and completer.popup().isVisible():
|
|
515
|
+
completer.clear()
|
|
516
|
+
|
|
517
|
+
# other wise handle the keypress
|
|
518
|
+
else:
|
|
519
|
+
# define special key sequences
|
|
520
|
+
modifiers = QApplication.instance().keyboardModifiers()
|
|
521
|
+
ctrlSpace = event.key() == Qt.Key_Space and modifiers == Qt.ControlModifier
|
|
522
|
+
ctrlM = event.key() == Qt.Key_M and modifiers == Qt.ControlModifier
|
|
523
|
+
ctrlI = event.key() == Qt.Key_I and modifiers == Qt.ControlModifier
|
|
524
|
+
|
|
525
|
+
# Process all events we do not want to override
|
|
526
|
+
if not (ctrlSpace or ctrlM or ctrlI):
|
|
527
|
+
QTextEdit.keyPressEvent(self, event)
|
|
528
|
+
|
|
529
|
+
window = self.window()
|
|
530
|
+
if ctrlI:
|
|
531
|
+
hasToggleCase = hasattr(window, 'toggleCaseSensitive')
|
|
532
|
+
if hasToggleCase:
|
|
533
|
+
window.toggleCaseSensitive()
|
|
534
|
+
if ctrlM:
|
|
535
|
+
hasCycleMode = hasattr(window, 'cycleCompleterMode')
|
|
536
|
+
if hasCycleMode:
|
|
537
|
+
window.cycleCompleterMode()
|
|
538
|
+
|
|
539
|
+
# check for particular events for the completion
|
|
540
|
+
if completer:
|
|
541
|
+
# look for documentation popups
|
|
542
|
+
if event.key() == Qt.Key_ParenLeft:
|
|
543
|
+
rect = self.cursorRect()
|
|
544
|
+
point = self.mapToGlobal(QPoint(rect.x(), rect.y()))
|
|
545
|
+
completer.showDocumentation(pos=point, scope=__main__.__dict__)
|
|
546
|
+
|
|
547
|
+
# hide documentation popups
|
|
548
|
+
elif event.key() == Qt.Key_ParenRight:
|
|
549
|
+
completer.hideDocumentation()
|
|
550
|
+
|
|
551
|
+
# determine if we need to show the popup or if it already is visible, we
|
|
552
|
+
# need to update it
|
|
553
|
+
elif (
|
|
554
|
+
event.key() == Qt.Key_Period
|
|
555
|
+
or event.key() == Qt.Key_Escape
|
|
556
|
+
or completer.popup().isVisible()
|
|
557
|
+
or ctrlSpace
|
|
558
|
+
or ctrlI
|
|
559
|
+
or ctrlM
|
|
560
|
+
or completer.wasCompletingCounter
|
|
561
|
+
):
|
|
562
|
+
completer.refreshList(scope=__main__.__dict__)
|
|
563
|
+
completer.popup().setCurrentIndex(
|
|
564
|
+
completer.completionModel().index(0, 0)
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
# show the completer for the rect
|
|
568
|
+
rect = self.cursorRect()
|
|
569
|
+
rect.setWidth(
|
|
570
|
+
completer.popup().sizeHintForColumn(0)
|
|
571
|
+
+ completer.popup().verticalScrollBar().sizeHint().width()
|
|
572
|
+
)
|
|
573
|
+
completer.complete(rect)
|
|
574
|
+
|
|
575
|
+
if completer.popup().isVisible():
|
|
576
|
+
completer.wasCompleting = True
|
|
577
|
+
completer.wasCompletingCounter = 0
|
|
578
|
+
|
|
579
|
+
if completer.wasCompleting and not completer.popup().isVisible():
|
|
580
|
+
wasCompletingCounterMax = completer.wasCompletingCounterMax
|
|
581
|
+
if completer.wasCompletingCounter <= wasCompletingCounterMax:
|
|
582
|
+
if event.key() not in (Qt.Key_Backspace, Qt.Key_Left):
|
|
583
|
+
completer.wasCompletingCounter += 1
|
|
584
|
+
else:
|
|
585
|
+
completer.wasCompletingCounter = 0
|
|
586
|
+
completer.wasCompleting = False
|
|
587
|
+
|
|
588
|
+
def keywordColor(self):
|
|
589
|
+
return self._keywordColor
|
|
590
|
+
|
|
591
|
+
def setKeywordColor(self, color):
|
|
592
|
+
self._keywordColor = color
|
|
593
|
+
|
|
594
|
+
def moveToHome(self):
|
|
595
|
+
"""moves the cursor to the home location"""
|
|
596
|
+
mode = QTextCursor.MoveAnchor
|
|
597
|
+
# select the home
|
|
598
|
+
if QApplication.instance().keyboardModifiers() == Qt.ShiftModifier:
|
|
599
|
+
mode = QTextCursor.KeepAnchor
|
|
600
|
+
# grab the cursor
|
|
601
|
+
cursor = self.textCursor()
|
|
602
|
+
if QApplication.instance().keyboardModifiers() == Qt.ControlModifier:
|
|
603
|
+
# move to the top of the document if control is pressed
|
|
604
|
+
cursor.movePosition(QTextCursor.Start)
|
|
605
|
+
else:
|
|
606
|
+
# Otherwise just move it to the start of the line
|
|
607
|
+
cursor.movePosition(QTextCursor.StartOfBlock, mode)
|
|
608
|
+
# move the cursor to the end of the prompt.
|
|
609
|
+
cursor.movePosition(QTextCursor.Right, mode, len(self.prompt()))
|
|
610
|
+
self.setTextCursor(cursor)
|
|
611
|
+
|
|
612
|
+
def outputPrompt(self):
|
|
613
|
+
"""The prompt used to output a result."""
|
|
614
|
+
return self._outputPrompt
|
|
615
|
+
|
|
616
|
+
def prompt(self):
|
|
617
|
+
return self._consolePrompt
|
|
618
|
+
|
|
619
|
+
def resultColor(self):
|
|
620
|
+
return self._resultColor
|
|
621
|
+
|
|
622
|
+
def setResultColor(self, color):
|
|
623
|
+
self._resultColor = color
|
|
624
|
+
|
|
625
|
+
def setCompleter(self, completer):
|
|
626
|
+
"""sets the completer instance for this widget"""
|
|
627
|
+
if completer:
|
|
628
|
+
self._completer = completer
|
|
629
|
+
completer.setWidget(self)
|
|
630
|
+
completer.activated.connect(self.insertCompletion)
|
|
631
|
+
|
|
632
|
+
def showEvent(self, event):
|
|
633
|
+
# _firstShow is used to ensure the first imput prompt is styled by any active
|
|
634
|
+
# stylesheet
|
|
635
|
+
if self._firstShow:
|
|
636
|
+
self.startInputLine()
|
|
637
|
+
self._firstShow = False
|
|
638
|
+
super(ConsolePrEdit, self).showEvent(event)
|
|
639
|
+
|
|
640
|
+
def startInputLine(self):
|
|
641
|
+
"""create a new command prompt line"""
|
|
642
|
+
self.startPrompt(self.prompt())
|
|
643
|
+
|
|
644
|
+
def startPrompt(self, prompt):
|
|
645
|
+
"""create a new command prompt line with the given prompt
|
|
646
|
+
|
|
647
|
+
Args:
|
|
648
|
+
prompt(str): The prompt to start the line with. If this prompt
|
|
649
|
+
is already the only text on the last line this function does nothing.
|
|
650
|
+
"""
|
|
651
|
+
self.moveCursor(QTextCursor.End)
|
|
652
|
+
|
|
653
|
+
# if this is not already a new line
|
|
654
|
+
if self.textCursor().block().text() != prompt:
|
|
655
|
+
charFormat = QTextCharFormat()
|
|
656
|
+
self.setCurrentCharFormat(charFormat)
|
|
657
|
+
|
|
658
|
+
inputstr = prompt
|
|
659
|
+
if self.textCursor().block().text():
|
|
660
|
+
inputstr = '\n' + inputstr
|
|
661
|
+
|
|
662
|
+
self.insertPlainText(inputstr)
|
|
663
|
+
|
|
664
|
+
def startOutputLine(self):
|
|
665
|
+
"""Create a new line to show output text."""
|
|
666
|
+
self.startPrompt(self._outputPrompt)
|
|
667
|
+
|
|
668
|
+
def stdoutColor(self):
|
|
669
|
+
return self._stdoutColor
|
|
670
|
+
|
|
671
|
+
def setStdoutColor(self, color):
|
|
672
|
+
self._stdoutColor = color
|
|
673
|
+
|
|
674
|
+
def stringColor(self):
|
|
675
|
+
return self._stringColor
|
|
676
|
+
|
|
677
|
+
def setStringColor(self, color):
|
|
678
|
+
self._stringColor = color
|
|
679
|
+
|
|
680
|
+
def removeCurrentLine(self):
|
|
681
|
+
self.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
|
|
682
|
+
self.moveCursor(QTextCursor.StartOfLine, QTextCursor.MoveAnchor)
|
|
683
|
+
self.moveCursor(QTextCursor.End, QTextCursor.KeepAnchor)
|
|
684
|
+
self.textCursor().removeSelectedText()
|
|
685
|
+
self.textCursor().deletePreviousChar()
|
|
686
|
+
self.insertPlainText("\n")
|
|
687
|
+
|
|
688
|
+
def parseErrorHyperLinkInfo(self, txt):
|
|
689
|
+
"""Determine if txt is a File-info line from a traceback, and if so, return info
|
|
690
|
+
dict.
|
|
691
|
+
"""
|
|
692
|
+
lineMarker = '", line '
|
|
693
|
+
ret = None
|
|
694
|
+
|
|
695
|
+
filenameEnd = txt.find(lineMarker)
|
|
696
|
+
if txt[:8] == ' File "' and filenameEnd >= 0:
|
|
697
|
+
filename = txt[8:filenameEnd]
|
|
698
|
+
lineNumStart = filenameEnd + len(lineMarker)
|
|
699
|
+
lineNumEnd = txt.find(',', lineNumStart)
|
|
700
|
+
if lineNumEnd == -1:
|
|
701
|
+
lineNumEnd = len(txt)
|
|
702
|
+
lineNum = txt[lineNumStart:lineNumEnd]
|
|
703
|
+
ret = {
|
|
704
|
+
'filename': filename,
|
|
705
|
+
'fileStart': 8,
|
|
706
|
+
'fileEnd': filenameEnd,
|
|
707
|
+
'lineNum': lineNum,
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return ret
|
|
711
|
+
|
|
712
|
+
def write(self, msg, error=False):
|
|
713
|
+
"""write the message to the logger"""
|
|
714
|
+
# Convert the stream_manager's stream to the boolean value this function expects
|
|
715
|
+
error = error == stream.STDERR
|
|
716
|
+
# Check that we haven't been garbage collected before trying to write.
|
|
717
|
+
# This can happen while shutting down a QApplication like Nuke.
|
|
718
|
+
if QtCompat.isValid(self):
|
|
719
|
+
window = self.window()
|
|
720
|
+
doHyperlink = (
|
|
721
|
+
hasattr(window, 'uiErrorHyperlinksACT')
|
|
722
|
+
and window.uiErrorHyperlinksACT.isChecked()
|
|
723
|
+
)
|
|
724
|
+
self.moveCursor(QTextCursor.End)
|
|
725
|
+
|
|
726
|
+
charFormat = QTextCharFormat()
|
|
727
|
+
if not error:
|
|
728
|
+
charFormat.setForeground(self.stdoutColor())
|
|
729
|
+
else:
|
|
730
|
+
charFormat.setForeground(self.errorMessageColor())
|
|
731
|
+
self.setCurrentCharFormat(charFormat)
|
|
732
|
+
|
|
733
|
+
# If showing Error Hyperlinks... Sometimes (when a syntax error, at least),
|
|
734
|
+
# the last File-Info line of a traceback is issued in multiple messages
|
|
735
|
+
# starting with unicode paragraph separator (r"\u2029") and followed by a
|
|
736
|
+
# newline, so our normal string checks search won't work. Instead, we'll
|
|
737
|
+
# manually reconstruct the line. If msg is a newline, grab that current line
|
|
738
|
+
# and check it. If it matches,proceed using that line as msg
|
|
739
|
+
cursor = self.textCursor()
|
|
740
|
+
info = None
|
|
741
|
+
|
|
742
|
+
if doHyperlink and msg == '\n':
|
|
743
|
+
cursor.select(QTextCursor.BlockUnderCursor)
|
|
744
|
+
line = cursor.selectedText()
|
|
745
|
+
|
|
746
|
+
# Remove possible leading unicode paragraph separator, which really
|
|
747
|
+
# messes up the works
|
|
748
|
+
if line and line[0] not in string.printable:
|
|
749
|
+
line = line[1:]
|
|
750
|
+
|
|
751
|
+
info = self.parseErrorHyperLinkInfo(line)
|
|
752
|
+
if info:
|
|
753
|
+
cursor.insertText("\n")
|
|
754
|
+
msg = "{}\n".format(line)
|
|
755
|
+
|
|
756
|
+
# If showing Error Hyperlinks, display underline output, otherwise
|
|
757
|
+
# display normal output. Exclude ConsolePrEdits
|
|
758
|
+
info = info if info else self.parseErrorHyperLinkInfo(msg)
|
|
759
|
+
filename = info.get("filename", "") if info else ""
|
|
760
|
+
isConsolePrEdit = '<ConsolePrEdit>' in filename
|
|
761
|
+
|
|
762
|
+
if info and doHyperlink and not isConsolePrEdit:
|
|
763
|
+
fileStart = info.get("fileStart")
|
|
764
|
+
fileEnd = info.get("fileEnd")
|
|
765
|
+
lineNum = info.get("lineNum")
|
|
766
|
+
|
|
767
|
+
isWorkbox = '<WorkboxSelection>' in filename or '<Workbox>' in filename
|
|
768
|
+
if isWorkbox:
|
|
769
|
+
split = filename.split(':')
|
|
770
|
+
workboxIdx = split[-1]
|
|
771
|
+
filename = ''
|
|
772
|
+
else:
|
|
773
|
+
filename = filename
|
|
774
|
+
workboxIdx = ''
|
|
775
|
+
href = '{}, {}, {}'.format(filename, workboxIdx, lineNum)
|
|
776
|
+
|
|
777
|
+
# Insert initial, non-underlined text
|
|
778
|
+
cursor.insertText(msg[:fileStart])
|
|
779
|
+
|
|
780
|
+
# Insert hyperlink
|
|
781
|
+
fmt = cursor.charFormat()
|
|
782
|
+
fmt.setAnchor(True)
|
|
783
|
+
fmt.setAnchorHref(href)
|
|
784
|
+
fmt.setFontUnderline(True)
|
|
785
|
+
toolTip = "Open {} at line number {}".format(filename, lineNum)
|
|
786
|
+
fmt.setToolTip(toolTip)
|
|
787
|
+
cursor.insertText(msg[fileStart:fileEnd], fmt)
|
|
788
|
+
|
|
789
|
+
# Insert the rest of the msg
|
|
790
|
+
fmt.setAnchor(False)
|
|
791
|
+
fmt.setAnchorHref('')
|
|
792
|
+
fmt.setFontUnderline(False)
|
|
793
|
+
fmt.setToolTip('')
|
|
794
|
+
cursor.insertText(msg[fileEnd:], fmt)
|
|
795
|
+
else:
|
|
796
|
+
# Non-hyperlink output
|
|
797
|
+
self.insertPlainText(msg)
|
|
798
|
+
|
|
799
|
+
# if a outputPipe was provided, write the message to that pipe
|
|
800
|
+
if self.outputPipe:
|
|
801
|
+
self.outputPipe(msg, error=error)
|