Coverage for openhcs/textual_tui/services/window_cache.py: 0.0%

68 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-14 05:57 +0000

1""" 

2Window position and size caching service for OpenHCS TUI. 

3 

4Provides persistent storage of window positions and sizes across application sessions. 

5""" 

6 

7import json 

8import logging 

9from pathlib import Path 

10from typing import Dict, Optional, Tuple 

11from textual.geometry import Offset, Size 

12 

13logger = logging.getLogger(__name__) 

14 

15 

16class WindowCache: 

17 """Service for caching window positions and sizes.""" 

18 

19 def __init__(self): 

20 """Initialize the window cache service.""" 

21 # Use the same directory as other OpenHCS data 

22 self.cache_dir = Path.home() / ".local" / "share" / "openhcs" 

23 self.cache_file = self.cache_dir / "window_cache.json" 

24 self._cache_data: Dict[str, Dict[str, Dict[str, int]]] = {} 

25 self._load_cache() 

26 

27 def _load_cache(self) -> None: 

28 """Load cache data from disk.""" 

29 try: 

30 if self.cache_file.exists(): 

31 with open(self.cache_file, 'r') as f: 

32 self._cache_data = json.load(f) 

33 logger.debug(f"Loaded window cache from {self.cache_file}") 

34 else: 

35 self._cache_data = {} 

36 logger.debug("No existing window cache found, starting fresh") 

37 except Exception as e: 

38 logger.warning(f"Failed to load window cache: {e}") 

39 self._cache_data = {} 

40 

41 def _save_cache(self) -> None: 

42 """Save cache data to disk.""" 

43 try: 

44 # Ensure cache directory exists 

45 self.cache_dir.mkdir(parents=True, exist_ok=True) 

46 

47 with open(self.cache_file, 'w') as f: 

48 json.dump(self._cache_data, f, indent=2) 

49 logger.debug(f"Saved window cache to {self.cache_file}") 

50 except Exception as e: 

51 logger.error(f"Failed to save window cache: {e}") 

52 

53 def save_window_state(self, window_id: str, position: Offset, size: Size) -> None: 

54 """ 

55 Save window position and size to cache. 

56  

57 Args: 

58 window_id: Unique window identifier (window button name) 

59 position: Window position (Offset with x, y) 

60 size: Window size (Size with width, height) 

61 """ 

62 try: 

63 self._cache_data[window_id] = { 

64 "position": {"x": position.x, "y": position.y}, 

65 "size": {"width": size.width, "height": size.height} 

66 } 

67 self._save_cache() 

68 logger.debug(f"Cached window state for '{window_id}': pos=({position.x},{position.y}), size=({size.width}x{size.height})") 

69 except Exception as e: 

70 logger.error(f"Failed to save window state for '{window_id}': {e}") 

71 

72 def load_window_state(self, window_id: str) -> Optional[Tuple[Offset, Size]]: 

73 """ 

74 Load window position and size from cache. 

75  

76 Args: 

77 window_id: Unique window identifier (window button name) 

78  

79 Returns: 

80 Tuple of (position, size) if cached, None if not found 

81 """ 

82 try: 

83 if window_id in self._cache_data: 

84 data = self._cache_data[window_id] 

85 position = Offset(data["position"]["x"], data["position"]["y"]) 

86 size = Size(data["size"]["width"], data["size"]["height"]) 

87 logger.debug(f"Loaded cached window state for '{window_id}': pos=({position.x},{position.y}), size=({size.width}x{size.height})") 

88 return position, size 

89 else: 

90 logger.debug(f"No cached state found for window '{window_id}'") 

91 return None 

92 except Exception as e: 

93 logger.error(f"Failed to load window state for '{window_id}': {e}") 

94 return None 

95 

96 def clear_window_cache(self, window_id: Optional[str] = None) -> None: 

97 """ 

98 Clear cached window state. 

99  

100 Args: 

101 window_id: Specific window to clear, or None to clear all 

102 """ 

103 try: 

104 if window_id: 

105 if window_id in self._cache_data: 

106 del self._cache_data[window_id] 

107 self._save_cache() 

108 logger.debug(f"Cleared cache for window '{window_id}'") 

109 else: 

110 self._cache_data.clear() 

111 self._save_cache() 

112 logger.debug("Cleared all window cache data") 

113 except Exception as e: 

114 logger.error(f"Failed to clear window cache: {e}") 

115 

116 

117# Global cache instance 

118_window_cache: Optional[WindowCache] = None 

119 

120 

121def get_window_cache() -> WindowCache: 

122 """Get the global window cache instance.""" 

123 global _window_cache 

124 if _window_cache is None: 

125 _window_cache = WindowCache() 

126 return _window_cache