Private
Public Access
0
0

refactor(external_editor): merge TextEditorConfig + ExternalEditorConfig from models.py

Per the 4-criteria decision rule: editor configs fail C1 (only used by
the editor subsystem), fail C2 (no state machine), fail C3 (no
dedicated test file), borderline C4. MERGE into the existing
src/external_editor.py which already has ExternalEditorLauncher +
the helper functions.

This commit:
 1. Adds TextEditorConfig + ExternalEditorConfig + EMPTY_TEXT_EDITOR_CONFIG
    class definitions to src/external_editor.py at the top.
 2. Removes the same class defs from src/models.py.
 3. Adds lazy re-export via the existing __getattr__ in src/models.py
    (EAGER would cycle: external_editor was previously importing from
    models; if models re-exports, the cycle would deadlock on initial
    load).
 4. Updates external_editor.py imports to no longer import from models
    (the class defs are now local).

Verification: VC8 (TextEditorConfig + ExternalEditorConfig)
  from src.external_editor import TextEditorConfig, ExternalEditorConfig,
                                     EMPTY_TEXT_EDITOR_CONFIG  # OK
  from src.models            import TextEditorConfig, ExternalEditorConfig,
                                     EMPTY_TEXT_EDITOR_CONFIG  # OK (lazy)
  identity check: True for all 3

Tests verified (22/22 PASS):
  tests/test_external_editor.py (17 tests)
  tests/test_external_editor_gui.py (5 tests)
This commit is contained in:
2026-06-26 10:12:30 -04:00
parent ecd8e82f2f
commit bca0875580
2 changed files with 70 additions and 69 deletions
+57 -4
View File
@@ -6,11 +6,64 @@ import subprocess
import tempfile
# TODO(Ed): Eliminate these?
from pathlib import Path
from typing import Optional, List, Dict, Any
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, List, Dict, Any
from src.models import ExternalEditorConfig, TextEditorConfig
from src.result_types import ErrorInfo, ErrorKind, Result
from src.result_types import ErrorInfo, ErrorKind, Result
from src.type_aliases import Metadata
@dataclass
class TextEditorConfig:
name: str = ""
path: str = ""
diff_args: List[str] = field(default_factory=list)
def to_dict(self) -> Metadata:
return {
"name": self.name,
"path": self.path,
"diff_args": self.diff_args,
}
@classmethod
def from_dict(cls, data: Metadata) -> "TextEditorConfig":
return cls(
name = data["name"],
path = data["path"],
diff_args = data.get("diff_args", []),
)
@dataclass
class ExternalEditorConfig:
editors: Dict[str, TextEditorConfig] = field(default_factory=dict)
default_editor: Optional[str] = None
def get_default(self) -> TextEditorConfig:
if self.default_editor and self.default_editor in self.editors:
return self.editors[self.default_editor]
if self.editors:
return next(iter(self.editors.values()))
return EMPTY_TEXT_EDITOR_CONFIG
def to_dict(self) -> Metadata:
return {
"editors": {k: v.to_dict() for k, v in self.editors.items()},
"default_editor": self.default_editor,
}
@classmethod
def from_dict(cls, data: Metadata) -> "ExternalEditorConfig":
editors = {}
for name, ed_data in data.get("editors", {}).items():
if isinstance(ed_data, dict): editors[name] = TextEditorConfig.from_dict(ed_data)
elif isinstance(ed_data, str): editors[name] = TextEditorConfig(name=name, path=ed_data)
return cls(editors=editors, default_editor=data.get("default_editor"))
EMPTY_TEXT_EDITOR_CONFIG: TextEditorConfig = TextEditorConfig()
class ExternalEditorLauncher: