Clide is being rebuilt as a Flutter desktop app. The Python Textual implementation moves wholesale into legacy/ rather than being deleted: its pane model, panel set, git skills, and panel communication design are real thought that should remain readable next to the new code while the rebuild finds its shape. Git's rename tracking preserves history, so `git log -- legacy/` still works. The Flutter rebuild lives at the repo root alongside a Go sidecar (the architecture claudian was heading toward, which folds into clide as a core component rather than a separate plugin project). Bootstrap of the new shape lands in subsequent commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
1.8 KiB
Python
73 lines
1.8 KiB
Python
"""Editor-related Pydantic models."""
|
|
|
|
from pathlib import Path
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
|
|
|
|
class CursorPosition(BaseModel):
|
|
"""Cursor position in editor."""
|
|
|
|
model_config = ConfigDict(strict=True, frozen=True)
|
|
|
|
line: int
|
|
column: int
|
|
|
|
|
|
class Selection(BaseModel):
|
|
"""Text selection range."""
|
|
|
|
model_config = ConfigDict(strict=True, frozen=True)
|
|
|
|
start: CursorPosition
|
|
end: CursorPosition
|
|
|
|
|
|
class FileBuffer(BaseModel):
|
|
"""A file buffer in the editor."""
|
|
|
|
model_config = ConfigDict(strict=True)
|
|
|
|
path: Path
|
|
content: str
|
|
language: str | None = None
|
|
is_modified: bool = False
|
|
cursor: CursorPosition = CursorPosition(line=0, column=0)
|
|
selection: Selection | None = None
|
|
scroll_offset: int = 0
|
|
|
|
@property
|
|
def filename(self) -> str:
|
|
"""Get the filename from path."""
|
|
return self.path.name
|
|
|
|
@property
|
|
def display_name(self) -> str:
|
|
"""Get display name with modification indicator."""
|
|
prefix = "● " if self.is_modified else ""
|
|
return f"{prefix}{self.filename}"
|
|
|
|
|
|
class EditorState(BaseModel):
|
|
"""State of the editor panel."""
|
|
|
|
model_config = ConfigDict(strict=True)
|
|
|
|
buffers: list[FileBuffer] = []
|
|
active_buffer_index: int | None = None
|
|
recent_files: list[Path] = []
|
|
|
|
@property
|
|
def active_buffer(self) -> FileBuffer | None:
|
|
"""Get currently active buffer."""
|
|
if self.active_buffer_index is not None and self.buffers:
|
|
return self.buffers[self.active_buffer_index]
|
|
return None
|
|
|
|
def get_buffer_by_path(self, path: Path) -> FileBuffer | None:
|
|
"""Find a buffer by its file path."""
|
|
for buffer in self.buffers:
|
|
if buffer.path == path:
|
|
return buffer
|
|
return None
|