fix(external_editor): cache auto-detect result, avoid hitting registry on every UI frame
This commit is contained in:
@@ -110,5 +110,17 @@
|
||||
"C:\\projects\\manual_slop\\tests\\test_mma_concurrent_tracks_sim.py": {
|
||||
"hash": "3e56f5dc0217637096ef60a9f79d4b6f8e575d2cf789bdb32ecbc62b5e44244c",
|
||||
"summary": "This Python script is an integration test designed to stress-test the concurrent execution of multiple MMA (presumably \"Multi-Modal Analysis\" or similar) tracks. It verifies that the system can handle starting, processing, and completing multiple tracks simultaneously without crashing and that all associated workers are accounted for.\n\n* **Concurrent Track Execution:** Simulates starting and managing two MMA tracks at the same time.\n* **Worker Verification:** Checks for the appearance and completion of workers associated with each track.\n* **API Hook Client Usage:** Interacts with a simulated API to control and monitor the MMA process.\n* **Mock Provider Setup:** Configures a custom mock provider to facilitate the test scenario.\n\n**Outline:**\n**Python** \u2014 135 lines\nimports: os, pytest, src, sys, time\nfunctions: _poll_mma_status, test_mma_concurrent_tracks_execution"
|
||||
},
|
||||
"C:\\projects\\manual_slop\\src\\patch_modal.py": {
|
||||
"hash": "9b034a4193a0d9031521d4c761b458170ef8feecba3220918543d4b768199ae2",
|
||||
"summary": "This module manages the state and callbacks for a patch approval modal. It handles requesting patch approval, storing pending patch details, and triggering actions upon patch application or rejection.\n\n* **State Management:** Tracks whether a modal is shown and holds details of a pending patch.\n* **Callback Handling:** Allows setting and invoking callbacks for patch application and rejection.\n* **Singleton Pattern:** Provides a global, single instance of the `PatchModalManager`.\n\n**Outline:**\n**Python** \u2014 73 lines\nimports: dataclasses, time, typing\nclass PendingPatch\nclass PatchModalManager: __init__, request_patch_approval, get_pending_patch, is_modal_shown, set_apply_callback, set_reject_callback, apply_patch, reject_patch, close_modal, reset\nfunctions: get_patch_modal_manager, reset_patch_modal_manager"
|
||||
},
|
||||
"C:\\Users\\Ed\\AppData\\Local\\Temp\\pytest-of-Ed\\pytest-864\\test_auto_aggregate_skip0\\file1.txt": {
|
||||
"hash": "d0b425e00e15a0d36b9b361f02bab63563aed6cb4665083905386c55d5b679fa",
|
||||
"summary": "This document contains a single line of text, \"content1\". Its purpose and key takeaways are limited to this singular piece of content.\n\n**Outline:**\n**TXT** \u2014 1 lines\npreview:\n```\ncontent1\n```"
|
||||
},
|
||||
"C:\\Users\\Ed\\AppData\\Local\\Temp\\pytest-of-Ed\\pytest-864\\test_force_full0\\other.txt": {
|
||||
"hash": "04d61c0832f9cbc2a210334352425d2519890a0a5945da96ccc5bd9ff101c4d3",
|
||||
"summary": "This document is a simple text file containing ten lines of content, with the first eight lines previewed. Its purpose appears to be for basic data storage or as a placeholder.\n\n**Outline:**\n**TXT** \u2014 10 lines\npreview:\n```\nline1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\n```"
|
||||
}
|
||||
}
|
||||
+14
-14
@@ -75,7 +75,7 @@ DockId=0xAFC85805,2
|
||||
|
||||
[Window][Theme]
|
||||
Pos=0,28
|
||||
Size=1874,1889
|
||||
Size=469,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000005,3
|
||||
|
||||
@@ -102,26 +102,26 @@ Collapsed=0
|
||||
DockId=0x0000000D,0
|
||||
|
||||
[Window][Discussion Hub]
|
||||
Pos=1876,28
|
||||
Size=1209,1889
|
||||
Pos=471,28
|
||||
Size=1209,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Operations Hub]
|
||||
Pos=0,28
|
||||
Size=1874,1889
|
||||
Size=469,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000005,2
|
||||
|
||||
[Window][Files & Media]
|
||||
Pos=1876,28
|
||||
Size=1209,1889
|
||||
Pos=471,28
|
||||
Size=1209,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][AI Settings]
|
||||
Pos=0,28
|
||||
Size=1874,1889
|
||||
Size=469,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
@@ -131,14 +131,14 @@ Size=416,325
|
||||
Collapsed=0
|
||||
|
||||
[Window][MMA Dashboard]
|
||||
Pos=1876,28
|
||||
Size=1209,1889
|
||||
Pos=471,28
|
||||
Size=1209,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000006,2
|
||||
|
||||
[Window][Log Management]
|
||||
Pos=1876,28
|
||||
Size=1209,1889
|
||||
Pos=471,28
|
||||
Size=1209,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000006,3
|
||||
|
||||
@@ -407,7 +407,7 @@ DockId=0x00000006,1
|
||||
|
||||
[Window][Project Settings]
|
||||
Pos=0,28
|
||||
Size=1874,1889
|
||||
Size=469,1172
|
||||
Collapsed=0
|
||||
DockId=0x00000005,1
|
||||
|
||||
@@ -561,11 +561,11 @@ Column 2 Width=150
|
||||
DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y
|
||||
DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A
|
||||
DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02
|
||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=3085,1889 Split=X
|
||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=1680,1172 Split=X
|
||||
DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2175,1183 Split=X
|
||||
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2
|
||||
DockNode ID=0x00000007 Parent=0x0000000B SizeRef=1512,858 Split=X Selected=0x8CA2375C
|
||||
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=840,1681 CentralNode=1 Selected=0x3F1379AF
|
||||
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=840,1681 CentralNode=1 Selected=0x418C7449
|
||||
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=1209,1681 Selected=0x2C0206CE
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=1777,858 Selected=0x418C7449
|
||||
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import sys
|
||||
with open('config.toml', 'rb') as f:
|
||||
data = f.read()
|
||||
BOM = bytes([0xef, 0xbb, 0xbf])
|
||||
if data.startswith(BOM):
|
||||
with open('config.toml', 'wb') as f:
|
||||
f.write(data[3:])
|
||||
print('BOM removed')
|
||||
else:
|
||||
print('No BOM found')
|
||||
sys.exit(0)
|
||||
+80
-1
@@ -46,6 +46,75 @@ class ExternalEditorLauncher:
|
||||
return None
|
||||
|
||||
|
||||
_cached_vscode_config: Optional[TextEditorConfig] = None
|
||||
|
||||
|
||||
def auto_detect_vscode() -> Optional[TextEditorConfig]:
|
||||
global _cached_vscode_config
|
||||
if _cached_vscode_config is not None:
|
||||
return _cached_vscode_config
|
||||
vscode_path = _find_vscode_in_registry() or _find_vscode_common_paths()
|
||||
if vscode_path:
|
||||
_cached_vscode_config = TextEditorConfig(
|
||||
name="vscode",
|
||||
path=vscode_path,
|
||||
diff_args=["--new-window", "--diff"]
|
||||
)
|
||||
return _cached_vscode_config
|
||||
|
||||
|
||||
def get_default_launcher() -> ExternalEditorLauncher:
|
||||
import subprocess
|
||||
paths = []
|
||||
reg_keys = [
|
||||
r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||
r"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||
r"HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||
]
|
||||
for key in reg_keys:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["powershell", "-Command", f"Get-ItemProperty -Path '{key}' -ErrorAction SilentlyContinue | Where-Object {{ $_.DisplayName -like '*Visual Studio Code*' }} | Select-Object -ExpandProperty InstallLocation"],
|
||||
capture_output=True, text=True, timeout=5
|
||||
)
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
line = line.strip()
|
||||
if line and line != "":
|
||||
exe_path = line.strip() + "\\Code.exe"
|
||||
if subprocess.run(["test", "-f", exe_path], check=False).returncode == 0:
|
||||
paths.append(exe_path)
|
||||
except Exception:
|
||||
pass
|
||||
if paths:
|
||||
return paths[0]
|
||||
return None
|
||||
|
||||
|
||||
def _find_vscode_common_paths() -> Optional[str]:
|
||||
import os
|
||||
candidates = [
|
||||
r"C:\apps\Microsoft VS Code\Code.exe",
|
||||
r"C:\Program Files\Microsoft VS Code\Code.exe",
|
||||
r"C:\Program Files (x86)\Microsoft VS Code\Code.exe",
|
||||
os.path.expanduser(r"~\AppData\Local\Programs\Microsoft VS Code\Code.exe"),
|
||||
]
|
||||
for path in candidates:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
def auto_detect_vscode() -> Optional[TextEditorConfig]:
|
||||
vscode_path = _find_vscode_in_registry() or _find_vscode_common_paths()
|
||||
if vscode_path:
|
||||
return TextEditorConfig(
|
||||
name="vscode",
|
||||
path=vscode_path,
|
||||
diff_args=["--new-window", "--diff"]
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def get_default_launcher() -> ExternalEditorLauncher:
|
||||
from src import models
|
||||
config = models.load_config()
|
||||
@@ -55,7 +124,17 @@ def get_default_launcher() -> ExternalEditorLauncher:
|
||||
"editors": editors_config,
|
||||
"default_editor": default_editor,
|
||||
})
|
||||
return ExternalEditorLauncher(ext_config)
|
||||
launcher = ExternalEditorLauncher(ext_config)
|
||||
detected = auto_detect_vscode()
|
||||
if detected:
|
||||
if not launcher.config.editors:
|
||||
launcher.config.editors["vscode"] = detected
|
||||
launcher.config.default_editor = "vscode"
|
||||
else:
|
||||
vscode = launcher.config.editors.get("vscode")
|
||||
if vscode and "--new-window" not in vscode.diff_args:
|
||||
vscode.diff_args = ["--new-window", "--diff"]
|
||||
return launcher
|
||||
|
||||
|
||||
def resolve_project_editor_override(project_path: Optional[str]) -> Optional[str]:
|
||||
|
||||
Reference in New Issue
Block a user