Coverage for src/prosemark/ports/editor_port.py: 100%

4 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-09-24 18:08 +0000

1"""EditorPort abstract base class for external editor integration. 

2 

3This module defines the EditorPort abstract base class that provides a contract 

4for opening files in external editors (VS Code, Vim, Emacs, etc.). The abstract 

5base class enables: 

6 

7* Cross-platform editor launching ($EDITOR, OS defaults) 

8* Testable editor integration through dependency injection 

9* Support for different editors and launch strategies 

10* Hexagonal architecture compliance by isolating system editor concerns 

11* Optional cursor positioning hints for better UX 

12""" 

13 

14from abc import ABC, abstractmethod 

15 

16 

17class EditorPort(ABC): 

18 """Abstract base class for external editor integration. 

19 

20 Defines the contract for opening files in external editors with support 

21 for cross-platform editor launching and optional cursor positioning hints. 

22 

23 Implementations should handle: 

24 - System-specific editor launching 

25 - Editor detection and configuration 

26 - Error handling for missing files or launch failures 

27 

28 Raises: 

29 FileNotFoundError: When the specified file path does not exist 

30 EditorLaunchError: When the editor cannot be launched or fails to start 

31 

32 """ 

33 

34 @abstractmethod 

35 def open(self, path: str, *, cursor_hint: str | None = None) -> None: 

36 """Open a file in the external editor. 

37 

38 Args: 

39 path: Absolute or relative file path to open 

40 cursor_hint: Optional positioning hint for cursor placement. 

41 Could be line number, search pattern, or 

42 implementation-specific format. 

43 

44 Raises: 

45 FileNotFoundError: When the specified file does not exist 

46 EditorLaunchError: When editor cannot be launched 

47 

48 Examples: 

49 >>> editor.open('/path/to/file.txt') 

50 >>> editor.open('draft.md', cursor_hint='42') # Line 42 

51 >>> editor.open('notes.txt', cursor_hint=':search_term') # Search pattern 

52 

53 """ 

54 ... # pragma: no cover