pyqt-code-editor 0.0.53__tar.gz → 0.0.55__tar.gz
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.
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/PKG-INFO +2 -2
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/__init__.py +1 -1
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/_settings.py +1 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/app.py +4 -0
- pyqt_code_editor-0.0.55/pyqt_code_editor/components/sigmund/__init__.py +1 -0
- pyqt_code_editor-0.0.55/pyqt_code_editor/components/sigmund/confirm_run_code_dialog.py +59 -0
- pyqt_code_editor-0.0.53/pyqt_code_editor/components/sigmund.py → pyqt_code_editor-0.0.55/pyqt_code_editor/components/sigmund/editor_workspace.py +5 -26
- pyqt_code_editor-0.0.55/pyqt_code_editor/components/sigmund/sigmund.py +28 -0
- pyqt_code_editor-0.0.55/pyqt_code_editor/components/sigmund/sigmund_analyst_chat_widget.py +35 -0
- pyqt_code_editor-0.0.55/pyqt_code_editor/components/sigmund/sigmund_analyst_widget.py +191 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/auto_pair.py +0 -1
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/base.py +4 -2
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/comment.py +4 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/merge_undo_actions.py +1 -6
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/search_replace.py +83 -28
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/readme.md +1 -1
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/COPYING +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyproject.toml +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/code_editors.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/generic.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/javascript.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/markdown.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/python.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/text.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/editor_panel.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/find_in_files.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/jupyter_console.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/project_explorer.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/settings_panel.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/workspace_explorer.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/environment_manager.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/auto_indent.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/check.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/complete.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/execute.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/file_link.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/highlight_matching_brackets.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/line_number.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/python_auto_indent.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/shortcuts.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/smart_backspace_delete.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/symbols.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/theme.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/widgets/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/zoom.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/sigmund-analyst.png +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/signal_router.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/syntax_highlighters/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/syntax_highlighters/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/syntax_highlighters/languages/generic.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/syntax_highlighters/languages/python.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/syntax_highlighters/syntax_highlighter.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/themes.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/languages/python/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/languages/python/_auto_indent.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/languages/python/_extract_cells.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/languages/python/_mask_str_in_code.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/watchdog.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/calltip_widget.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/completion_popup.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/dock.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/quick_open_dialog.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/quick_open_file_dialog.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/quick_symbol_dialog.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/search_replace_frame.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/tab_splitter.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/tabbed_editor.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/languages/generic.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/languages/python.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/manager.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/process.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/__init__.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/codestral.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/jedi.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/ruff.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/sigmund.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/symbol.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/tree_sitter.py +0 -0
- {pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyqt_code_editor
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.55
|
|
4
4
|
Summary: Fully featured code-editor widgets for PyQt
|
|
5
5
|
Keywords: code editor,pyqt,ide
|
|
6
6
|
Author-email: Sebastiaan Mathôt <s.mathot@cogsci.nl>
|
|
@@ -32,7 +32,7 @@ Project-URL: Source, https://github.com/open-cogsci/sigmund-analyst
|
|
|
32
32
|
|
|
33
33
|
# PyQt Code Editor / Sigmund Analyst
|
|
34
34
|
|
|
35
|
-
Copyright 2025 Sebastiaan Mathôt
|
|
35
|
+
Copyright 2025-2026 Sebastiaan Mathôt
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
## About
|
|
@@ -120,6 +120,7 @@ class Settings(QObject):
|
|
|
120
120
|
check_interval_delay = SettingProperty(5000, "Checking")
|
|
121
121
|
|
|
122
122
|
# Sigmund provider
|
|
123
|
+
sigmund_review_actions = SettingProperty(True, "Sigmund")
|
|
123
124
|
sigmund_max_context = SettingProperty(2000, "Sigmund")
|
|
124
125
|
sigmund_fim_endpoint = SettingProperty('http://localhost:5000/code_completion/fim', "Sigmund")
|
|
125
126
|
sigmund_token = SettingProperty(None, "Sigmund")
|
|
@@ -349,6 +349,10 @@ class SigmundAnalyst(QMainWindow):
|
|
|
349
349
|
self._jupyter_console.execute_code(code)
|
|
350
350
|
|
|
351
351
|
def _execute_file(self, path):
|
|
352
|
+
working_directory = os.path.dirname(path)
|
|
353
|
+
if os.path.isdir(working_directory):
|
|
354
|
+
self._jupyter_console.change_directory(working_directory)
|
|
355
|
+
self._toggle_dock_widget(self._jupyter_console, show=True)
|
|
352
356
|
self._jupyter_console.execute_file(path)
|
|
353
357
|
|
|
354
358
|
def _find_in_files(self):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .sigmund import Sigmund
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from qtpy.QtWidgets import QVBoxLayout, QDialogButtonBox, QLabel, \
|
|
2
|
+
QSizePolicy, QDialog, QSplitter
|
|
3
|
+
from qtpy.QtCore import Qt
|
|
4
|
+
import logging
|
|
5
|
+
from sigmund_qtwidget.chat_browser import ChatBrowser
|
|
6
|
+
from pyqt_code_editor.code_editors import create_editor
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
MAX_MESSAGE_HEIGHT = 200
|
|
11
|
+
|
|
12
|
+
class ConfirmRunCodeDialog(QDialog):
|
|
13
|
+
"""
|
|
14
|
+
A modal dialog that displays code to be executed and asks the user to confirm or cancel.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, parent, code: str, language: str):
|
|
18
|
+
super().__init__(parent)
|
|
19
|
+
|
|
20
|
+
self.setWindowTitle(f"Confirm {language} code execution")
|
|
21
|
+
|
|
22
|
+
layout = QVBoxLayout()
|
|
23
|
+
self.setLayout(layout)
|
|
24
|
+
|
|
25
|
+
# Use ChatBrowser to display the AI message
|
|
26
|
+
self.message_browser = ChatBrowser(self)
|
|
27
|
+
self.message_browser.append_message(
|
|
28
|
+
'ai', 'Sigmund wants to run the following code:')
|
|
29
|
+
self.message_browser.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
|
30
|
+
self.message_browser.setMaximumHeight(MAX_MESSAGE_HEIGHT)
|
|
31
|
+
|
|
32
|
+
# Create code editor for the code to be executed
|
|
33
|
+
self.code_view = create_editor(language=language)
|
|
34
|
+
self.code_view.setPlainText(code)
|
|
35
|
+
self.code_view.setReadOnly(True)
|
|
36
|
+
|
|
37
|
+
# Create a vertical splitter to hold the message browser and the code
|
|
38
|
+
splitter = QSplitter(Qt.Vertical)
|
|
39
|
+
splitter.addWidget(self.message_browser)
|
|
40
|
+
splitter.addWidget(self.code_view)
|
|
41
|
+
layout.addWidget(splitter)
|
|
42
|
+
|
|
43
|
+
# The disclaimer label
|
|
44
|
+
disclaimer_label = QLabel(
|
|
45
|
+
"Carefully review the code before execution. Executing code can have unintended consequences.",
|
|
46
|
+
self
|
|
47
|
+
)
|
|
48
|
+
disclaimer_label.setWordWrap(True)
|
|
49
|
+
disclaimer_label.setObjectName('control-warning')
|
|
50
|
+
disclaimer_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
51
|
+
layout.addWidget(disclaimer_label)
|
|
52
|
+
|
|
53
|
+
# Dialog buttons
|
|
54
|
+
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
55
|
+
self.button_box.accepted.connect(self.accept)
|
|
56
|
+
self.button_box.rejected.connect(self.reject)
|
|
57
|
+
layout.addWidget(self.button_box)
|
|
58
|
+
|
|
59
|
+
self.resize(800, 600)
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
from sigmund_qtwidget.sigmund_widget import SigmundWidget
|
|
2
|
-
from ..widgets import Dock
|
|
3
|
-
from .. import watchdog, settings
|
|
4
1
|
import textwrap
|
|
5
2
|
import logging
|
|
6
3
|
logger = logging.getLogger(__name__)
|
|
@@ -76,11 +73,14 @@ class EditorWorkspace:
|
|
|
76
73
|
|
|
77
74
|
def set(self, content, language):
|
|
78
75
|
text_cursor = self._editor.textCursor()
|
|
76
|
+
text_cursor.beginEditBlock()
|
|
79
77
|
if text_cursor.hasSelection():
|
|
80
78
|
text_cursor.insertText(content)
|
|
81
|
-
self._editor.setTextCursor(text_cursor)
|
|
82
79
|
else:
|
|
83
|
-
|
|
80
|
+
text_cursor.select(text_cursor.Document)
|
|
81
|
+
text_cursor.insertText(content)
|
|
82
|
+
text_cursor.endEditBlock()
|
|
83
|
+
self._editor.setTextCursor(text_cursor)
|
|
84
84
|
self._editor.set_modified(True)
|
|
85
85
|
|
|
86
86
|
def has_changed(self, content, language):
|
|
@@ -98,24 +98,3 @@ class EditorWorkspace:
|
|
|
98
98
|
if content is None:
|
|
99
99
|
return ''
|
|
100
100
|
return content
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class Sigmund(Dock):
|
|
104
|
-
def __init__(self, parent, editor_panel):
|
|
105
|
-
super().__init__('Sigmund', parent)
|
|
106
|
-
self.setObjectName("sigmund")
|
|
107
|
-
workspace = EditorWorkspace(editor_panel)
|
|
108
|
-
self.sigmund_widget = SigmundWidget(self, application='Sigmund Analyst')
|
|
109
|
-
self.sigmund_widget.setStyleSheet(f'font-size: {settings.font_size}pt')
|
|
110
|
-
self.sigmund_widget.set_workspace_manager(workspace)
|
|
111
|
-
self.setWidget(self.sigmund_widget)
|
|
112
|
-
|
|
113
|
-
def setVisible(self, visible):
|
|
114
|
-
if visible:
|
|
115
|
-
logger.info('starting sigmund connector')
|
|
116
|
-
self.sigmund_widget.start_server()
|
|
117
|
-
watchdog.register_subprocess(self.sigmund_widget.server_pid)
|
|
118
|
-
else:
|
|
119
|
-
logger.info('stopping sigmund connector')
|
|
120
|
-
self.sigmund_widget.stop_server()
|
|
121
|
-
super().setVisible(visible)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from ...widgets import Dock
|
|
2
|
+
from ... import watchdog, settings
|
|
3
|
+
from .editor_workspace import EditorWorkspace
|
|
4
|
+
from .sigmund_analyst_widget import SigmundAnalystWidget
|
|
5
|
+
import logging
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Sigmund(Dock):
|
|
10
|
+
def __init__(self, parent, editor_panel):
|
|
11
|
+
super().__init__('Sigmund', parent)
|
|
12
|
+
self.setObjectName("sigmund")
|
|
13
|
+
workspace = EditorWorkspace(editor_panel)
|
|
14
|
+
self.sigmund_widget = SigmundAnalystWidget(
|
|
15
|
+
self, editor_panel)
|
|
16
|
+
self.sigmund_widget.setStyleSheet(f'font-size: {settings.font_size}pt')
|
|
17
|
+
self.sigmund_widget.set_workspace_manager(workspace)
|
|
18
|
+
self.setWidget(self.sigmund_widget)
|
|
19
|
+
|
|
20
|
+
def setVisible(self, visible):
|
|
21
|
+
if visible:
|
|
22
|
+
logger.info('starting sigmund connector')
|
|
23
|
+
self.sigmund_widget.start_server()
|
|
24
|
+
watchdog.register_subprocess(self.sigmund_widget.server_pid)
|
|
25
|
+
else:
|
|
26
|
+
logger.info('stopping sigmund connector')
|
|
27
|
+
self.sigmund_widget.stop_server()
|
|
28
|
+
super().setVisible(visible)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from qtpy.QtWidgets import QCheckBox, QWidget, QVBoxLayout
|
|
2
|
+
from sigmund_qtwidget.chat_widget import ChatWidget
|
|
3
|
+
from ... import settings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SigmundAnalystChatWidget(ChatWidget):
|
|
7
|
+
"""Extended chat widget with Sigmund Analyst-specific options"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, parent=None):
|
|
10
|
+
super().__init__(parent)
|
|
11
|
+
# Create a container for the checkboxes
|
|
12
|
+
options_container = QWidget()
|
|
13
|
+
options_layout = QVBoxLayout(options_container)
|
|
14
|
+
options_layout.setContentsMargins(5, 5, 5, 5)
|
|
15
|
+
options_layout.setSpacing(2)
|
|
16
|
+
# "Review proposed changes" checkbox
|
|
17
|
+
self._review_actions_checkbox = QCheckBox(
|
|
18
|
+
"Review Sigmund's actions (recommended)")
|
|
19
|
+
self._review_actions_checkbox.setChecked(
|
|
20
|
+
settings.sigmund_review_actions)
|
|
21
|
+
self._review_actions_checkbox.stateChanged.connect(
|
|
22
|
+
self._on_review_actions_changed)
|
|
23
|
+
options_layout.addWidget(self._review_actions_checkbox)
|
|
24
|
+
# Insert the options container before the input container
|
|
25
|
+
main_layout = self.layout()
|
|
26
|
+
main_layout.insertWidget(main_layout.count(), options_container)
|
|
27
|
+
|
|
28
|
+
def _on_review_actions_changed(self, state):
|
|
29
|
+
"""Store the review changes setting."""
|
|
30
|
+
settings.sigmund_review_actions = bool(state)
|
|
31
|
+
|
|
32
|
+
def append_message(self, msg_type, text, scroll=True):
|
|
33
|
+
if msg_type == 'ai' and '(Suggesting IDE action)' in text:
|
|
34
|
+
text = '⚙️ Sigmund is working …'
|
|
35
|
+
self._chat_browser.append_message(msg_type, text, scroll)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
from sigmund_qtwidget.sigmund_widget import SigmundWidget
|
|
4
|
+
from qtpy.QtCore import QEventLoop, QTimer
|
|
5
|
+
from qtpy.QtWidgets import QMessageBox, QDialog
|
|
6
|
+
from .sigmund_analyst_chat_widget import SigmundAnalystChatWidget
|
|
7
|
+
from .confirm_run_code_dialog import ConfirmRunCodeDialog
|
|
8
|
+
from ... import settings
|
|
9
|
+
import logging
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
ACTION_CANCELLED = 'I do not approve this action.'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SigmundAnalystWidget(SigmundWidget):
|
|
16
|
+
"""Extends the default Sigmund widget with Sigmund Analyst-specific
|
|
17
|
+
functionality.
|
|
18
|
+
"""
|
|
19
|
+
chat_widget_cls = SigmundAnalystChatWidget
|
|
20
|
+
|
|
21
|
+
def __init__(self, parent, editor_panel):
|
|
22
|
+
super().__init__(parent, application='Sigmund Analyst')
|
|
23
|
+
try:
|
|
24
|
+
self._app = parent.parent()
|
|
25
|
+
self._jupyter_console = self._app._jupyter_console
|
|
26
|
+
# Connect the code_executed signal to a slot
|
|
27
|
+
except AttributeError:
|
|
28
|
+
logger.warning('No Jupyter console found.')
|
|
29
|
+
self._jupyter_console = None
|
|
30
|
+
else:
|
|
31
|
+
self._jupyter_console.execution_complete.connect(
|
|
32
|
+
self._handle_execution_result)
|
|
33
|
+
self._editor_panel = editor_panel
|
|
34
|
+
self._transient_settings = {
|
|
35
|
+
'tool_ide_open_file': 'true',
|
|
36
|
+
'tool_ide_execute_code': 'true'
|
|
37
|
+
}
|
|
38
|
+
# Store execution results
|
|
39
|
+
self._execution_result = None
|
|
40
|
+
self._execution_loop = None
|
|
41
|
+
|
|
42
|
+
def _confirm_action(self, action_type, details):
|
|
43
|
+
"""Show a confirmation dialog for the proposed action.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
action_type (str): Type of action (e.g., "open file", "execute code")
|
|
47
|
+
details (str): Detailed information about the action
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
bool: True if action is approved, False otherwise
|
|
51
|
+
"""
|
|
52
|
+
if not settings.sigmund_review_actions:
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
if action_type == "open file":
|
|
56
|
+
return QMessageBox.question(
|
|
57
|
+
self,
|
|
58
|
+
"Open file",
|
|
59
|
+
f"Sigmund wants to open: \n\n{details}",
|
|
60
|
+
QMessageBox.Ok | QMessageBox.Cancel,
|
|
61
|
+
QMessageBox.Ok
|
|
62
|
+
) == QMessageBox.Ok
|
|
63
|
+
dialog = ConfirmRunCodeDialog(
|
|
64
|
+
self,
|
|
65
|
+
action_type,
|
|
66
|
+
details
|
|
67
|
+
)
|
|
68
|
+
return dialog.exec_() == QDialog.Accepted
|
|
69
|
+
|
|
70
|
+
def _handle_execution_result(self, output, result):
|
|
71
|
+
"""Slot that handles the code_executed signal."""
|
|
72
|
+
self._execution_result = (output, result)
|
|
73
|
+
if self._execution_loop and self._execution_loop.isRunning():
|
|
74
|
+
time.sleep(0.5) # Wait for errors to appear
|
|
75
|
+
self._execution_loop.quit()
|
|
76
|
+
|
|
77
|
+
def run_command_open_file(self, path):
|
|
78
|
+
if settings.sigmund_review_actions:
|
|
79
|
+
if not QMessageBox.question(self,
|
|
80
|
+
"Confirm open file",
|
|
81
|
+
f"Sigmund wants to open: \n\n{path}",
|
|
82
|
+
QMessageBox.Ok | QMessageBox.Cancel,
|
|
83
|
+
QMessageBox.Ok) == QMessageBox.Ok:
|
|
84
|
+
return ACTION_CANCELLED
|
|
85
|
+
try:
|
|
86
|
+
self._editor_panel.open_file(path)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
return f'Failed to open file: {e}'
|
|
89
|
+
return f'Opened file: {path}'
|
|
90
|
+
|
|
91
|
+
def run_command_execute_code(self, code, language):
|
|
92
|
+
if settings.sigmund_review_actions:
|
|
93
|
+
if not ConfirmRunCodeDialog(self, code, language).exec() \
|
|
94
|
+
== ConfirmRunCodeDialog.Accepted:
|
|
95
|
+
return ACTION_CANCELLED
|
|
96
|
+
if self._jupyter_console is None:
|
|
97
|
+
return 'Code execution not supported.'
|
|
98
|
+
self._app._toggle_dock_widget(self._jupyter_console, show=True)
|
|
99
|
+
self._execution_result = None
|
|
100
|
+
self._execution_loop = QEventLoop()
|
|
101
|
+
QTimer.singleShot(30000, self._execution_loop.quit) # 30 second timeout
|
|
102
|
+
self._jupyter_console.execute_code(code)
|
|
103
|
+
self._execution_loop.exec_()
|
|
104
|
+
self._execution_loop = None
|
|
105
|
+
if self._execution_result is None:
|
|
106
|
+
return 'Code execution timed out or failed to return a result.'
|
|
107
|
+
try:
|
|
108
|
+
console_content = self._jupyter_console.get_current_console().jupyter_widget._control.toPlainText()
|
|
109
|
+
except Exception as e:
|
|
110
|
+
return f'Failed to get results from console content: {e}'
|
|
111
|
+
console_content = ''
|
|
112
|
+
console_content = '\n'.join(console_content.splitlines()[-100:])
|
|
113
|
+
return f'# Console output (may be truncated):\n\n{console_content}'
|
|
114
|
+
@property
|
|
115
|
+
def _editor(self):
|
|
116
|
+
return self._editor_panel.active_editor()
|
|
117
|
+
|
|
118
|
+
def send_user_message(self, text, *args, **kwargs):
|
|
119
|
+
current_path = self._editor.code_editor_file_path
|
|
120
|
+
# If the editor is not linked to a file, simply use the working
|
|
121
|
+
# directory.
|
|
122
|
+
if current_path is None:
|
|
123
|
+
current_path = '[unsaved file]'
|
|
124
|
+
working_directory = os.getcwd()
|
|
125
|
+
else:
|
|
126
|
+
working_directory = os.path.dirname(current_path)
|
|
127
|
+
|
|
128
|
+
# Initialize with default value
|
|
129
|
+
working_directory_contents = "(No directory contents available)"
|
|
130
|
+
|
|
131
|
+
# Get directory contents with priority to top-level items
|
|
132
|
+
top_level = []
|
|
133
|
+
all_items = []
|
|
134
|
+
|
|
135
|
+
# Only wrap file system operations in try-except
|
|
136
|
+
try:
|
|
137
|
+
# Get top-level items (depth=1)
|
|
138
|
+
top_level = [f for f in os.listdir(working_directory)
|
|
139
|
+
if os.path.isfile(os.path.join(working_directory, f))
|
|
140
|
+
or os.path.isdir(os.path.join(working_directory, f))]
|
|
141
|
+
|
|
142
|
+
# Then get deeper items if we haven't reached our limit
|
|
143
|
+
remaining_slots = max(0, 20 - len(top_level))
|
|
144
|
+
if remaining_slots > 0:
|
|
145
|
+
for root, dirs, files in os.walk(working_directory):
|
|
146
|
+
# Skip the top level since we already have it
|
|
147
|
+
if root == working_directory:
|
|
148
|
+
continue
|
|
149
|
+
# Add files first
|
|
150
|
+
for file in files:
|
|
151
|
+
if remaining_slots <= 0:
|
|
152
|
+
break
|
|
153
|
+
rel_path = os.path.relpath(os.path.join(root, file), working_directory)
|
|
154
|
+
all_items.append(f".\\{rel_path}")
|
|
155
|
+
remaining_slots -= 1
|
|
156
|
+
# Then add directories if we still have space
|
|
157
|
+
for dir in dirs:
|
|
158
|
+
if remaining_slots <= 0:
|
|
159
|
+
break
|
|
160
|
+
rel_path = os.path.relpath(os.path.join(root, dir), working_directory)
|
|
161
|
+
all_items.append(f".\\{rel_path}\\")
|
|
162
|
+
remaining_slots -= 1
|
|
163
|
+
|
|
164
|
+
# Combine top level and deeper items
|
|
165
|
+
working_directory_contents = "\n".join(
|
|
166
|
+
sorted([f".\\{item}" if os.path.isfile(os.path.join(working_directory, item))
|
|
167
|
+
else f".\\{item}\\" for item in top_level] +
|
|
168
|
+
all_items)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if len(top_level) + len(all_items) > 20:
|
|
172
|
+
working_directory_contents += "\n... (additional files truncated)"
|
|
173
|
+
|
|
174
|
+
except PermissionError:
|
|
175
|
+
working_directory_contents = "(Could not read some directory contents - permission denied)"
|
|
176
|
+
except OSError as e:
|
|
177
|
+
working_directory_contents = f"(Could not read directory contents: {str(e)})"
|
|
178
|
+
|
|
179
|
+
system_prompt = f'''## Working directory
|
|
180
|
+
|
|
181
|
+
The workspace corresponds to the following file: {current_path}
|
|
182
|
+
The working directory is: {working_directory}
|
|
183
|
+
|
|
184
|
+
Overview of working directory:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
{working_directory_contents}
|
|
188
|
+
```
|
|
189
|
+
'''
|
|
190
|
+
self._transient_system_prompt = system_prompt
|
|
191
|
+
super().send_user_message(text, *args, **kwargs)
|
|
@@ -106,7 +106,9 @@ class Base:
|
|
|
106
106
|
if the worker died or the result queue is empty, keep polling.
|
|
107
107
|
"""
|
|
108
108
|
to_remove = []
|
|
109
|
-
|
|
109
|
+
# Create a list of active requests to avoid the dictionary being
|
|
110
|
+
# changed during iteration
|
|
111
|
+
for pid, queue in list(self._active_requests.items()):
|
|
110
112
|
# 1) Check if the worker is still alive
|
|
111
113
|
if not manager.check_worker_alive(pid):
|
|
112
114
|
logger.warning(f"Worker process {pid} no longer alive. Removing from active requests.")
|
|
@@ -143,7 +145,7 @@ class Base:
|
|
|
143
145
|
# Cleanup: remove completed or dead requests. Also stop unused workers.
|
|
144
146
|
# This function periodically prunes worker processes if they are unused.
|
|
145
147
|
for pid in to_remove:
|
|
146
|
-
self._active_requests.pop(pid, None)
|
|
148
|
+
self._active_requests.pop(pid, None)
|
|
147
149
|
manager.stop_unused_workers()
|
|
148
150
|
|
|
149
151
|
def set_modified(self, modified):
|
|
@@ -44,6 +44,7 @@ class Comment:
|
|
|
44
44
|
def _toggle_comment(self):
|
|
45
45
|
"""Toggle comment on the current selection or current line."""
|
|
46
46
|
cursor = self.textCursor()
|
|
47
|
+
cursor.beginEditBlock()
|
|
47
48
|
if not cursor.hasSelection():
|
|
48
49
|
# If no selection, just operate on the current line
|
|
49
50
|
cursor.select(cursor.LineUnderCursor)
|
|
@@ -70,6 +71,7 @@ class Comment:
|
|
|
70
71
|
self._uncomment_blocks(startBlock, endBlock)
|
|
71
72
|
else:
|
|
72
73
|
self._comment_blocks(startBlock, endBlock)
|
|
74
|
+
cursor.endEditBlock()
|
|
73
75
|
|
|
74
76
|
def _comment_blocks(self, start_block: int, end_block: int):
|
|
75
77
|
"""Comment all lines from start_block to end_block."""
|
|
@@ -84,6 +86,7 @@ class Comment:
|
|
|
84
86
|
insert_position = block.position() + leading_spaces
|
|
85
87
|
cursor.setPosition(insert_position)
|
|
86
88
|
cursor.insertText(self.code_editor_comment_string)
|
|
89
|
+
self.setTextCursor(cursor)
|
|
87
90
|
|
|
88
91
|
def _uncomment_blocks(self, start_block: int, end_block: int):
|
|
89
92
|
"""Uncomment all lines from start_block to end_block."""
|
|
@@ -102,3 +105,4 @@ class Comment:
|
|
|
102
105
|
cursor.setPosition(remove_position + strip_len, cursor.KeepAnchor)
|
|
103
106
|
if cursor.selectedText() == self.code_editor_comment_string.rstrip('\r\n'):
|
|
104
107
|
cursor.removeSelectedText()
|
|
108
|
+
self.setTextCursor(cursor)
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/merge_undo_actions.py
RENAMED
|
@@ -20,11 +20,6 @@ class MergeUndoActions:
|
|
|
20
20
|
key = event.key()
|
|
21
21
|
modifiers = event.modifiers()
|
|
22
22
|
|
|
23
|
-
is_navigation = (
|
|
24
|
-
key in navigation_keys
|
|
25
|
-
and not (modifiers & Qt.KeyboardModifier.ShiftModifier)
|
|
26
|
-
)
|
|
27
|
-
|
|
28
23
|
# Treat platform "command" modifier as well (Control on Windows/Linux, Meta on macOS)
|
|
29
24
|
ctrl_or_meta = Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.MetaModifier
|
|
30
25
|
has_ctrl_or_meta = bool(modifiers & ctrl_or_meta)
|
|
@@ -39,7 +34,7 @@ class MergeUndoActions:
|
|
|
39
34
|
key == Qt.Key.Key_Y
|
|
40
35
|
)
|
|
41
36
|
|
|
42
|
-
if
|
|
37
|
+
if key in navigation_keys or is_undo or is_redo:
|
|
43
38
|
# Do not wrap these in an edit block
|
|
44
39
|
super().keyPressEvent(event)
|
|
45
40
|
return
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/search_replace.py
RENAMED
|
@@ -8,10 +8,9 @@ from qtpy.QtCore import Qt
|
|
|
8
8
|
from .. import settings
|
|
9
9
|
from ..widgets.search_replace_frame import SearchReplaceFrame
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
class SearchReplaceHighlighter(QSyntaxHighlighter):
|
|
13
12
|
"""
|
|
14
|
-
|
|
13
|
+
Syntax highlighter that highlights all matches of a given pattern.
|
|
15
14
|
Updated whenever the pattern or text changes.
|
|
16
15
|
"""
|
|
17
16
|
def __init__(self, parent=None):
|
|
@@ -20,46 +19,87 @@ class SearchReplaceHighlighter(QSyntaxHighlighter):
|
|
|
20
19
|
self._use_regex = False
|
|
21
20
|
self._case_sensitive = False
|
|
22
21
|
self._whole_word = False
|
|
23
|
-
|
|
22
|
+
self._matches = [] # Stores all matches in the document as (block_number, start, length)
|
|
23
|
+
|
|
24
24
|
# Highlight style
|
|
25
25
|
self.highlight_format = QTextCharFormat()
|
|
26
26
|
self.highlight_format.setBackground(QColor(settings.search_replace_background))
|
|
27
27
|
self.highlight_format.setForeground(QColor(settings.search_replace_foreground))
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
def setSearchOptions(self, pattern, use_regex, case_sensitive, whole_word):
|
|
30
30
|
self._pattern = pattern
|
|
31
31
|
self._use_regex = use_regex
|
|
32
32
|
self._case_sensitive = case_sensitive
|
|
33
33
|
self._whole_word = whole_word
|
|
34
34
|
self.rehighlight() # Trigger a re-scan
|
|
35
|
-
|
|
36
|
-
def
|
|
37
|
-
|
|
35
|
+
|
|
36
|
+
def rehighlight(self):
|
|
37
|
+
"""Find all matches in the entire document and store them"""
|
|
38
|
+
if not self._pattern or not self.document():
|
|
39
|
+
self._matches = []
|
|
40
|
+
super().rehighlight()
|
|
38
41
|
return
|
|
39
|
-
|
|
42
|
+
|
|
40
43
|
# Build the pattern
|
|
41
44
|
pattern = self._pattern
|
|
42
45
|
flags = 0 if self._case_sensitive else re.IGNORECASE
|
|
43
|
-
|
|
46
|
+
|
|
44
47
|
if self._use_regex:
|
|
45
|
-
# If whole_word is asked for, add \b on both sides (can be tricky with punctuation).
|
|
46
48
|
if self._whole_word:
|
|
47
49
|
pattern = rf"\b{pattern}\b"
|
|
48
50
|
try:
|
|
49
51
|
regex = re.compile(pattern, flags)
|
|
50
52
|
except re.error:
|
|
51
|
-
|
|
53
|
+
self._matches = []
|
|
54
|
+
super().rehighlight()
|
|
55
|
+
return
|
|
52
56
|
else:
|
|
53
|
-
# Escape user text if not in regex mode
|
|
54
57
|
pattern = re.escape(pattern)
|
|
55
58
|
if self._whole_word:
|
|
56
59
|
pattern = rf"\b{pattern}\b"
|
|
57
60
|
regex = re.compile(pattern, flags)
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
|
|
62
|
+
# Find all matches in the entire document
|
|
63
|
+
self._matches = []
|
|
64
|
+
full_text = self.document().toPlainText()
|
|
65
|
+
for match in regex.finditer(full_text):
|
|
60
66
|
start = match.start()
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
end = match.end()
|
|
68
|
+
|
|
69
|
+
# Convert character positions to block/position
|
|
70
|
+
block = self.document().findBlock(start)
|
|
71
|
+
block_number = block.blockNumber()
|
|
72
|
+
block_start = block.position()
|
|
73
|
+
block_end = block_start + block.length() - 1
|
|
74
|
+
|
|
75
|
+
# Handle matches that span multiple blocks
|
|
76
|
+
while start <= block_end and end > block_start:
|
|
77
|
+
match_start_in_block = max(start - block_start, 0)
|
|
78
|
+
match_end_in_block = min(end - block_start, block.length() - 1)
|
|
79
|
+
match_length = match_end_in_block - match_start_in_block
|
|
80
|
+
|
|
81
|
+
if match_length > 0:
|
|
82
|
+
self._matches.append((block_number, match_start_in_block, match_length))
|
|
83
|
+
|
|
84
|
+
# Move to next block if match spans multiple blocks
|
|
85
|
+
if end > block_end:
|
|
86
|
+
block = block.next()
|
|
87
|
+
if not block.isValid():
|
|
88
|
+
break
|
|
89
|
+
block_number = block.blockNumber()
|
|
90
|
+
block_start = block.position()
|
|
91
|
+
block_end = block_start + block.length() - 1
|
|
92
|
+
else:
|
|
93
|
+
break
|
|
94
|
+
|
|
95
|
+
super().rehighlight()
|
|
96
|
+
|
|
97
|
+
def highlightBlock(self, text):
|
|
98
|
+
"""Highlight matches that belong to this block"""
|
|
99
|
+
block_number = self.currentBlock().blockNumber()
|
|
100
|
+
for match_block, start, length in self._matches:
|
|
101
|
+
if match_block == block_number:
|
|
102
|
+
self.setFormat(start, length, self.highlight_format)
|
|
63
103
|
|
|
64
104
|
|
|
65
105
|
class SearchReplace:
|
|
@@ -325,13 +365,14 @@ class SearchReplace:
|
|
|
325
365
|
needle = self._searchFrame.findEdit.text()
|
|
326
366
|
if not needle:
|
|
327
367
|
return
|
|
328
|
-
|
|
368
|
+
|
|
329
369
|
replacement = self._searchFrame.replaceEdit.text()
|
|
330
|
-
|
|
331
|
-
# Save cursor
|
|
370
|
+
|
|
371
|
+
# Save cursor and get current text
|
|
332
372
|
saved_cursor = self.textCursor()
|
|
373
|
+
cursor_pos = saved_cursor.position()
|
|
333
374
|
text = self.toPlainText()
|
|
334
|
-
|
|
375
|
+
|
|
335
376
|
# Build regex pattern
|
|
336
377
|
flags = 0 if self._searchFrame.caseBox.isChecked() else re.IGNORECASE
|
|
337
378
|
patt = needle
|
|
@@ -339,20 +380,34 @@ class SearchReplace:
|
|
|
339
380
|
patt = re.escape(patt)
|
|
340
381
|
if self._searchFrame.wholeWordBox.isChecked():
|
|
341
382
|
patt = rf"\b{patt}\b"
|
|
342
|
-
|
|
383
|
+
|
|
343
384
|
try:
|
|
344
385
|
compiled = re.compile(patt, flags)
|
|
345
386
|
except re.error:
|
|
346
387
|
return
|
|
347
|
-
|
|
388
|
+
|
|
389
|
+
# Get text before cursor
|
|
390
|
+
text_before = text[:cursor_pos]
|
|
391
|
+
|
|
392
|
+
# Apply replacement to full text
|
|
348
393
|
new_text, num_replacements = compiled.subn(replacement, text)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
394
|
+
|
|
395
|
+
# Apply replacement to just the before portion to calculate position change
|
|
396
|
+
new_text_before, _ = compiled.subn(replacement, text_before)
|
|
397
|
+
length_change = len(new_text_before) - len(text_before)
|
|
398
|
+
new_cursor_pos = cursor_pos + length_change
|
|
399
|
+
|
|
400
|
+
# Use a single undoable operation
|
|
401
|
+
cursor = self.textCursor()
|
|
402
|
+
cursor.beginEditBlock()
|
|
403
|
+
cursor.select(QTextCursor.Document)
|
|
404
|
+
cursor.insertText(new_text)
|
|
405
|
+
cursor.setPosition(new_cursor_pos)
|
|
406
|
+
cursor.endEditBlock()
|
|
407
|
+
self.setTextCursor(cursor)
|
|
408
|
+
|
|
409
|
+
# Update UI
|
|
352
410
|
self._searchFrame.findEdit.setText(replacement)
|
|
353
|
-
|
|
354
|
-
# Restore cursor
|
|
355
|
-
self.setTextCursor(saved_cursor)
|
|
356
411
|
self.updateHighlighter()
|
|
357
412
|
self.set_modified(True)
|
|
358
413
|
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/__init__.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/code_editors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/code_editors/languages/text.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/editor_panel.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/find_in_files.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/jupyter_console.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/project_explorer.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/components/settings_panel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/python_auto_indent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/mixins/widgets/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/syntax_highlighters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/utils/languages/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/calltip_widget.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/completion_popup.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/quick_open_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/quick_symbol_dialog.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/search_replace_frame.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/tab_splitter.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/widgets/tabbed_editor.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/languages/__init__.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/languages/generic.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/languages/python.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/__init__.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/codestral.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/jedi.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/ruff.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/sigmund.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/symbol.py
RENAMED
|
File without changes
|
{pyqt_code_editor-0.0.53 → pyqt_code_editor-0.0.55}/pyqt_code_editor/worker/providers/tree_sitter.py
RENAMED
|
File without changes
|
|
File without changes
|