Files
clide/clide/widgets/panels/sidebar.py
T
Jeroen SchweitzerandClaude Opus 4.5 c955e3ad25 Add file watcher integration and IDE enhancements
- Implement file system watching with watchdog for real-time file panel updates
- Add FileEventMessage for event-driven file change handling
- Integrate Claude events parsing for IDE awareness of Claude actions
- Add extension hooks for file changes (clide_on_file_changed, clide_on_file_saved)
- Enhance editor pane with syntax highlighting service
- Improve workspace panel with action bar and file operations
- Update Claude panel with PTY terminal integration
- Add TODO.md to track long-term project items
- Update keybindings to use Alt-based shortcuts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 16:14:44 +01:00

169 lines
4.9 KiB
Python

"""Sidebar panel with Files, Git, and Tree tabs."""
from pathlib import Path
from textual.app import ComposeResult
from textual.containers import Container, Vertical
from textual.message import Message
from textual.reactive import reactive
from textual.widgets import TabbedContent, TabPane
from clide.widgets.components.branch_status import BranchStatus
from clide.widgets.components.files_view import FilesView
from clide.widgets.components.git_changes import GitChangesView
from clide.widgets.components.git_graph import GitGraphView
class SidebarPanel(Vertical):
"""Left sidebar panel with file browser, git changes, and git graph."""
DEFAULT_CSS = """
SidebarPanel {
width: 20%;
min-width: 25;
height: 100%;
background: $surface;
}
SidebarPanel TabbedContent {
height: 1fr;
}
SidebarPanel .sidebar-content {
height: 1fr;
}
SidebarPanel BranchStatus {
dock: bottom;
height: auto;
}
"""
class FileSelected(Message):
"""Emitted when a file is selected from the file browser."""
def __init__(self, path: Path) -> None:
self.path = path
super().__init__()
class GitFileSelected(Message):
"""Emitted when a file is selected from git changes."""
def __init__(self, path: Path, staged: bool) -> None:
self.path = path
self.staged = staged
super().__init__()
class BranchChanged(Message):
"""Emitted when the branch is changed."""
def __init__(self, branch: str) -> None:
self.branch = branch
super().__init__()
# Reactive state
current_branch: reactive[str] = reactive("main")
visible: reactive[bool] = reactive(True)
def __init__(
self,
workdir: Path | None = None,
**kwargs,
) -> None:
super().__init__(**kwargs)
self._workdir = workdir or Path.cwd()
self.id = "panel-sidebar"
def compose(self) -> ComposeResult:
with Container(classes="sidebar-content"), TabbedContent(id="sidebar-tabs"):
with TabPane("Files", id="sidebar-files"):
yield FilesView(path=self._workdir)
with TabPane("Git", id="sidebar-git"):
yield GitChangesView()
with TabPane("Tree", id="sidebar-tree"):
yield GitGraphView()
yield BranchStatus(current_branch=self.current_branch)
def watch_visible(self, visible: bool) -> None:
"""Handle visibility changes."""
self.display = visible
def watch_current_branch(self, branch: str) -> None:
"""Update branch status when branch changes."""
try:
branch_status = self.query_one(BranchStatus)
branch_status.branch = branch
except Exception:
pass
def update_git_status(
self,
staged: list,
unstaged: list,
) -> None:
"""Update git changes view."""
try:
git_view = self.query_one(GitChangesView)
git_view.update_changes(staged, unstaged)
except Exception:
pass
def update_git_graph(self, commits: list) -> None:
"""Update git graph view."""
try:
graph = self.query_one(GitGraphView)
graph.update_graph(commits)
except Exception:
pass
def update_branches(self, branches: list[str]) -> None:
"""Update available branches."""
try:
branch_status = self.query_one(BranchStatus)
branch_status.update_branches(branches)
except Exception:
pass
def refresh_files(self) -> None:
"""Refresh file browser."""
try:
files_view = self.query_one(FilesView)
files_view.reload()
except Exception:
pass
def highlight_file(self, path: Path) -> None:
"""Highlight a file in the file browser.
Used to show which file Claude is working with.
"""
try:
files_view = self.query_one(FilesView)
files_view.highlight_path(path)
except Exception:
pass
def focus_tab(self, tab_id: str) -> None:
"""Focus a specific tab."""
tabs = self.query_one("#sidebar-tabs", TabbedContent)
tabs.active = tab_id
def on_files_view_file_selected(self, event: FilesView.FileSelected) -> None:
"""Forward file selection."""
self.post_message(self.FileSelected(event.path))
def on_git_changes_view_file_clicked(
self,
event: GitChangesView.FileClicked,
) -> None:
"""Forward git file selection."""
self.post_message(self.GitFileSelected(event.path, event.staged))
def on_branch_status_branch_changed(
self,
event: BranchStatus.BranchChanged,
) -> None:
"""Forward branch change."""
self.current_branch = event.branch
self.post_message(self.BranchChanged(event.branch))