| 1090 | ignore_patterns = _load_ignore_patterns(repo_root) |
| 1091 | |
| 1092 | class GraphUpdateHandler(FileSystemEventHandler): |
| 1093 | def __init__(self): |
| 1094 | self._pending: set[str] = set() |
| 1095 | self._lock = threading.Lock() |
| 1096 | self._timer: threading.Timer | None = None |
| 1097 | |
| 1098 | def _should_handle(self, path: str) -> bool: |
| 1099 | if Path(path).is_symlink(): |
| 1100 | return False |
| 1101 | try: |
| 1102 | rel = str(Path(path).relative_to(repo_root)) |
| 1103 | except ValueError: |
| 1104 | return False |
| 1105 | if _should_ignore(rel, ignore_patterns): |
| 1106 | return False |
| 1107 | if parser.detect_language(Path(path)) is None: |
| 1108 | return False |
| 1109 | return True |
| 1110 | |
| 1111 | def on_modified(self, event): |
| 1112 | if event.is_directory: |
| 1113 | return |
| 1114 | if self._should_handle(event.src_path): |
| 1115 | self._schedule(event.src_path) |
| 1116 | |
| 1117 | def on_created(self, event): |
| 1118 | if event.is_directory: |
| 1119 | return |
| 1120 | if self._should_handle(event.src_path): |
| 1121 | self._schedule(event.src_path) |
| 1122 | |
| 1123 | def on_deleted(self, event): |
| 1124 | if event.is_directory: |
| 1125 | return |
| 1126 | # Only handle files we would normally track |
| 1127 | try: |
| 1128 | rel = str(Path(event.src_path).relative_to(repo_root)) |
| 1129 | except ValueError: |
| 1130 | return |
| 1131 | if _should_ignore(rel, ignore_patterns): |
| 1132 | return |
| 1133 | try: |
| 1134 | store.remove_file_data(event.src_path) |
| 1135 | store.commit() |
| 1136 | logger.info("Removed: %s", rel) |
| 1137 | except Exception as e: |
| 1138 | logger.error("Error removing %s: %s", rel, e) |
| 1139 | |
| 1140 | def _schedule(self, abs_path: str): |
| 1141 | """Add file to pending set and reset the debounce timer.""" |
| 1142 | with self._lock: |
| 1143 | self._pending.add(abs_path) |
| 1144 | if self._timer is not None: |
| 1145 | self._timer.cancel() |
| 1146 | self._timer = threading.Timer(_DEBOUNCE_SECONDS, self._flush) |
| 1147 | self._timer.start() |
| 1148 | |
| 1149 | def _flush(self): |