fix padding

This commit is contained in:
James Long 2026-05-20 10:32:09 -04:00
commit 53e2ab8b1f

View file

@ -73,7 +73,10 @@ function DiffViewer(props: { api: TuiPluginApi }) {
if (input.mode === "last-turn") { if (input.mode === "last-turn") {
const sessionID = input.sessionID const sessionID = input.sessionID
if (!sessionID) return [] if (!sessionID) return []
const result = await props.api.client.session.diff({ sessionID, messageID: input.messageID }, { throwOnError: true }) const result = await props.api.client.session.diff(
{ sessionID, messageID: input.messageID },
{ throwOnError: true },
)
return normalizeDiffs(result.data ?? []) return normalizeDiffs(result.data ?? [])
} }
@ -121,7 +124,10 @@ function DiffViewer(props: { api: TuiPluginApi }) {
const highlighted = highlightedFileNode() const highlighted = highlightedFileNode()
if (highlighted !== undefined && fileRows().some((row) => row.id === highlighted)) return if (highlighted !== undefined && fileRows().some((row) => row.id === highlighted)) return
const lastHighlighted = lastHighlightedFileNode() const lastHighlighted = lastHighlightedFileNode()
const next = lastHighlighted !== undefined && fileRows().some((row) => row.id === lastHighlighted) ? lastHighlighted : fileRows()[0]?.id const next =
lastHighlighted !== undefined && fileRows().some((row) => row.id === lastHighlighted)
? lastHighlighted
: fileRows()[0]?.id
setHighlightedFileNode(next) setHighlightedFileNode(next)
} }
@ -130,7 +136,8 @@ function DiffViewer(props: { api: TuiPluginApi }) {
if (node !== undefined) setLastHighlightedFileNode(node) if (node !== undefined) setLastHighlightedFileNode(node)
} }
const moveFileSelection = (offset: number) => setHighlighted(moveFileTreeSelection(fileRows(), highlightedFileNode(), offset)) const moveFileSelection = (offset: number) =>
setHighlighted(moveFileTreeSelection(fileRows(), highlightedFileNode(), offset))
const clearFileTreePatchState = () => { const clearFileTreePatchState = () => {
setHighlightedFileNode(undefined) setHighlightedFileNode(undefined)
@ -182,14 +189,17 @@ function DiffViewer(props: { api: TuiPluginApi }) {
const jumpRelativePatchFile = (offset: number) => { const jumpRelativePatchFile = (offset: number) => {
const current = focus() === "files" ? highlightedFileNode() : undefined const current = focus() === "files" ? highlightedFileNode() : undefined
const nextFromSelection = current === undefined ? undefined : moveFileTreeSelectionToFile(fileRows(), current, offset) const nextFromSelection =
current === undefined ? undefined : moveFileTreeSelectionToFile(fileRows(), current, offset)
if (nextFromSelection !== undefined) { if (nextFromSelection !== undefined) {
jumpToFileIndex(fileRows().find((row) => row.id === nextFromSelection)?.fileIndex) jumpToFileIndex(fileRows().find((row) => row.id === nextFromSelection)?.fileIndex)
return return
} }
const currentFileIndex = activePatchFileIndex() ?? currentPatchFileIndex() const currentFileIndex = activePatchFileIndex() ?? currentPatchFileIndex()
const currentRow = fileRows().find((row) => row.fileIndex === currentFileIndex) const currentRow = fileRows().find((row) => row.fileIndex === currentFileIndex)
scrollToFileIndex(fileRows().find((row) => row.id === moveFileTreeSelectionToFile(fileRows(), currentRow?.id, offset))?.fileIndex) scrollToFileIndex(
fileRows().find((row) => row.id === moveFileTreeSelectionToFile(fileRows(), currentRow?.id, offset))?.fileIndex,
)
} }
const highlightedPatchFileIndex = () => fileRows().find((row) => row.id === highlightedFileNode())?.fileIndex const highlightedPatchFileIndex = () => fileRows().find((row) => row.id === highlightedFileNode())?.fileIndex
@ -243,166 +253,170 @@ function DiffViewer(props: { api: TuiPluginApi }) {
props.api.route.navigate("home") props.api.route.navigate("home")
}, },
}, },
{ {
name: "diff.down", name: "diff.down",
title: "Move diff viewer down", title: "Move diff viewer down",
category: "VCS", category: "VCS",
run: focusRunner({ run: focusRunner({
files() { files() {
moveFileSelection(1) moveFileSelection(1)
},
patches() {
clearFileTreePatchState()
scroll?.scrollBy(1)
},
}),
},
{
name: "diff.up",
title: "Move diff viewer up",
category: "VCS",
run: focusRunner({
files() {
moveFileSelection(-1)
},
patches() {
clearFileTreePatchState()
scroll?.scrollBy(-1)
},
}),
},
{
name: "diff.page.down",
title: "Page diff viewer down",
category: "VCS",
run: focusRunner({
files() {
moveFileSelection(8)
},
patches() {
clearFileTreePatchState()
if (scroll) scroll.scrollBy(scroll.height)
},
}),
},
{
name: "diff.page.up",
title: "Page diff viewer up",
category: "VCS",
run: focusRunner({
files() {
moveFileSelection(-8)
},
patches() {
clearFileTreePatchState()
if (scroll) scroll.scrollBy(-scroll.height)
},
}),
},
{
name: "diff.toggle",
title: "Toggle diff viewer item",
category: "VCS",
run: focusRunner({
files() {
toggleSelectedFileTreeRow()
},
patches() {},
}),
},
{
name: "diff.expand",
title: "Expand diff viewer item",
category: "VCS",
run: focusRunner({
files() {
setExpandedFileNodes((expanded) => setFileTreeDirectoryExpanded(fileTree(), expanded, highlightedFileNode(), true))
},
patches() {},
}),
},
{
name: "diff.collapse",
title: "Collapse diff viewer item",
category: "VCS",
run: focusRunner({
files() {
setExpandedFileNodes((expanded) => setFileTreeDirectoryExpanded(fileTree(), expanded, highlightedFileNode(), false))
},
patches() {},
}),
},
{
name: "diff.next_file",
title: "Jump to next diff file",
category: "VCS",
run() {
jumpRelativePatchFile(1)
}, },
}, patches() {
{ clearFileTreePatchState()
name: "diff.previous_file", scroll?.scrollBy(1)
title: "Jump to previous diff file",
category: "VCS",
run() {
jumpRelativePatchFile(-1)
}, },
}, }),
{ },
name: "diff.switch_focus", {
title: "Switch diff viewer focus", name: "diff.up",
category: "VCS", title: "Move diff viewer up",
run() { category: "VCS",
if (!showFileTree()) return run: focusRunner({
setFocus((current) => { files() {
if (current === "files") return "patches" moveFileSelection(-1)
ensureHighlightedFileNode()
return "files"
})
}, },
}, patches() {
{ clearFileTreePatchState()
name: "diff.toggle_file_tree", scroll?.scrollBy(-1)
title: "Toggle diff viewer file tree",
category: "VCS",
run() {
setShowFileTree((value) => {
if (value) setFocus("patches")
return !value
})
}, },
}, }),
{ },
name: "diff.single_patch", {
title: "Toggle single patch view", name: "diff.page.down",
category: "VCS", title: "Page diff viewer down",
run() { category: "VCS",
setSinglePatch((value) => { run: focusRunner({
const next = !value files() {
if (next) ensureHighlightedPatchFile() moveFileSelection(8)
else scrollToHighlightedPatchFile()
return next
})
}, },
}, patches() {
{ clearFileTreePatchState()
name: "diff.switch_diff", if (scroll) scroll.scrollBy(scroll.height)
title: "Switch diff viewer source",
category: "VCS",
run() {
openSwitchDiffDialog()
}, },
}, }),
{ },
name: "diff.toggle_view", {
title: "Toggle diff viewer split or unified view", name: "diff.page.up",
category: "VCS", title: "Page diff viewer up",
run() { category: "VCS",
if (!splitAvailable()) return run: focusRunner({
setViewOverride(view() === "split" ? "unified" : "split") files() {
moveFileSelection(-8)
}, },
patches() {
clearFileTreePatchState()
if (scroll) scroll.scrollBy(-scroll.height)
},
}),
},
{
name: "diff.toggle",
title: "Toggle diff viewer item",
category: "VCS",
run: focusRunner({
files() {
toggleSelectedFileTreeRow()
},
patches() {},
}),
},
{
name: "diff.expand",
title: "Expand diff viewer item",
category: "VCS",
run: focusRunner({
files() {
setExpandedFileNodes((expanded) =>
setFileTreeDirectoryExpanded(fileTree(), expanded, highlightedFileNode(), true),
)
},
patches() {},
}),
},
{
name: "diff.collapse",
title: "Collapse diff viewer item",
category: "VCS",
run: focusRunner({
files() {
setExpandedFileNodes((expanded) =>
setFileTreeDirectoryExpanded(fileTree(), expanded, highlightedFileNode(), false),
)
},
patches() {},
}),
},
{
name: "diff.next_file",
title: "Jump to next diff file",
category: "VCS",
run() {
jumpRelativePatchFile(1)
}, },
] },
{
name: "diff.previous_file",
title: "Jump to previous diff file",
category: "VCS",
run() {
jumpRelativePatchFile(-1)
},
},
{
name: "diff.switch_focus",
title: "Switch diff viewer focus",
category: "VCS",
run() {
if (!showFileTree()) return
setFocus((current) => {
if (current === "files") return "patches"
ensureHighlightedFileNode()
return "files"
})
},
},
{
name: "diff.toggle_file_tree",
title: "Toggle diff viewer file tree",
category: "VCS",
run() {
setShowFileTree((value) => {
if (value) setFocus("patches")
return !value
})
},
},
{
name: "diff.single_patch",
title: "Toggle single patch view",
category: "VCS",
run() {
setSinglePatch((value) => {
const next = !value
if (next) ensureHighlightedPatchFile()
else scrollToHighlightedPatchFile()
return next
})
},
},
{
name: "diff.switch_diff",
title: "Switch diff viewer source",
category: "VCS",
run() {
openSwitchDiffDialog()
},
},
{
name: "diff.toggle_view",
title: "Toggle diff viewer split or unified view",
category: "VCS",
run() {
if (!splitAvailable()) return
setViewOverride(view() === "split" ? "unified" : "split")
},
},
]
const switchDiffOptions = createMemo(() => [ const switchDiffOptions = createMemo(() => [
{ {
@ -505,67 +519,74 @@ function DiffViewer(props: { api: TuiPluginApi }) {
> >
<Switch> <Switch>
<Match when={diff.error}> <Match when={diff.error}>
<text fg={theme().error}>Failed to load diff</text> <box paddingTop={1}>
<text fg={theme().error}>Failed to load diff</text>
</box>
</Match> </Match>
<Match when={files().length === 0}> <Match when={files().length === 0}>
<text fg={theme().textMuted}>No diff to show</text> <box paddingTop={1}>
<text fg={theme().textMuted}>No diff to show</text>
</box>
</Match> </Match>
<Match when={files().length > 0}> <Match when={files().length > 0}>
<scrollbox <scrollbox
ref={(element: ScrollBoxRenderable) => (scroll = element)} ref={(element: ScrollBoxRenderable) => (scroll = element)}
flexGrow={1} flexGrow={1}
minHeight={0} minHeight={0}
verticalScrollbarOptions={{ visible: false }} verticalScrollbarOptions={{ visible: false }}
horizontalScrollbarOptions={{ visible: false }} horizontalScrollbarOptions={{ visible: false }}
> >
<For each={visiblePatchFiles()}> <For each={visiblePatchFiles()}>
{(entry) => ( {(entry) => (
<box <box
ref={(element: BoxRenderable) => registerPatchNode(entry.fileIndex, element)} ref={(element: BoxRenderable) => registerPatchNode(entry.fileIndex, element)}
marginBottom={1} marginBottom={1}
backgroundColor={theme().backgroundPanel} backgroundColor={theme().backgroundPanel}
> >
<box <box
flexDirection="row" flexDirection="row"
gap={2} gap={2}
flexShrink={0} flexShrink={0}
paddingTop={1} paddingTop={1}
paddingBottom={1} paddingBottom={1}
paddingLeft={2} paddingLeft={2}
paddingRight={1} paddingRight={1}
backgroundColor={theme().backgroundPanel} backgroundColor={theme().backgroundPanel}
> >
<text fg={theme().text}>{entry.file.file}</text> <text fg={theme().text}>{entry.file.file}</text>
<text fg={theme().diffAdded}>+{entry.file.additions}</text> <text fg={theme().diffAdded}>+{entry.file.additions}</text>
<text fg={theme().diffRemoved}>-{entry.file.deletions}</text> <text fg={theme().diffRemoved}>-{entry.file.deletions}</text>
</box> </box>
<Show when={entry.file.patch} fallback={<text fg={theme().textMuted}>No patch available for this file.</text>}> <Show
{(patch) => ( when={entry.file.patch}
<diff fallback={<text fg={theme().textMuted}>No patch available for this file.</text>}
diff={patch()} >
view={view()} {(patch) => (
filetype={filetype(entry.file.file)} <diff
syntaxStyle={themeState.syntax()} diff={patch()}
showLineNumbers={true} view={view()}
width="100%" filetype={filetype(entry.file.file)}
wrapMode="word" syntaxStyle={themeState.syntax()}
fg={theme().text} showLineNumbers={true}
addedBg={theme().diffAddedBg} width="100%"
removedBg={theme().diffRemovedBg} wrapMode="word"
contextBg={theme().diffContextBg} fg={theme().text}
addedSignColor={theme().diffHighlightAdded} addedBg={theme().diffAddedBg}
removedSignColor={theme().diffHighlightRemoved} removedBg={theme().diffRemovedBg}
lineNumberFg={theme().diffLineNumber} contextBg={theme().diffContextBg}
lineNumberBg={theme().diffContextBg} addedSignColor={theme().diffHighlightAdded}
addedLineNumberBg={theme().diffAddedLineNumberBg} removedSignColor={theme().diffHighlightRemoved}
removedLineNumberBg={theme().diffRemovedLineNumberBg} lineNumberFg={theme().diffLineNumber}
/> lineNumberBg={theme().diffContextBg}
)} addedLineNumberBg={theme().diffAddedLineNumberBg}
</Show> removedLineNumberBg={theme().diffRemovedLineNumberBg}
</box> />
)} )}
</For> </Show>
</scrollbox> </box>
)}
</For>
</scrollbox>
</Match> </Match>
</Switch> </Switch>
</box> </box>
@ -598,14 +619,16 @@ function DiffViewer(props: { api: TuiPluginApi }) {
<Show when={toggleFileTreeShortcut()}> <Show when={toggleFileTreeShortcut()}>
{(shortcut) => ( {(shortcut) => (
<text fg={theme().text}> <text fg={theme().text}>
{shortcut()} <span style={{ fg: theme().textMuted }}>{showFileTree() ? "hide file tree" : "show file tree"}</span> {shortcut()}{" "}
<span style={{ fg: theme().textMuted }}>{showFileTree() ? "hide file tree" : "show file tree"}</span>
</text> </text>
)} )}
</Show> </Show>
<Show when={singlePatchShortcut()}> <Show when={singlePatchShortcut()}>
{(shortcut) => ( {(shortcut) => (
<text fg={theme().text}> <text fg={theme().text}>
{shortcut()} <span style={{ fg: theme().textMuted }}>{singlePatch() ? "all patches" : "single patch"}</span> {shortcut()}{" "}
<span style={{ fg: theme().textMuted }}>{singlePatch() ? "all patches" : "single patch"}</span>
</text> </text>
)} )}
</Show> </Show>
@ -619,7 +642,8 @@ function DiffViewer(props: { api: TuiPluginApi }) {
<Show when={toggleViewShortcut()}> <Show when={toggleViewShortcut()}>
{(shortcut) => ( {(shortcut) => (
<text fg={theme().text}> <text fg={theme().text}>
{shortcut()} <span style={{ fg: theme().textMuted }}>{view() === "split" ? "unified view" : "split view"}</span> {shortcut()}{" "}
<span style={{ fg: theme().textMuted }}>{view() === "split" ? "unified view" : "split view"}</span>
</text> </text>
)} )}
</Show> </Show>