Files
clide/clide/widgets/components/git_graph.py
T
Jeroen SchweitzerandClaude Opus 4.5 1ed21d2a0f Restructure project and add user settings persistence
- Move src/clide/ to clide/ (flatten directory structure)
- Add SettingsService for persistent user preferences
- Settings stored in ~/.clide/settings.json
- Persist theme, panel visibility, and compact mode state
- Fix terminal rendering glitch with throttled refresh (~60fps)
- Update pyproject.toml, Makefile, and tests for new structure

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

91 lines
2.3 KiB
Python

"""Git graph visualization component."""
from textual.app import ComposeResult
from textual.containers import Vertical
from textual.message import Message
from textual.widgets import RichLog
from clide.models.git import GitCommit
class GitGraphView(Vertical):
"""View for git commit graph visualization."""
DEFAULT_CSS = """
GitGraphView {
height: 100%;
}
GitGraphView RichLog {
height: 100%;
scrollbar-size: 1 1;
}
GitGraphView .commit-line {
height: auto;
}
"""
# Graph drawing characters
COMMIT = "●"
MERGE = "◆"
LINE = "│"
BRANCH = "├"
JOIN = "┴"
class CommitSelected(Message):
"""Emitted when a commit is selected."""
def __init__(self, commit: GitCommit) -> None:
self.commit = commit
super().__init__()
def __init__(self, commits: list[GitCommit] | None = None, **kwargs) -> None:
super().__init__(**kwargs)
self._commits = commits or []
def compose(self) -> ComposeResult:
yield RichLog(id="graph-log", highlight=True, markup=True)
def on_mount(self) -> None:
"""Render initial graph."""
self._render_graph()
def update_commits(self, commits: list[GitCommit]) -> None:
"""Update the commit list."""
self._commits = commits
self._render_graph()
def _render_graph(self) -> None:
"""Render the commit graph."""
log = self.query_one("#graph-log", RichLog)
log.clear()
for commit in self._commits:
line = self._format_commit_line(commit)
log.write(line)
def _format_commit_line(self, commit: GitCommit) -> str:
"""Format a single commit line."""
# Choose commit symbol
symbol = self.MERGE if commit.is_merge else self.COMMIT
# Format refs (branches, tags)
refs_str = ""
if commit.refs:
refs = ", ".join(commit.refs)
refs_str = f" [bold cyan]({refs})[/]"
# Truncate message
message = commit.message[:50]
if len(commit.message) > 50:
message += "..."
return (
f"[bold yellow]{symbol}[/] "
f"[dim]{commit.short_hash}[/]"
f"{refs_str} "
f"{message} "
f"[dim]- {commit.author}, {commit.date}[/]"
)