pyqt-code-editor 0.0.58__tar.gz → 0.0.60__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.
Files changed (91) hide show
  1. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/PKG-INFO +1 -1
  2. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/__init__.py +1 -1
  3. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/sigmund/sigmund_analyst_chat_widget.py +1 -1
  4. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/sigmund/sigmund_analyst_widget.py +77 -4
  5. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/search_replace.py +8 -1
  6. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/COPYING +0 -0
  7. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyproject.toml +0 -0
  8. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/_settings.py +0 -0
  9. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/app.py +0 -0
  10. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/__init__.py +0 -0
  11. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/code_editors.py +0 -0
  12. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/languages/__init__.py +0 -0
  13. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/languages/generic.py +0 -0
  14. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/languages/javascript.py +0 -0
  15. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/languages/markdown.py +0 -0
  16. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/languages/python.py +0 -0
  17. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/code_editors/languages/text.py +0 -0
  18. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/__init__.py +0 -0
  19. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/editor_panel.py +0 -0
  20. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/find_in_files.py +0 -0
  21. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/jupyter_console/__init__.py +0 -0
  22. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/jupyter_console/jupyter_console.py +0 -0
  23. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/jupyter_console/jupyter_console_tab.py +0 -0
  24. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/jupyter_console/kernel_spec_manager.py +0 -0
  25. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/project_explorer.py +0 -0
  26. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/settings_panel.py +0 -0
  27. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/sigmund/__init__.py +0 -0
  28. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/sigmund/confirm_run_code_dialog.py +0 -0
  29. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/sigmund/editor_workspace.py +0 -0
  30. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/sigmund/sigmund.py +0 -0
  31. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/components/workspace_explorer.py +0 -0
  32. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/environment_manager.py +0 -0
  33. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/__init__.py +0 -0
  34. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/auto_indent.py +0 -0
  35. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/auto_pair.py +0 -0
  36. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/base.py +0 -0
  37. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/check.py +0 -0
  38. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/comment.py +0 -0
  39. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/complete.py +0 -0
  40. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/execute.py +0 -0
  41. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/file_link.py +0 -0
  42. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/highlight_matching_brackets.py +0 -0
  43. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/line_number.py +0 -0
  44. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/merge_undo_actions.py +0 -0
  45. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/python_auto_indent.py +0 -0
  46. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/shortcuts.py +0 -0
  47. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/smart_backspace_delete.py +0 -0
  48. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/symbols.py +0 -0
  49. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/theme.py +0 -0
  50. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/widgets/__init__.py +0 -0
  51. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/mixins/zoom.py +0 -0
  52. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/sigmund-analyst.png +0 -0
  53. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/signal_router.py +0 -0
  54. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/syntax_highlighters/__init__.py +0 -0
  55. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/syntax_highlighters/languages/__init__.py +0 -0
  56. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/syntax_highlighters/languages/generic.py +0 -0
  57. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/syntax_highlighters/languages/python.py +0 -0
  58. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/syntax_highlighters/syntax_highlighter.py +0 -0
  59. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/themes.py +0 -0
  60. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/utils/__init__.py +0 -0
  61. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/utils/languages/__init__.py +0 -0
  62. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/utils/languages/python/__init__.py +0 -0
  63. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/utils/languages/python/_auto_indent.py +0 -0
  64. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/utils/languages/python/_extract_cells.py +0 -0
  65. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/utils/languages/python/_mask_str_in_code.py +0 -0
  66. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/watchdog.py +0 -0
  67. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/__init__.py +0 -0
  68. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/calltip_widget.py +0 -0
  69. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/completion_popup.py +0 -0
  70. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/dock.py +0 -0
  71. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/quick_open_dialog.py +0 -0
  72. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/quick_open_file_dialog.py +0 -0
  73. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/quick_symbol_dialog.py +0 -0
  74. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/search_replace_frame.py +0 -0
  75. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/tab_splitter.py +0 -0
  76. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/widgets/tabbed_editor.py +0 -0
  77. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/__init__.py +0 -0
  78. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/languages/__init__.py +0 -0
  79. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/languages/generic.py +0 -0
  80. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/languages/python.py +0 -0
  81. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/manager.py +0 -0
  82. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/process.py +0 -0
  83. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/__init__.py +0 -0
  84. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/codestral.py +0 -0
  85. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/jedi.py +0 -0
  86. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/ruff.py +0 -0
  87. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/sigmund.py +0 -0
  88. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/symbol.py +0 -0
  89. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/providers/tree_sitter.py +0 -0
  90. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/pyqt_code_editor/worker/settings.py +0 -0
  91. {pyqt_code_editor-0.0.58 → pyqt_code_editor-0.0.60}/readme.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqt_code_editor
3
- Version: 0.0.58
3
+ Version: 0.0.60
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>
@@ -2,4 +2,4 @@
2
2
 
3
3
  from ._settings import settings
4
4
 
5
- __version__ = '0.0.58'
5
+ __version__ = '0.0.60'
@@ -61,5 +61,5 @@ class SigmundAnalystChatWidget(ChatWidget):
61
61
 
62
62
  def append_message(self, msg_type, text, scroll=True):
63
63
  if msg_type == 'ai' and '(Suggesting IDE action)' in text:
64
- text = '⚙️ Sigmund is working …'
64
+ text = f'⚙️ Sigmund is working …\n\n{text}'
65
65
  self._chat_browser.append_message(msg_type, text, scroll)
@@ -33,13 +33,23 @@ class SigmundAnalystWidget(SigmundWidget):
33
33
  self._editor_panel = editor_panel
34
34
  self._transient_settings = {
35
35
  'tool_ide_open_file': 'true',
36
- 'tool_ide_execute_code': 'true'
36
+ 'tool_ide_execute_code': 'true',
37
+ 'tool_ide_inspect_files': 'true',
38
+ 'tool_ide_list_files': 'true'
37
39
  }
38
40
  # Store execution results
39
41
  self._execution_result = None
40
42
  self._execution_loop = None
41
43
  self._working_directory = None
42
44
 
45
+ def _resolve_path(self, path):
46
+ """Resolve a path relative to the current working directory.
47
+ Absolute paths are returned unchanged.
48
+ """
49
+ if self._working_directory is not None and not os.path.isabs(path):
50
+ return os.path.join(self._working_directory, path)
51
+ return path
52
+
43
53
  def _confirm_action(self, action_type, details):
44
54
  """Show a confirmation dialog for the proposed action.
45
55
 
@@ -75,6 +85,7 @@ class SigmundAnalystWidget(SigmundWidget):
75
85
  self._execution_loop.quit()
76
86
 
77
87
  def run_command_open_file(self, path):
88
+ path = self._resolve_path(path)
78
89
  if settings.sigmund_review_actions:
79
90
  if not QMessageBox.question(self,
80
91
  "Confirm open file",
@@ -89,7 +100,67 @@ class SigmundAnalystWidget(SigmundWidget):
89
100
  return f'Failed to open file: {e}'
90
101
  return f'Opened file: {path}'
91
102
 
92
- def run_command_execute_code(self, code, language):
103
+ def run_command_inspect_files(self, paths, encoding='utf-8'):
104
+ results = []
105
+ for path in paths:
106
+ path = self._resolve_path(path)
107
+ try:
108
+ with open(path, 'r', encoding=encoding) as f:
109
+ contents = f.read()
110
+ results.append(f'<file path="{path}">\n{contents}\n</file>')
111
+ except FileNotFoundError:
112
+ results.append(f'<file path="{path}" error="File not found" />')
113
+ except Exception as e:
114
+ results.append(f'<file path="{path}" error="{e}" />')
115
+ return '\n\n'.join(results)
116
+
117
+ def run_command_list_files(self, path, recursive=False, max_files=250):
118
+ path = self._resolve_path(path)
119
+ lines = []
120
+ try:
121
+ if recursive:
122
+ entries = list(os.walk(path))
123
+ else:
124
+ entries = sorted(os.scandir(path), key=lambda e: e.name)
125
+ except FileNotFoundError:
126
+ return f'Directory not found: {path}'
127
+ except PermissionError:
128
+ return f'Permission denied: {path}'
129
+ except Exception as e:
130
+ return f'Failed to list files: {e}'
131
+ truncated = False
132
+ if recursive:
133
+ for root, dirs, files in entries:
134
+ rel_root = os.path.relpath(root, path)
135
+ prefix = '' if rel_root == '.' else rel_root + os.sep
136
+ for d in sorted(dirs):
137
+ lines.append(f'{prefix}{d}{os.sep}')
138
+ if len(lines) >= max_files:
139
+ truncated = True
140
+ break
141
+ if truncated:
142
+ break
143
+ for f in sorted(files):
144
+ lines.append(f'{prefix}{f}')
145
+ if len(lines) >= max_files:
146
+ truncated = True
147
+ break
148
+ if truncated:
149
+ break
150
+ else:
151
+ for entry in entries:
152
+ lines.append(entry.name + (os.sep if entry.is_dir() else ''))
153
+ if len(lines) >= max_files:
154
+ truncated = True
155
+ break
156
+ if not lines:
157
+ return f'Directory is empty: {path}'
158
+ result = '\n'.join(lines)
159
+ if truncated:
160
+ result += f'\n(truncated at {max_files} entries)'
161
+ return result
162
+
163
+ def run_command_execute_code(self, code, language='python'):
93
164
  if settings.sigmund_review_actions:
94
165
  if not ConfirmRunCodeDialog(self, code, language).exec() \
95
166
  == ConfirmRunCodeDialog.Accepted:
@@ -139,7 +210,7 @@ class SigmundAnalystWidget(SigmundWidget):
139
210
  @property
140
211
  def _editor(self):
141
212
  return self._editor_panel.active_editor()
142
-
213
+
143
214
  def send_user_message(self, text, *args, **kwargs):
144
215
  current_path = self._editor.code_editor_file_path
145
216
  # If the editor is not linked to a file, simply use the working
@@ -202,6 +273,8 @@ class SigmundAnalystWidget(SigmundWidget):
202
273
  working_directory_contents = f"(Could not read directory contents: {str(e)})"
203
274
 
204
275
  system_prompt = f'''## Working directory
276
+
277
+ IMPORTANT: Do NOT call inspect_files() with {current_path}, because it is already in the workspace.
205
278
 
206
279
  The workspace corresponds to the following file: {current_path}
207
280
  The working directory is: {working_directory}
@@ -215,4 +288,4 @@ Overview of working directory:
215
288
  self._transient_system_prompt = system_prompt
216
289
  self._working_directory = working_directory
217
290
  super().send_user_message(text, *args, **kwargs)
218
- self._attachments = None
291
+ self._attachments = None
@@ -5,8 +5,11 @@ from qtpy.QtGui import (
5
5
  QTextCursor, QKeySequence, QTextDocument
6
6
  )
7
7
  from qtpy.QtCore import Qt
8
+ import logging
8
9
  from .. import settings
9
10
  from ..widgets.search_replace_frame import SearchReplaceFrame
11
+ logger = logging.getLogger(__name__)
12
+
10
13
 
11
14
  class SearchReplaceHighlighter(QSyntaxHighlighter):
12
15
  """
@@ -390,7 +393,11 @@ class SearchReplace:
390
393
  text_before = text[:cursor_pos]
391
394
 
392
395
  # Apply replacement to full text
393
- new_text, num_replacements = compiled.subn(replacement, text)
396
+ try:
397
+ new_text, num_replacements = compiled.subn(replacement, text)
398
+ except re.error as e:
399
+ logging.error(f"Regex error during replacement: {e}")
400
+ return
394
401
 
395
402
  # Apply replacement to just the before portion to calculate position change
396
403
  new_text_before, _ = compiled.subn(replacement, text_before)