@tooee/view 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react";
2
+ import type { HunkDiffFile } from "@tooee/diff";
3
+ export interface DiffFilePickerOverlayProps {
4
+ files: readonly HunkDiffFile[];
5
+ onSelect: (fileIndex: number) => void;
6
+ close: () => void;
7
+ }
8
+ /**
9
+ * Fuzzy file picker for a diff. Entries are indexed by position so two files
10
+ * with the same path (a rename pair, say) still resolve to distinct rows.
11
+ */
12
+ export declare const DiffFilePickerOverlay: ({ files, onSelect, close, }: DiffFilePickerOverlayProps) => ReactNode;
13
+ //# sourceMappingURL=diff-file-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-file-picker.d.ts","sourceRoot":"","sources":["../../src/components/diff-file-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,gCAI/B,0BAA0B,KAAG,SAkB/B,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
+ import { CommandPalette } from "@tooee/renderers";
3
+ /**
4
+ * Fuzzy file picker for a diff. Entries are indexed by position so two files
5
+ * with the same path (a rename pair, say) still resolve to distinct rows.
6
+ */
7
+ export const DiffFilePickerOverlay = function DiffFilePickerOverlay({ files, onSelect, close, }) {
8
+ const entries = files.map((file, index) => ({
9
+ id: String(index),
10
+ title: `${file.previousPath === undefined ? "" : `${file.previousPath} -> `}${file.path ?? file.id} +${file.stats.additions} -${file.stats.deletions}`,
11
+ }));
12
+ return (_jsx(CommandPalette, { commands: entries, onClose: close, onSelect: (id) => {
13
+ onSelect(Number(id));
14
+ close();
15
+ } }));
16
+ };
17
+ //# sourceMappingURL=diff-file-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-file-picker.js","sourceRoot":"","sources":["../../src/components/diff-file-picker.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASlD;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,qBAAqB,CAAC,EAClE,KAAK,EACL,QAAQ,EACR,KAAK,GACsB;IAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;QACjB,KAAK,EAAE,GAAG,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,MAAM,GACzE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EACpB,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;KACtD,CAAC,CAAC,CAAC;IAEJ,OAAO,CACL,KAAC,cAAc,IACb,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,KAAK,EACd,QAAQ,EAAE,CAAC,EAAU,EAAE,EAAE;YACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YACrB,KAAK,EAAE,CAAC;QACV,CAAC,GACD,CACH,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { DiffContent } from "../../types.js";
2
+ import type { SubviewProps } from "./types.js";
3
+ interface DiffSubviewProps extends SubviewProps {
4
+ content: DiffContent;
5
+ }
6
+ /**
7
+ * The built-in diff viewer: a Hunk-rendered patch inside Tooee's normal chrome.
8
+ *
9
+ * Hunk owns the drawing of each file header and hunk; the row document owns
10
+ * scrolling, the cursor, decorations and mouse routing. The cursor row maps 1:1
11
+ * onto Hunk's `{ fileId, hunkIndex }` selection, so `j`/`k` step hunk by hunk.
12
+ */
13
+ export declare const DiffSubview: ({ content, decorations, actions, ...screen }: DiffSubviewProps) => React.ReactNode;
14
+ export {};
15
+ //# sourceMappingURL=diff-subview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-subview.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/diff-subview.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,UAAU,gBAAiB,SAAQ,YAAY;IAC7C,OAAO,EAAE,WAAW,CAAC;CACtB;AAcD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,iDAKrB,gBAAgB,KAAG,KAAK,CAAC,SAyL3B,CAAC"}
@@ -0,0 +1,166 @@
1
+ import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
+ import { createElement, useCallback, useMemo, useState } from "react";
3
+ import { DiffView, buildDiffModel, diffRowAdapter } from "@tooee/diff";
4
+ import { useCommand } from "@tooee/commands";
5
+ import { useConfig } from "@tooee/config";
6
+ import { useOverlay } from "@tooee/overlays";
7
+ import { useDocumentController } from "@tooee/shell";
8
+ import { useContentCommands } from "../../hooks/use-content-commands.js";
9
+ import { ViewScreen } from "../view-screen.js";
10
+ import { DiffFilePickerOverlay } from "../diff-file-picker.js";
11
+ /** Columns panned per h/l press when a hunk is wider than the viewport. */
12
+ const HSCROLL_STEP = 4;
13
+ const FILE_PICKER_OVERLAY = "diff-file-picker";
14
+ /**
15
+ * Rows are file headers and hunks, so `getText` is the row's patch text and
16
+ * `getSource` its span in the original patch: search, copy and marks all work
17
+ * in real patch coordinates rather than in rendered diff lines.
18
+ */
19
+ const DIFF_ROW_ADAPTER = diffRowAdapter;
20
+ /**
21
+ * The built-in diff viewer: a Hunk-rendered patch inside Tooee's normal chrome.
22
+ *
23
+ * Hunk owns the drawing of each file header and hunk; the row document owns
24
+ * scrolling, the cursor, decorations and mouse routing. The cursor row maps 1:1
25
+ * onto Hunk's `{ fileId, hunkIndex }` selection, so `j`/`k` step hunk by hunk.
26
+ */
27
+ export const DiffSubview = function DiffSubview({ content, decorations, actions, ...screen }) {
28
+ const config = useConfig();
29
+ const overlay = useOverlay();
30
+ const textContent = content.patch;
31
+ const model = useMemo(() => buildDiffModel(content.patch), [content.patch]);
32
+ const [layout, setLayout] = useState(content.layout ?? config.view?.diffLayout ?? "stack");
33
+ const [wrapLines, setWrapLines] = useState(config.view?.wrap ?? false);
34
+ const [horizontalOffset, setHorizontalOffset] = useState(0);
35
+ const { showLineNumbers } = useContentCommands({ content, textContent });
36
+ const document = useDocumentController({
37
+ adapter: DIFF_ROW_ADAPTER,
38
+ // The controller projects the screen's actions onto menu entries at open time.
39
+ contextMenu: actions,
40
+ decorations,
41
+ multiSelect: true,
42
+ preserveCursorByKey: true,
43
+ rows: model.rows,
44
+ });
45
+ const { activeIndex } = document;
46
+ // `setCursor` rather than `selectRow`: the latter stands down while a modal
47
+ // overlay is open, which is exactly when the file picker commits its choice.
48
+ const { setCursor } = document.navigation;
49
+ /** Index of the file-header row for `fileIndex`, or `null` when absent. */
50
+ const fileRowIndex = useCallback((fileIndex) => {
51
+ const index = model.rows.findIndex((row) => row.kind === "file" && row.fileIndex === fileIndex);
52
+ return index === -1 ? null : index;
53
+ }, [model.rows]);
54
+ const jumpFile = useCallback((delta) => {
55
+ const current = activeIndex === null ? undefined : model.rows[activeIndex];
56
+ const from = current?.fileIndex ?? 0;
57
+ const target = Math.min(Math.max(from + delta, 0), model.files.length - 1);
58
+ const index = fileRowIndex(target);
59
+ if (index !== null) {
60
+ setCursor(index);
61
+ }
62
+ }, [activeIndex, fileRowIndex, model.files.length, model.rows, setCursor]);
63
+ useCommand({
64
+ handler: () => {
65
+ setLayout((value) => (value === "split" ? "stack" : "split"));
66
+ },
67
+ hotkey: "s",
68
+ id: "diff.toggle-layout",
69
+ modes: ["cursor", "select"],
70
+ title: "Toggle split/unified diff",
71
+ });
72
+ useCommand({
73
+ handler: () => {
74
+ setWrapLines((value) => !value);
75
+ setHorizontalOffset(0);
76
+ },
77
+ hotkey: "w",
78
+ id: "diff.toggle-wrap",
79
+ modes: ["cursor", "select"],
80
+ title: "Toggle diff line wrapping",
81
+ });
82
+ useCommand({
83
+ handler: () => {
84
+ jumpFile(1);
85
+ },
86
+ hotkey: "]",
87
+ id: "diff.next-file",
88
+ modes: ["cursor", "select"],
89
+ title: "Next file",
90
+ });
91
+ useCommand({
92
+ handler: () => {
93
+ jumpFile(-1);
94
+ },
95
+ hotkey: "[",
96
+ id: "diff.prev-file",
97
+ modes: ["cursor", "select"],
98
+ title: "Previous file",
99
+ });
100
+ useCommand({
101
+ handler: () => {
102
+ setHorizontalOffset((value) => Math.max(0, value - HSCROLL_STEP));
103
+ },
104
+ hotkey: "h",
105
+ id: "diff.scroll-left",
106
+ modes: ["cursor"],
107
+ title: "Pan diff left",
108
+ when: () => !wrapLines,
109
+ });
110
+ useCommand({
111
+ handler: () => {
112
+ setHorizontalOffset((value) => value + HSCROLL_STEP);
113
+ },
114
+ hotkey: "l",
115
+ id: "diff.scroll-right",
116
+ modes: ["cursor"],
117
+ title: "Pan diff right",
118
+ when: () => !wrapLines,
119
+ });
120
+ useCommand({
121
+ handler: () => {
122
+ overlay.open(FILE_PICKER_OVERLAY, ({ close }) => createElement(DiffFilePickerOverlay, {
123
+ close: () => {
124
+ close();
125
+ },
126
+ files: model.files,
127
+ onSelect: (fileIndex) => {
128
+ const index = fileRowIndex(fileIndex);
129
+ if (index !== null) {
130
+ setCursor(index);
131
+ }
132
+ },
133
+ }), null, { ownCommands: true, role: "modal", surfaceMode: "insert" });
134
+ },
135
+ hotkey: "f",
136
+ id: "diff.file-picker",
137
+ modes: ["cursor", "select"],
138
+ title: "Go to file",
139
+ });
140
+ const activeRow = activeIndex === null ? undefined : model.rows[activeIndex];
141
+ const statusItems = useMemo(() => [
142
+ { label: "Format:", value: content.format },
143
+ { label: "Files:", value: String(model.files.length) },
144
+ { label: "Changes:", value: `+${model.stats.additions} -${model.stats.deletions}` },
145
+ { label: "Layout:", value: layout },
146
+ ...(activeRow
147
+ ? [
148
+ {
149
+ label: "At:",
150
+ value: activeRow.hunkIndex >= 0
151
+ ? `${activeRow.parent.path ?? activeRow.fileId}:${activeRow.hunkIndex + 1}`
152
+ : (activeRow.parent.path ?? activeRow.fileId),
153
+ },
154
+ ]
155
+ : []),
156
+ ], [
157
+ activeRow,
158
+ content.format,
159
+ layout,
160
+ model.files.length,
161
+ model.stats.additions,
162
+ model.stats.deletions,
163
+ ]);
164
+ return (_jsx(ViewScreen, { content: content, controller: document, actions: actions, statusItems: statusItems, ...screen, children: _jsx(DiffView, { rows: model.rows, document: document, activeIndex: activeIndex, showLineNumbers: showLineNumbers, layout: layout, wrapLines: wrapLines, horizontalOffset: horizontalOffset }) }));
165
+ };
166
+ //# sourceMappingURL=diff-subview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-subview.js","sourceRoot":"","sources":["../../../src/components/subviews/diff-subview.tsx"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ export { MarkdownSubview } from "./markdown-subview.js";
2
2
  export { CodeSubview } from "./code-subview.js";
3
3
  export { ImageSubview } from "./image-subview.js";
4
4
  export { TableSubview } from "./table-subview.js";
5
+ export { DiffSubview } from "./diff-subview.js";
5
6
  export { CustomSubview } from "./custom-subview.js";
6
7
  export type { SubviewProps } from "./types.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -2,5 +2,6 @@ export { MarkdownSubview } from "./markdown-subview.js";
2
2
  export { CodeSubview } from "./code-subview.js";
3
3
  export { ImageSubview } from "./image-subview.js";
4
4
  export { TableSubview } from "./table-subview.js";
5
+ export { DiffSubview } from "./diff-subview.js";
5
6
  export { CustomSubview } from "./custom-subview.js";
6
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/subviews/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/subviews/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"default-provider.d.ts","sourceRoot":"","sources":["../src/default-provider.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AA2FD,eAAO,MAAM,kBAAkB,aACnB,MAAM,YACP,qBAAqB,KAC7B,eAoBF,CAAC;AAEF,eAAO,MAAM,mBAAmB,aACrB,qBAAqB,KAC7B,eAQF,CAAC;AAEF,eAAO,MAAM,uBAAuB,aACxB,MAAM,KACf,eAEF,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAAwC,eAE5E,CAAC"}
1
+ {"version":3,"file":"default-provider.d.ts","sourceRoot":"","sources":["../src/default-provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAW,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAmGD,eAAO,MAAM,kBAAkB,aACnB,MAAM,YACP,qBAAqB,KAC7B,eAyBF,CAAC;AAEF,eAAO,MAAM,mBAAmB,aACrB,qBAAqB,KAC7B,eAQF,CAAC;AAEF,eAAO,MAAM,uBAAuB,aACxB,MAAM,KACf,eAEF,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAAwC,eAE5E,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { parseAuto } from "@tooee/renderers";
3
+ import { isDiffPatch } from "@tooee/diff";
3
4
  const detectFormat = function detectFormat(filePath) {
4
5
  const ext = filePath.split(".").pop()?.toLowerCase();
5
6
  if (ext === undefined || ext === "") {
@@ -13,6 +14,10 @@ const detectFormat = function detectFormat(filePath) {
13
14
  if (tableExts.has(ext)) {
14
15
  return { format: "table" };
15
16
  }
17
+ const diffExts = new Set(["diff", "patch"]);
18
+ if (diffExts.has(ext)) {
19
+ return { format: "diff" };
20
+ }
16
21
  const markdownExts = new Set(["md", "mdx", "markdown"]);
17
22
  if (markdownExts.has(ext)) {
18
23
  return { format: "markdown" };
@@ -58,6 +63,9 @@ const contentFromText = function contentFromText(text, format, title, language)
58
63
  case "code": {
59
64
  return { code: text, format: "code", language, title };
60
65
  }
66
+ case "diff": {
67
+ return { format: "diff", patch: text, title };
68
+ }
61
69
  case "table": {
62
70
  const parsed = parseAuto(text);
63
71
  return { columns: parsed.columns, format: "table", rows: parsed.rows, title };
@@ -84,7 +92,11 @@ export const createFileProvider = function createFileProvider(filePath, options
84
92
  }
85
93
  const file = Bun.file(filePath);
86
94
  const text = await file.text();
87
- const content = contentFromText(text, format, title, detected.language);
95
+ // Patches are routinely written to files with no telling extension.
96
+ const resolved = options.renderer === undefined && detected.format === "text" && isDiffPatch(text)
97
+ ? "diff"
98
+ : format;
99
+ const content = contentFromText(text, resolved, title, detected.language);
88
100
  if (content.format === "markdown") {
89
101
  content.imageBasePath = path.dirname(path.resolve(filePath));
90
102
  }
@@ -96,7 +108,7 @@ export const createStdinProvider = function createStdinProvider(options = {}) {
96
108
  return {
97
109
  async load() {
98
110
  const text = await new Response(Bun.stdin.stream()).text();
99
- const format = options.renderer ?? "markdown";
111
+ const format = options.renderer ?? (isDiffPatch(text) ? "diff" : "markdown");
100
112
  return contentFromText(text, format, "stdin");
101
113
  },
102
114
  };
@@ -1 +1 @@
1
- {"version":3,"file":"default-provider.js","sourceRoot":"","sources":["../src/default-provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"default-provider.js","sourceRoot":"","sources":["../src/default-provider.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { listDirectoryFiles } from "./directory-provider.js";
8
8
  export type { DirectoryEntry } from "./directory-provider.js";
9
9
  export { createViewCommandContext, useProvideViewCommandContext, } from "./hooks/use-view-command-context.js";
10
10
  export type { CreateViewCommandContextOptions, ProvideViewCommandContextOptions, ViewCommandContext, } from "./hooks/use-view-command-context.js";
11
- export type { AnyContent, Content, ContentChunk, ContentFormat, ContentProvider, ContentRenderer, ContentRendererProps, CustomContent, ImageContent, MarkdownContent, CodeContent, TextContent, TableContent, ViewContent, ViewContentProvider, ColumnDef, TableRow, } from "./types.js";
11
+ export type { AnyContent, Content, ContentChunk, ContentFormat, ContentProvider, ContentRenderer, ContentRendererProps, CustomContent, DiffContent, ImageContent, MarkdownContent, CodeContent, TextContent, TableContent, ViewContent, ViewContentProvider, ColumnDef, TableRow, } from "./types.js";
12
12
  export { getTextContent, isBuiltinContent, isCustomContent } from "./types.js";
13
13
  export { CodeBlockChrome } from "@tooee/renderers";
14
14
  export type { CodeBlockRenderer, CodeBlockRendererProps, CodeBlockHScroll } from "@tooee/renderers";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,+BAA+B,EAC/B,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,UAAU,EACV,OAAO,EACP,YAAY,EACZ,aAAa,EACb,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,+BAA+B,EAC/B,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,UAAU,EACV,OAAO,EACP,YAAY,EACZ,aAAa,EACb,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,qCAAqC,CAAC;AAyB7C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,qCAAqC,CAAC;AA0B7C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { ImageFit, ImageRenderProtocol, ImageSource } from "@opentui/core";
3
3
  import type { ColumnDef, SourceLineRow, TableRow } from "@tooee/renderers";
4
4
  import type { DocumentController } from "@tooee/shell";
5
5
  import type { MarkSet } from "@tooee/marks";
6
- export type Content = MarkdownContent | CodeContent | TextContent | ImageContent | TableContent;
6
+ export type Content = MarkdownContent | CodeContent | TextContent | ImageContent | TableContent | DiffContent;
7
7
  export type ContentFormat = Content["format"];
8
8
  interface BaseContent {
9
9
  title?: string;
@@ -35,6 +35,13 @@ export interface TableContent extends BaseContent {
35
35
  columns: ColumnDef[];
36
36
  rows: TableRow[];
37
37
  }
38
+ export interface DiffContent extends BaseContent {
39
+ format: "diff";
40
+ /** Unified patch text, single- or multi-file. */
41
+ patch: string;
42
+ /** Initial layout; defaults to stacked (unified). */
43
+ layout?: "split" | "stack";
44
+ }
38
45
  export interface CustomContent<T = unknown> {
39
46
  format: string;
40
47
  data: T;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // === Utilities ===
2
- const BUILTIN_FORMATS = new Set(["markdown", "code", "text", "image", "table"]);
2
+ const BUILTIN_FORMATS = new Set(["markdown", "code", "text", "image", "table", "diff"]);
3
3
  export const isBuiltinContent = function isBuiltinContent(content) {
4
4
  return BUILTIN_FORMATS.has(content.format);
5
5
  };
@@ -52,6 +52,9 @@ export const getTextContent = function getTextContent(content) {
52
52
  case "code": {
53
53
  return content.code;
54
54
  }
55
+ case "diff": {
56
+ return content.patch;
57
+ }
55
58
  case "text": {
56
59
  return content.text;
57
60
  }
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE/E,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAUnE,UAAU,SAAS;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACvD,kEAAkE;IAClE,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;CAC9C;AAED,eAAO,MAAM,IAAI,yFAMd,SAAS,KAAG,KAAK,CAAC,SAkFpB,CAAC"}
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAG/E,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAWnE,UAAU,SAAS;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACvD,kEAAkE;IAClE,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;CAC9C;AAED,eAAO,MAAM,IAAI,yFAMd,SAAS,KAAG,KAAK,CAAC,SA4FpB,CAAC"}
package/dist/view.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
2
  import { useCallback, useMemo, useState } from "react";
3
3
  import { useTheme } from "@tooee/themes";
4
+ import { DIFF_CODE_BLOCK_RENDERERS } from "@tooee/diff";
4
5
  import { isCustomContent } from "./types.js";
5
6
  import { useContentLoader } from "./hooks/use-content-loader.js";
6
- import { MarkdownSubview, CodeSubview, TableSubview, ImageSubview, CustomSubview, } from "./components/subviews/index.js";
7
+ import { MarkdownSubview, CodeSubview, TableSubview, ImageSubview, DiffSubview, CustomSubview, } from "./components/subviews/index.js";
7
8
  export const View = function View({ contentProvider, actions, renderers, codeBlockRenderers, onMarkdownLinkActivate, }) {
8
9
  const { theme } = useTheme();
9
10
  const { content, streaming, error, providerMarks, reload } = useContentLoader(contentProvider);
@@ -23,6 +24,9 @@ export const View = function View({ contentProvider, actions, renderers, codeBlo
23
24
  // Mark sets are decoration layers; the controller composes them with the
24
25
  // interaction layers it generates, ordered by each set's own priority.
25
26
  const decorations = useMemo(() => [...providerMarks, ...userMarks], [providerMarks, userMarks]);
27
+ // ```diff / ```patch fences render as Hunk diff blocks unless the host
28
+ // registers its own renderer for those types.
29
+ const mergedCodeBlockRenderers = useMemo(() => ({ ...DIFF_CODE_BLOCK_RENDERERS, ...codeBlockRenderers }), [codeBlockRenderers]);
26
30
  if ((error?.length ?? 0) > 0) {
27
31
  return (_jsx("box", { style: { flexDirection: "column" }, children: _jsx("text", { content: `Error: ${error}`, fg: theme.error }) }));
28
32
  }
@@ -45,7 +49,7 @@ export const View = function View({ contentProvider, actions, renderers, codeBlo
45
49
  }
46
50
  switch (content.format) {
47
51
  case "markdown": {
48
- return (_jsx(MarkdownSubview, { content: content, codeBlockRenderers: codeBlockRenderers, onLinkActivate: onMarkdownLinkActivate, ...shared }));
52
+ return (_jsx(MarkdownSubview, { content: content, codeBlockRenderers: mergedCodeBlockRenderers, onLinkActivate: onMarkdownLinkActivate, ...shared }));
49
53
  }
50
54
  case "code":
51
55
  case "text": {
@@ -57,6 +61,9 @@ export const View = function View({ contentProvider, actions, renderers, codeBlo
57
61
  case "table": {
58
62
  return _jsx(TableSubview, { content: content, ...shared });
59
63
  }
64
+ case "diff": {
65
+ return _jsx(DiffSubview, { content: content, ...shared });
66
+ }
60
67
  default: {
61
68
  return null;
62
69
  }
package/dist/view.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tooee/view",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Terminal content viewer for markdown, code, text, images, and tables",
5
5
  "keywords": [
6
6
  "cli",
@@ -40,15 +40,16 @@
40
40
  "typecheck": "tsc --noEmit"
41
41
  },
42
42
  "dependencies": {
43
- "@tooee/commands": "0.6.2",
44
- "@tooee/config": "0.6.2",
45
- "@tooee/layout": "0.6.2",
46
- "@tooee/marks": "0.6.2",
47
- "@tooee/overlays": "0.6.2",
48
- "@tooee/renderers": "0.6.2",
49
- "@tooee/search": "0.6.2",
50
- "@tooee/shell": "0.6.2",
51
- "@tooee/themes": "0.6.2",
43
+ "@tooee/commands": "0.7.0",
44
+ "@tooee/config": "0.7.0",
45
+ "@tooee/diff": "0.7.0",
46
+ "@tooee/layout": "0.7.0",
47
+ "@tooee/marks": "0.7.0",
48
+ "@tooee/overlays": "0.7.0",
49
+ "@tooee/renderers": "0.7.0",
50
+ "@tooee/search": "0.7.0",
51
+ "@tooee/shell": "0.7.0",
52
+ "@tooee/themes": "0.7.0",
52
53
  "@xstate/store": "^4",
53
54
  "@xstate/store-react": "^2",
54
55
  "marked": "^17.0.4"
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from "react";
2
+ import { CommandPalette } from "@tooee/renderers";
3
+ import type { HunkDiffFile } from "@tooee/diff";
4
+
5
+ export interface DiffFilePickerOverlayProps {
6
+ files: readonly HunkDiffFile[];
7
+ onSelect: (fileIndex: number) => void;
8
+ close: () => void;
9
+ }
10
+
11
+ /**
12
+ * Fuzzy file picker for a diff. Entries are indexed by position so two files
13
+ * with the same path (a rename pair, say) still resolve to distinct rows.
14
+ */
15
+ export const DiffFilePickerOverlay = function DiffFilePickerOverlay({
16
+ files,
17
+ onSelect,
18
+ close,
19
+ }: DiffFilePickerOverlayProps): ReactNode {
20
+ const entries = files.map((file, index) => ({
21
+ id: String(index),
22
+ title: `${file.previousPath === undefined ? "" : `${file.previousPath} -> `}${
23
+ file.path ?? file.id
24
+ } +${file.stats.additions} -${file.stats.deletions}`,
25
+ }));
26
+
27
+ return (
28
+ <CommandPalette
29
+ commands={entries}
30
+ onClose={close}
31
+ onSelect={(id: string) => {
32
+ onSelect(Number(id));
33
+ close();
34
+ }}
35
+ />
36
+ );
37
+ };
@@ -0,0 +1,229 @@
1
+ import { createElement, useCallback, useMemo, useState } from "react";
2
+ import { DiffView, buildDiffModel, diffRowAdapter } from "@tooee/diff";
3
+ import type { DiffRow } from "@tooee/diff";
4
+ import { useCommand } from "@tooee/commands";
5
+ import { useConfig } from "@tooee/config";
6
+ import { useOverlay } from "@tooee/overlays";
7
+ import type { OverlayCloseReason } from "@tooee/overlays";
8
+ import { useDocumentController } from "@tooee/shell";
9
+ import type { DocumentRowAdapter } from "@tooee/shell";
10
+ import type { DiffContent } from "../../types.js";
11
+ import { useContentCommands } from "../../hooks/use-content-commands.js";
12
+ import { ViewScreen } from "../view-screen.js";
13
+ import { DiffFilePickerOverlay } from "../diff-file-picker.js";
14
+ import type { SubviewProps } from "./types.js";
15
+
16
+ interface DiffSubviewProps extends SubviewProps {
17
+ content: DiffContent;
18
+ }
19
+
20
+ /** Columns panned per h/l press when a hunk is wider than the viewport. */
21
+ const HSCROLL_STEP = 4;
22
+
23
+ const FILE_PICKER_OVERLAY = "diff-file-picker";
24
+
25
+ /**
26
+ * Rows are file headers and hunks, so `getText` is the row's patch text and
27
+ * `getSource` its span in the original patch: search, copy and marks all work
28
+ * in real patch coordinates rather than in rendered diff lines.
29
+ */
30
+ const DIFF_ROW_ADAPTER: DocumentRowAdapter<DiffRow> = diffRowAdapter;
31
+
32
+ /**
33
+ * The built-in diff viewer: a Hunk-rendered patch inside Tooee's normal chrome.
34
+ *
35
+ * Hunk owns the drawing of each file header and hunk; the row document owns
36
+ * scrolling, the cursor, decorations and mouse routing. The cursor row maps 1:1
37
+ * onto Hunk's `{ fileId, hunkIndex }` selection, so `j`/`k` step hunk by hunk.
38
+ */
39
+ export const DiffSubview = function DiffSubview({
40
+ content,
41
+ decorations,
42
+ actions,
43
+ ...screen
44
+ }: DiffSubviewProps): React.ReactNode {
45
+ const config = useConfig();
46
+ const overlay = useOverlay();
47
+ const textContent = content.patch;
48
+ const model = useMemo(() => buildDiffModel(content.patch), [content.patch]);
49
+
50
+ const [layout, setLayout] = useState<"split" | "stack">(
51
+ content.layout ?? config.view?.diffLayout ?? "stack",
52
+ );
53
+ const [wrapLines, setWrapLines] = useState(config.view?.wrap ?? false);
54
+ const [horizontalOffset, setHorizontalOffset] = useState(0);
55
+
56
+ const { showLineNumbers } = useContentCommands({ content, textContent });
57
+
58
+ const document = useDocumentController<DiffRow>({
59
+ adapter: DIFF_ROW_ADAPTER,
60
+ // The controller projects the screen's actions onto menu entries at open time.
61
+ contextMenu: actions,
62
+ decorations,
63
+ multiSelect: true,
64
+ preserveCursorByKey: true,
65
+ rows: model.rows,
66
+ });
67
+
68
+ const { activeIndex } = document;
69
+ // `setCursor` rather than `selectRow`: the latter stands down while a modal
70
+ // overlay is open, which is exactly when the file picker commits its choice.
71
+ const { setCursor } = document.navigation;
72
+
73
+ /** Index of the file-header row for `fileIndex`, or `null` when absent. */
74
+ const fileRowIndex = useCallback(
75
+ (fileIndex: number): number | null => {
76
+ const index = model.rows.findIndex(
77
+ (row) => row.kind === "file" && row.fileIndex === fileIndex,
78
+ );
79
+ return index === -1 ? null : index;
80
+ },
81
+ [model.rows],
82
+ );
83
+
84
+ const jumpFile = useCallback(
85
+ (delta: number) => {
86
+ const current = activeIndex === null ? undefined : model.rows[activeIndex];
87
+ const from = current?.fileIndex ?? 0;
88
+ const target = Math.min(Math.max(from + delta, 0), model.files.length - 1);
89
+ const index = fileRowIndex(target);
90
+ if (index !== null) {
91
+ setCursor(index);
92
+ }
93
+ },
94
+ [activeIndex, fileRowIndex, model.files.length, model.rows, setCursor],
95
+ );
96
+
97
+ useCommand({
98
+ handler: () => {
99
+ setLayout((value) => (value === "split" ? "stack" : "split"));
100
+ },
101
+ hotkey: "s",
102
+ id: "diff.toggle-layout",
103
+ modes: ["cursor", "select"],
104
+ title: "Toggle split/unified diff",
105
+ });
106
+ useCommand({
107
+ handler: () => {
108
+ setWrapLines((value) => !value);
109
+ setHorizontalOffset(0);
110
+ },
111
+ hotkey: "w",
112
+ id: "diff.toggle-wrap",
113
+ modes: ["cursor", "select"],
114
+ title: "Toggle diff line wrapping",
115
+ });
116
+ useCommand({
117
+ handler: () => {
118
+ jumpFile(1);
119
+ },
120
+ hotkey: "]",
121
+ id: "diff.next-file",
122
+ modes: ["cursor", "select"],
123
+ title: "Next file",
124
+ });
125
+ useCommand({
126
+ handler: () => {
127
+ jumpFile(-1);
128
+ },
129
+ hotkey: "[",
130
+ id: "diff.prev-file",
131
+ modes: ["cursor", "select"],
132
+ title: "Previous file",
133
+ });
134
+ useCommand({
135
+ handler: () => {
136
+ setHorizontalOffset((value) => Math.max(0, value - HSCROLL_STEP));
137
+ },
138
+ hotkey: "h",
139
+ id: "diff.scroll-left",
140
+ modes: ["cursor"],
141
+ title: "Pan diff left",
142
+ when: () => !wrapLines,
143
+ });
144
+ useCommand({
145
+ handler: () => {
146
+ setHorizontalOffset((value) => value + HSCROLL_STEP);
147
+ },
148
+ hotkey: "l",
149
+ id: "diff.scroll-right",
150
+ modes: ["cursor"],
151
+ title: "Pan diff right",
152
+ when: () => !wrapLines,
153
+ });
154
+ useCommand({
155
+ handler: () => {
156
+ overlay.open(
157
+ FILE_PICKER_OVERLAY,
158
+ ({ close }: { close: (reason?: OverlayCloseReason) => void }) =>
159
+ createElement(DiffFilePickerOverlay, {
160
+ close: () => {
161
+ close();
162
+ },
163
+ files: model.files,
164
+ onSelect: (fileIndex: number) => {
165
+ const index = fileRowIndex(fileIndex);
166
+ if (index !== null) {
167
+ setCursor(index);
168
+ }
169
+ },
170
+ }),
171
+ null,
172
+ { ownCommands: true, role: "modal", surfaceMode: "insert" },
173
+ );
174
+ },
175
+ hotkey: "f",
176
+ id: "diff.file-picker",
177
+ modes: ["cursor", "select"],
178
+ title: "Go to file",
179
+ });
180
+
181
+ const activeRow = activeIndex === null ? undefined : model.rows[activeIndex];
182
+ const statusItems = useMemo(
183
+ () => [
184
+ { label: "Format:", value: content.format },
185
+ { label: "Files:", value: String(model.files.length) },
186
+ { label: "Changes:", value: `+${model.stats.additions} -${model.stats.deletions}` },
187
+ { label: "Layout:", value: layout },
188
+ ...(activeRow
189
+ ? [
190
+ {
191
+ label: "At:",
192
+ value:
193
+ activeRow.hunkIndex >= 0
194
+ ? `${activeRow.parent.path ?? activeRow.fileId}:${activeRow.hunkIndex + 1}`
195
+ : (activeRow.parent.path ?? activeRow.fileId),
196
+ },
197
+ ]
198
+ : []),
199
+ ],
200
+ [
201
+ activeRow,
202
+ content.format,
203
+ layout,
204
+ model.files.length,
205
+ model.stats.additions,
206
+ model.stats.deletions,
207
+ ],
208
+ );
209
+
210
+ return (
211
+ <ViewScreen
212
+ content={content}
213
+ controller={document}
214
+ actions={actions}
215
+ statusItems={statusItems}
216
+ {...screen}
217
+ >
218
+ <DiffView
219
+ rows={model.rows}
220
+ document={document}
221
+ activeIndex={activeIndex}
222
+ showLineNumbers={showLineNumbers}
223
+ layout={layout}
224
+ wrapLines={wrapLines}
225
+ horizontalOffset={horizontalOffset}
226
+ />
227
+ </ViewScreen>
228
+ );
229
+ };
@@ -2,5 +2,6 @@ export { MarkdownSubview } from "./markdown-subview.js";
2
2
  export { CodeSubview } from "./code-subview.js";
3
3
  export { ImageSubview } from "./image-subview.js";
4
4
  export { TableSubview } from "./table-subview.js";
5
+ export { DiffSubview } from "./diff-subview.js";
5
6
  export { CustomSubview } from "./custom-subview.js";
6
7
  export type { SubviewProps } from "./types.js";
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { parseAuto } from "@tooee/renderers";
3
+ import { isDiffPatch } from "@tooee/diff";
3
4
  import type { Content, ContentFormat, ContentProvider } from "./types.js";
4
5
 
5
6
  export interface CreateProviderOptions {
@@ -25,6 +26,11 @@ const detectFormat = function detectFormat(filePath: string): {
25
26
  return { format: "table" };
26
27
  }
27
28
 
29
+ const diffExts = new Set(["diff", "patch"]);
30
+ if (diffExts.has(ext)) {
31
+ return { format: "diff" };
32
+ }
33
+
28
34
  const markdownExts = new Set(["md", "mdx", "markdown"]);
29
35
  if (markdownExts.has(ext)) {
30
36
  return { format: "markdown" };
@@ -79,6 +85,9 @@ const contentFromText = function contentFromText(
79
85
  case "code": {
80
86
  return { code: text, format: "code", language, title };
81
87
  }
88
+ case "diff": {
89
+ return { format: "diff", patch: text, title };
90
+ }
82
91
  case "table": {
83
92
  const parsed = parseAuto(text);
84
93
  return { columns: parsed.columns, format: "table", rows: parsed.rows, title };
@@ -111,7 +120,12 @@ export const createFileProvider = function createFileProvider(
111
120
 
112
121
  const file = Bun.file(filePath);
113
122
  const text = await file.text();
114
- const content = contentFromText(text, format, title, detected.language);
123
+ // Patches are routinely written to files with no telling extension.
124
+ const resolved =
125
+ options.renderer === undefined && detected.format === "text" && isDiffPatch(text)
126
+ ? "diff"
127
+ : format;
128
+ const content = contentFromText(text, resolved, title, detected.language);
115
129
  if (content.format === "markdown") {
116
130
  content.imageBasePath = path.dirname(path.resolve(filePath));
117
131
  }
@@ -126,7 +140,7 @@ export const createStdinProvider = function createStdinProvider(
126
140
  return {
127
141
  async load(): Promise<Content> {
128
142
  const text = await new Response(Bun.stdin.stream()).text();
129
- const format = options.renderer ?? "markdown";
143
+ const format = options.renderer ?? (isDiffPatch(text) ? "diff" : "markdown");
130
144
  return contentFromText(text, format, "stdin");
131
145
  },
132
146
  };
package/src/index.ts CHANGED
@@ -29,6 +29,7 @@ export type {
29
29
  ContentRenderer,
30
30
  ContentRendererProps,
31
31
  CustomContent,
32
+ DiffContent,
32
33
  ImageContent,
33
34
  MarkdownContent,
34
35
  CodeContent,
package/src/types.ts CHANGED
@@ -6,7 +6,13 @@ import type { MarkSet } from "@tooee/marks";
6
6
 
7
7
  // === Built-in content types ===
8
8
 
9
- export type Content = MarkdownContent | CodeContent | TextContent | ImageContent | TableContent;
9
+ export type Content =
10
+ | MarkdownContent
11
+ | CodeContent
12
+ | TextContent
13
+ | ImageContent
14
+ | TableContent
15
+ | DiffContent;
10
16
 
11
17
  export type ContentFormat = Content["format"];
12
18
 
@@ -46,6 +52,14 @@ export interface TableContent extends BaseContent {
46
52
  rows: TableRow[];
47
53
  }
48
54
 
55
+ export interface DiffContent extends BaseContent {
56
+ format: "diff";
57
+ /** Unified patch text, single- or multi-file. */
58
+ patch: string;
59
+ /** Initial layout; defaults to stacked (unified). */
60
+ layout?: "split" | "stack";
61
+ }
62
+
49
63
  // === Custom content ===
50
64
 
51
65
  export interface CustomContent<T = unknown> {
@@ -122,7 +136,7 @@ export type { ColumnDef, TableRow } from "@tooee/renderers";
122
136
 
123
137
  // === Utilities ===
124
138
 
125
- const BUILTIN_FORMATS = new Set<string>(["markdown", "code", "text", "image", "table"]);
139
+ const BUILTIN_FORMATS = new Set<string>(["markdown", "code", "text", "image", "table", "diff"]);
126
140
 
127
141
  export const isBuiltinContent = function isBuiltinContent(content: AnyContent): content is Content {
128
142
  return BUILTIN_FORMATS.has(content.format);
@@ -184,6 +198,9 @@ export const getTextContent = function getTextContent(content: AnyContent): stri
184
198
  case "code": {
185
199
  return content.code;
186
200
  }
201
+ case "diff": {
202
+ return content.patch;
203
+ }
187
204
  case "text": {
188
205
  return content.text;
189
206
  }
package/src/view.tsx CHANGED
@@ -3,6 +3,7 @@ import { useTheme } from "@tooee/themes";
3
3
  import type { ActionDefinition } from "@tooee/commands";
4
4
  import type { MarkSet } from "@tooee/marks";
5
5
  import type { CodeBlockRenderer, MarkdownLinkHandler } from "@tooee/renderers";
6
+ import { DIFF_CODE_BLOCK_RENDERERS } from "@tooee/diff";
6
7
  import { isCustomContent } from "./types.js";
7
8
  import type { ContentProvider, ContentRenderer } from "./types.js";
8
9
  import { useContentLoader } from "./hooks/use-content-loader.js";
@@ -11,6 +12,7 @@ import {
11
12
  CodeSubview,
12
13
  TableSubview,
13
14
  ImageSubview,
15
+ DiffSubview,
14
16
  CustomSubview,
15
17
  } from "./components/subviews/index.js";
16
18
 
@@ -58,6 +60,13 @@ export const View = function View({
58
60
  // interaction layers it generates, ordered by each set's own priority.
59
61
  const decorations = useMemo(() => [...providerMarks, ...userMarks], [providerMarks, userMarks]);
60
62
 
63
+ // ```diff / ```patch fences render as Hunk diff blocks unless the host
64
+ // registers its own renderer for those types.
65
+ const mergedCodeBlockRenderers = useMemo(
66
+ () => ({ ...DIFF_CODE_BLOCK_RENDERERS, ...codeBlockRenderers }),
67
+ [codeBlockRenderers],
68
+ );
69
+
61
70
  if ((error?.length ?? 0) > 0) {
62
71
  return (
63
72
  <box style={{ flexDirection: "column" }}>
@@ -95,7 +104,7 @@ export const View = function View({
95
104
  return (
96
105
  <MarkdownSubview
97
106
  content={content}
98
- codeBlockRenderers={codeBlockRenderers}
107
+ codeBlockRenderers={mergedCodeBlockRenderers}
99
108
  onLinkActivate={onMarkdownLinkActivate}
100
109
  {...shared}
101
110
  />
@@ -111,6 +120,9 @@ export const View = function View({
111
120
  case "table": {
112
121
  return <TableSubview content={content} {...shared} />;
113
122
  }
123
+ case "diff": {
124
+ return <DiffSubview content={content} {...shared} />;
125
+ }
114
126
  default: {
115
127
  return null;
116
128
  }