pyqt-code-editor 0.0.59__tar.gz → 0.0.61__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.59 → pyqt_code_editor-0.0.61}/PKG-INFO +1 -1
  2. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/__init__.py +1 -1
  3. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/sigmund/sigmund_analyst_chat_widget.py +1 -1
  4. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/sigmund/sigmund_analyst_widget.py +68 -1
  5. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/search_replace.py +8 -1
  6. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/COPYING +0 -0
  7. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyproject.toml +0 -0
  8. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/_settings.py +0 -0
  9. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/app.py +0 -0
  10. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/__init__.py +0 -0
  11. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/code_editors.py +0 -0
  12. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/languages/__init__.py +0 -0
  13. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/languages/generic.py +0 -0
  14. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/languages/javascript.py +0 -0
  15. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/languages/markdown.py +0 -0
  16. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/languages/python.py +0 -0
  17. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/code_editors/languages/text.py +0 -0
  18. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/__init__.py +0 -0
  19. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/editor_panel.py +0 -0
  20. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/find_in_files.py +0 -0
  21. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/jupyter_console/__init__.py +0 -0
  22. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/jupyter_console/jupyter_console.py +0 -0
  23. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/jupyter_console/jupyter_console_tab.py +0 -0
  24. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/jupyter_console/kernel_spec_manager.py +0 -0
  25. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/project_explorer.py +0 -0
  26. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/settings_panel.py +0 -0
  27. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/sigmund/__init__.py +0 -0
  28. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/sigmund/confirm_run_code_dialog.py +0 -0
  29. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/sigmund/editor_workspace.py +0 -0
  30. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/sigmund/sigmund.py +0 -0
  31. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/components/workspace_explorer.py +0 -0
  32. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/environment_manager.py +0 -0
  33. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/__init__.py +0 -0
  34. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/auto_indent.py +0 -0
  35. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/auto_pair.py +0 -0
  36. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/base.py +0 -0
  37. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/check.py +0 -0
  38. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/comment.py +0 -0
  39. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/complete.py +0 -0
  40. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/execute.py +0 -0
  41. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/file_link.py +0 -0
  42. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/highlight_matching_brackets.py +0 -0
  43. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/line_number.py +0 -0
  44. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/merge_undo_actions.py +0 -0
  45. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/python_auto_indent.py +0 -0
  46. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/shortcuts.py +0 -0
  47. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/smart_backspace_delete.py +0 -0
  48. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/symbols.py +0 -0
  49. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/theme.py +0 -0
  50. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/widgets/__init__.py +0 -0
  51. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/mixins/zoom.py +0 -0
  52. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/sigmund-analyst.png +0 -0
  53. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/signal_router.py +0 -0
  54. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/syntax_highlighters/__init__.py +0 -0
  55. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/syntax_highlighters/languages/__init__.py +0 -0
  56. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/syntax_highlighters/languages/generic.py +0 -0
  57. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/syntax_highlighters/languages/python.py +0 -0
  58. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/syntax_highlighters/syntax_highlighter.py +0 -0
  59. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/themes.py +0 -0
  60. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/utils/__init__.py +0 -0
  61. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/utils/languages/__init__.py +0 -0
  62. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/utils/languages/python/__init__.py +0 -0
  63. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/utils/languages/python/_auto_indent.py +0 -0
  64. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/utils/languages/python/_extract_cells.py +0 -0
  65. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/utils/languages/python/_mask_str_in_code.py +0 -0
  66. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/watchdog.py +0 -0
  67. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/__init__.py +0 -0
  68. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/calltip_widget.py +0 -0
  69. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/completion_popup.py +0 -0
  70. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/dock.py +0 -0
  71. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/quick_open_dialog.py +0 -0
  72. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/quick_open_file_dialog.py +0 -0
  73. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/quick_symbol_dialog.py +0 -0
  74. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/search_replace_frame.py +0 -0
  75. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/tab_splitter.py +0 -0
  76. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/widgets/tabbed_editor.py +0 -0
  77. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/__init__.py +0 -0
  78. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/languages/__init__.py +0 -0
  79. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/languages/generic.py +0 -0
  80. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/languages/python.py +0 -0
  81. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/manager.py +0 -0
  82. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/process.py +0 -0
  83. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/__init__.py +0 -0
  84. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/codestral.py +0 -0
  85. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/jedi.py +0 -0
  86. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/ruff.py +0 -0
  87. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/sigmund.py +0 -0
  88. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/symbol.py +0 -0
  89. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/providers/tree_sitter.py +0 -0
  90. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/pyqt_code_editor/worker/settings.py +0 -0
  91. {pyqt_code_editor-0.0.59 → pyqt_code_editor-0.0.61}/readme.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqt_code_editor
3
- Version: 0.0.59
3
+ Version: 0.0.61
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.59'
5
+ __version__ = '0.0.61'
@@ -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)
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import subprocess
2
3
  import time
3
4
  from sigmund_qtwidget.sigmund_widget import SigmundWidget
4
5
  from qtpy.QtCore import QEventLoop, QTimer
@@ -35,13 +36,23 @@ class SigmundAnalystWidget(SigmundWidget):
35
36
  'tool_ide_open_file': 'true',
36
37
  'tool_ide_execute_code': 'true',
37
38
  'tool_ide_inspect_files': 'true',
38
- 'tool_ide_list_files': 'true'
39
+ 'tool_ide_list_files': 'true',
40
+ 'tool_ide_write_file': 'true',
41
+ 'tool_ide_execute_shell_command': 'true'
39
42
  }
40
43
  # Store execution results
41
44
  self._execution_result = None
42
45
  self._execution_loop = None
43
46
  self._working_directory = None
44
47
 
48
+ def _resolve_path(self, path):
49
+ """Resolve a path relative to the current working directory.
50
+ Absolute paths are returned unchanged.
51
+ """
52
+ if self._working_directory is not None and not os.path.isabs(path):
53
+ return os.path.join(self._working_directory, path)
54
+ return path
55
+
45
56
  def _confirm_action(self, action_type, details):
46
57
  """Show a confirmation dialog for the proposed action.
47
58
 
@@ -77,6 +88,7 @@ class SigmundAnalystWidget(SigmundWidget):
77
88
  self._execution_loop.quit()
78
89
 
79
90
  def run_command_open_file(self, path):
91
+ path = self._resolve_path(path)
80
92
  if settings.sigmund_review_actions:
81
93
  if not QMessageBox.question(self,
82
94
  "Confirm open file",
@@ -94,6 +106,7 @@ class SigmundAnalystWidget(SigmundWidget):
94
106
  def run_command_inspect_files(self, paths, encoding='utf-8'):
95
107
  results = []
96
108
  for path in paths:
109
+ path = self._resolve_path(path)
97
110
  try:
98
111
  with open(path, 'r', encoding=encoding) as f:
99
112
  contents = f.read()
@@ -105,6 +118,7 @@ class SigmundAnalystWidget(SigmundWidget):
105
118
  return '\n\n'.join(results)
106
119
 
107
120
  def run_command_list_files(self, path, recursive=False, max_files=250):
121
+ path = self._resolve_path(path)
108
122
  lines = []
109
123
  try:
110
124
  if recursive:
@@ -194,6 +208,57 @@ class SigmundAnalystWidget(SigmundWidget):
194
208
  <output>
195
209
  {self._execution_result[0]}
196
210
  </output>
211
+ '''
212
+
213
+ def run_command_write_file(self, path, content, encoding='utf-8'):
214
+ path = self._resolve_path(path)
215
+ language = os.path.splitext(path)[1].lstrip('.') or 'text'
216
+ if settings.sigmund_review_actions:
217
+ if not ConfirmRunCodeDialog(self, content, language).exec() \
218
+ == ConfirmRunCodeDialog.Accepted:
219
+ return ACTION_CANCELLED
220
+ try:
221
+ dir_name = os.path.dirname(path)
222
+ if dir_name:
223
+ os.makedirs(dir_name, exist_ok=True)
224
+ with open(path, 'w', encoding=encoding) as f:
225
+ f.write(content)
226
+ except Exception as e:
227
+ return f'Failed to write file: {e}'
228
+ return f'Wrote file: {path}'
229
+
230
+ def run_command_execute_shell_command(self, shell_command, timeout=30,
231
+ working_directory=None):
232
+ if settings.sigmund_review_actions:
233
+ if not ConfirmRunCodeDialog(self, shell_command, 'shell').exec() \
234
+ == ConfirmRunCodeDialog.Accepted:
235
+ return ACTION_CANCELLED
236
+ try:
237
+ result = subprocess.run(
238
+ shell_command,
239
+ shell=True,
240
+ capture_output=True,
241
+ text=True,
242
+ timeout=timeout,
243
+ cwd=working_directory if working_directory else self._working_directory
244
+ )
245
+ output = result.stdout
246
+ if result.stderr:
247
+ output += f'\nSTDERR:\n{result.stderr}'
248
+ if not output.strip():
249
+ output = '(no output)'
250
+ except subprocess.TimeoutExpired:
251
+ return f'Shell command timed out after {timeout} seconds.'
252
+ except Exception as e:
253
+ return f'Failed to execute shell command: {e}'
254
+ return f'''The following shell command was executed:
255
+ <executed_command>
256
+ {shell_command}
257
+ </executed_command>
258
+
259
+ <output>
260
+ {output}
261
+ </output>
197
262
  '''
198
263
 
199
264
  @property
@@ -263,6 +328,8 @@ class SigmundAnalystWidget(SigmundWidget):
263
328
 
264
329
  system_prompt = f'''## Working directory
265
330
 
331
+ IMPORTANT: Do NOT call inspect_files() with {current_path}, because it is already in the workspace.
332
+
266
333
  The workspace corresponds to the following file: {current_path}
267
334
  The working directory is: {working_directory}
268
335
 
@@ -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)