@herbertgao/pi-extensions 2026.9.18 → 2026.9.20
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.
- package/README.md +20 -28
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +76 -59
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +76 -59
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/preview.webp +0 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +93 -34
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +346 -117
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +6 -36
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/index.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -29
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +330 -360
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/index.ts +56 -108
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/session.ts +97 -15
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/subagent.ts +80 -45
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/flush-docked-bash.ts +36 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer-layout.ts +229 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +479 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/startup-header.ts +92 -61
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/working-message.ts +75 -40
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +19 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +1080 -229
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +232 -259
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +42 -41
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +8 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +2 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +277 -113
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +15 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +18 -72
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +61 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts +25 -57
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-component.ts +125 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-edit-render.ts +227 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +136 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +115 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-inline.ts +324 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-layout.ts +762 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-limits.ts +152 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-palette.ts +410 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-parse.ts +535 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +21 -3219
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-text.ts +44 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +568 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +47 -10
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +145 -190
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/mcp-title.ts +39 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{message-display.ts → tool/message-display.ts} +24 -90
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +426 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +90 -132
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{show-more-hint.ts → tool/show-more-hint.ts} +10 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +8 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-color.ts +44 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +76 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/component-tree.ts +34 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/format.ts +28 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +51 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/patch-keys.ts +124 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/sgr-mouse.ts +70 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +8 -8
- package/node_modules/pi-antigravity/README.md +29 -6
- package/node_modules/pi-antigravity/package.json +12 -7
- package/node_modules/pi-antigravity/src/auth/accounts.ts +327 -0
- package/node_modules/pi-antigravity/src/auth/index.ts +9 -0
- package/node_modules/pi-antigravity/src/client/client.ts +1 -1
- package/node_modules/pi-antigravity/src/image/image.ts +4 -4
- package/node_modules/pi-antigravity/src/index.ts +203 -13
- package/node_modules/pi-antigravity/src/search/index.ts +1 -0
- package/node_modules/pi-antigravity/src/search/search.ts +325 -0
- package/node_modules/pi-antigravity/src/stream/stream.ts +191 -14
- package/node_modules/pi-antigravity/src/types/enums.ts +45 -36
- package/node_modules/pi-antigravity/src/types/types.ts +5 -12
- package/node_modules/pi-antigravity/src/utils/http.ts +7 -2
- package/node_modules/pi-antigravity/src/utils/util.ts +31 -3
- package/node_modules/pi-typesafe/README.md +2 -0
- package/node_modules/pi-typesafe/package.json +2 -1
- package/node_modules/pi-web-access/CHANGELOG.md +72 -0
- package/node_modules/pi-web-access/README.md +34 -13
- package/node_modules/pi-web-access/chrome-cookies.ts +79 -25
- package/node_modules/pi-web-access/curator-page.ts +5 -1
- package/node_modules/pi-web-access/curator-server.ts +2 -0
- package/node_modules/pi-web-access/dist/index.js +1337 -1009
- package/node_modules/pi-web-access/exa.ts +20 -52
- package/node_modules/pi-web-access/extract.ts +41 -4
- package/node_modules/pi-web-access/gemini-search.ts +12 -4
- package/node_modules/pi-web-access/index.ts +29 -37
- package/node_modules/pi-web-access/openai-search.ts +35 -7
- package/node_modules/pi-web-access/package.json +6 -5
- package/node_modules/pi-web-access/page-query.ts +2 -2
- package/node_modules/pi-web-access/query-rewrite.ts +2 -3
- package/node_modules/pi-web-access/ssrf-protection.ts +27 -10
- package/node_modules/pi-web-access/storage.ts +48 -77
- package/node_modules/pi-web-access/summary-model-scope.ts +6 -77
- package/node_modules/pi-web-access/summary-review.ts +3 -4
- package/node_modules/pi-web-access/tavily.ts +67 -20
- package/node_modules/pi-web-access/tool-activation.ts +53 -33
- package/node_modules/pi-web-access/utils.ts +1 -1
- package/node_modules/pi-web-access/you.ts +164 -0
- package/node_modules/pi-web-access/zai.ts +161 -0
- package/package.json +7 -11
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +0 -101
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.svg +0 -101
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/welcome.webp +0 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/render-utils.ts +0 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +0 -30
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +0 -12
- package/node_modules/pi-footer/CHANGELOG.md +0 -145
- package/node_modules/pi-footer/LICENSE +0 -21
- package/node_modules/pi-footer/README.md +0 -354
- package/node_modules/pi-footer/package.json +0 -68
- package/node_modules/pi-footer/src/cache.ts +0 -106
- package/node_modules/pi-footer/src/colors.ts +0 -237
- package/node_modules/pi-footer/src/config.ts +0 -202
- package/node_modules/pi-footer/src/event-widgets.ts +0 -41
- package/node_modules/pi-footer/src/extension-statuses.ts +0 -102
- package/node_modules/pi-footer/src/git.ts +0 -135
- package/node_modules/pi-footer/src/index.ts +0 -268
- package/node_modules/pi-footer/src/metrics.ts +0 -141
- package/node_modules/pi-footer/src/presets.ts +0 -383
- package/node_modules/pi-footer/src/render.ts +0 -114
- package/node_modules/pi-footer/src/separators.ts +0 -52
- package/node_modules/pi-footer/src/types.ts +0 -122
- package/node_modules/pi-footer/src/ui/color-level-confirm.ts +0 -22
- package/node_modules/pi-footer/src/ui/color-options.ts +0 -195
- package/node_modules/pi-footer/src/ui/config-lifecycle.ts +0 -61
- package/node_modules/pi-footer/src/ui/edit-colors.ts +0 -13
- package/node_modules/pi-footer/src/ui/events.ts +0 -35
- package/node_modules/pi-footer/src/ui/extension-status-picker.ts +0 -60
- package/node_modules/pi-footer/src/ui/extension-statuses.ts +0 -73
- package/node_modules/pi-footer/src/ui/fields.ts +0 -252
- package/node_modules/pi-footer/src/ui/global-menu.ts +0 -126
- package/node_modules/pi-footer/src/ui/helpers.ts +0 -44
- package/node_modules/pi-footer/src/ui/layout.ts +0 -17
- package/node_modules/pi-footer/src/ui/line-list.ts +0 -19
- package/node_modules/pi-footer/src/ui/model.ts +0 -64
- package/node_modules/pi-footer/src/ui/navigation.ts +0 -29
- package/node_modules/pi-footer/src/ui/option-edit.ts +0 -93
- package/node_modules/pi-footer/src/ui/overlay-render.ts +0 -103
- package/node_modules/pi-footer/src/ui/screen-context.ts +0 -18
- package/node_modules/pi-footer/src/ui/screen-controller.ts +0 -27
- package/node_modules/pi-footer/src/ui/screen-render.ts +0 -32
- package/node_modules/pi-footer/src/ui/screen-state.ts +0 -20
- package/node_modules/pi-footer/src/ui/screen.ts +0 -243
- package/node_modules/pi-footer/src/ui/screens/add-widget.ts +0 -92
- package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +0 -52
- package/node_modules/pi-footer/src/ui/screens/controller.ts +0 -12
- package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +0 -68
- package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +0 -115
- package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +0 -61
- package/node_modules/pi-footer/src/ui/screens/global.ts +0 -75
- package/node_modules/pi-footer/src/ui/screens/line-list.ts +0 -108
- package/node_modules/pi-footer/src/ui/screens/main.ts +0 -99
- package/node_modules/pi-footer/src/ui/screens/terminal.ts +0 -121
- package/node_modules/pi-footer/src/ui/screens/widget-list.ts +0 -154
- package/node_modules/pi-footer/src/ui/terminal-menu.ts +0 -32
- package/node_modules/pi-footer/src/ui/theme.ts +0 -48
- package/node_modules/pi-footer/src/ui/title-bar.ts +0 -100
- package/node_modules/pi-footer/src/ui/widget-actions.ts +0 -76
- package/node_modules/pi-footer/src/ui.ts +0 -66
- package/node_modules/pi-footer/src/widgets/context.ts +0 -28
- package/node_modules/pi-footer/src/widgets/core/active-tools.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/context-window.ts +0 -24
- package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +0 -19
- package/node_modules/pi-footer/src/widgets/core/cwd.ts +0 -108
- package/node_modules/pi-footer/src/widgets/core/event.ts +0 -34
- package/node_modules/pi-footer/src/widgets/core/external-status.ts +0 -102
- package/node_modules/pi-footer/src/widgets/core/model-provider.ts +0 -20
- package/node_modules/pi-footer/src/widgets/core/model.ts +0 -35
- package/node_modules/pi-footer/src/widgets/core/provider.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/session-name.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/branch.ts +0 -81
- package/node_modules/pi-footer/src/widgets/git/clean.ts +0 -19
- package/node_modules/pi-footer/src/widgets/git/deletions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/diff.ts +0 -38
- package/node_modules/pi-footer/src/widgets/git/insertions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/remote.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/root.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/sha.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/staged.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/status.ts +0 -19
- package/node_modules/pi-footer/src/widgets/git/unstaged.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/untracked.ts +0 -17
- package/node_modules/pi-footer/src/widgets/instance.ts +0 -118
- package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +0 -18
- package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +0 -32
- package/node_modules/pi-footer/src/widgets/layout/separator.ts +0 -57
- package/node_modules/pi-footer/src/widgets/layout/spacer.ts +0 -31
- package/node_modules/pi-footer/src/widgets/options.ts +0 -122
- package/node_modules/pi-footer/src/widgets/project/runtime.ts +0 -361
- package/node_modules/pi-footer/src/widgets/registry.ts +0 -223
- package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/compactions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/elapsed.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/last-activity.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/messages.ts +0 -19
- package/node_modules/pi-footer/src/widgets/session/session-id.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/session-start.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/tool-results.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/total-messages.ts +0 -19
- package/node_modules/pi-footer/src/widgets/session/total-time.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/user-messages.ts +0 -17
- package/node_modules/pi-footer/src/widgets/store.ts +0 -26
- package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +0 -55
- package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +0 -108
- package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +0 -26
- package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +0 -29
- package/node_modules/pi-footer/src/widgets/tokens/context.ts +0 -29
- package/node_modules/pi-footer/src/widgets/tokens/cost.ts +0 -51
- package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +0 -20
- package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/types.ts +0 -181
- package/node_modules/pi-footer/src/widgets/utils/colors.ts +0 -11
- package/node_modules/pi-footer/src/widgets/utils/context.ts +0 -112
- package/node_modules/pi-footer/src/widgets/utils/session.ts +0 -19
- package/node_modules/pi-footer/src/widgets/utils/token-format.ts +0 -78
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
2
2
|
import { ThinkingPreviewBlock } from "../../feature/compact-thinking.ts";
|
|
3
3
|
import { isCompactAssistantComponent } from "../compact-mode.ts";
|
|
4
|
-
import { isMessageDisplayComponent } from "../message-display.ts";
|
|
5
4
|
import { ToolGroupComponent } from "../tool/grouping.ts";
|
|
5
|
+
import { isMessageDisplayComponent } from "../tool/message-display.ts";
|
|
6
6
|
import { isToolExecutionComponent, stripTerminalSequencesPreservingLayout } from "./packets.ts";
|
|
7
7
|
import { getScrollButtonWidget } from "./scroll.ts";
|
|
8
8
|
|
|
@@ -11,12 +11,17 @@ export type ComponentRowHit = {
|
|
|
11
11
|
row: number;
|
|
12
12
|
/** 内部工具命中时所属的展开 group;普通卡点击仍折叠整个 group。 */
|
|
13
13
|
group?: ToolGroupComponent;
|
|
14
|
+
/** compact 展开面板内的命中:外层面板,单击非提示区时收起它。 */
|
|
15
|
+
owner?: any;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
|
-
/** 行内 [click to show more] 提示的命中列区间(1-based,含两端)。 */
|
|
18
|
+
/** 行内 [click to show more] / [↑ Collapse] 提示的命中列区间(1-based,含两端)。 */
|
|
17
19
|
export function collapsedHintHitbox(line: string): { startCol: number; endCol: number } | null {
|
|
18
20
|
const plain = stripTerminalSequencesPreservingLayout(line);
|
|
19
|
-
const match =
|
|
21
|
+
const match =
|
|
22
|
+
/(\([^()\n]* \/ click\)|click to show more|to show more|↑ Collapse|to collapse)(?=\)?\s*$)/.exec(
|
|
23
|
+
plain,
|
|
24
|
+
);
|
|
20
25
|
if (!match?.[1]) return null;
|
|
21
26
|
const startCol = visibleWidth(plain.slice(0, match.index)) + 1;
|
|
22
27
|
return { startCol, endCol: startCol + visibleWidth(match[1]) - 1 };
|
|
@@ -119,11 +124,15 @@ export function componentAtLocalRow(
|
|
|
119
124
|
return { component, row: localRow };
|
|
120
125
|
}
|
|
121
126
|
if (isCompactAssistantComponent(component)) {
|
|
122
|
-
//
|
|
127
|
+
// 折叠:整行摘要。展开:先命中面板内 thinking/工具卡/文本,其余(空行)仍归外层卡片。
|
|
123
128
|
if (component.expanded === true) {
|
|
124
129
|
const inner = nestedChildAtRow(component, localRow, width);
|
|
125
|
-
if (inner
|
|
126
|
-
|
|
130
|
+
if (inner) {
|
|
131
|
+
// 展开的 thinking 有自己的展开态:点它只收它自己,不收整块面板。
|
|
132
|
+
const ownExpandable = inner instanceof ThinkingPreviewBlock && inner.expanded === true;
|
|
133
|
+
return ownExpandable
|
|
134
|
+
? { component: inner, row: localRow }
|
|
135
|
+
: { component: inner, row: localRow, owner: component };
|
|
127
136
|
}
|
|
128
137
|
}
|
|
129
138
|
return { component, row: localRow };
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { ExpandedToolIoView, ToolIoSection } from "../tool/result.ts";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import { walkComponentTree } from "../../utils/component-tree.ts";
|
|
3
|
+
export {
|
|
4
|
+
stripTerminalSequences,
|
|
5
|
+
stripTerminalSequencesPreservingLayout,
|
|
6
|
+
} from "../../utils/ansi-text.ts";
|
|
7
|
+
export {
|
|
8
|
+
parseSgrMousePackets,
|
|
9
|
+
isSgrLeftPress,
|
|
10
|
+
isSgrLeftRelease,
|
|
11
|
+
isSgrIdleMotion,
|
|
12
|
+
type SgrMousePacket,
|
|
13
|
+
} from "../../utils/sgr-mouse.ts";
|
|
10
14
|
|
|
11
15
|
/** Final painted placement of one outermost tool/group row after parent layout. */
|
|
12
16
|
export type FrameToolPlacement = {
|
|
@@ -24,53 +28,6 @@ const TOOL_FRAME_MARKER_RE = /\x1b_cc:t(\d+):(\d+)\x07/g;
|
|
|
24
28
|
const TOOL_VIEW_MARKER_RE = /\x1b_cc:v(\d+):([io])\x07/g;
|
|
25
29
|
export const toolFrameMarker = (id: number, row: number) => `\x1b_cc:t${id}:${row}\x07`;
|
|
26
30
|
|
|
27
|
-
/**
|
|
28
|
-
* 解析整段终端输入为 SGR 鼠标包序列;数据必须完全由连续 SGR 包组成
|
|
29
|
-
* (夹杂其他字节返回 null,交由常规输入链处理)。
|
|
30
|
-
*/
|
|
31
|
-
export function parseSgrMousePackets(data: string): SgrMousePacket[] | null {
|
|
32
|
-
const pattern = /\x1b\[<(\d+);(\d+);(\d+)([Mm])/g;
|
|
33
|
-
const packets: SgrMousePacket[] = [];
|
|
34
|
-
let offset = 0;
|
|
35
|
-
|
|
36
|
-
for (const match of data.matchAll(pattern)) {
|
|
37
|
-
if (match.index !== offset) return null;
|
|
38
|
-
offset = match.index + match[0].length;
|
|
39
|
-
packets.push({
|
|
40
|
-
code: Number(match[1]),
|
|
41
|
-
col: Number(match[2]),
|
|
42
|
-
row: Number(match[3]),
|
|
43
|
-
final: match[4] as "M" | "m",
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return packets.length > 0 && offset === data.length ? packets : null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** 是否为左键按下(排除修饰键、32 表示 motion 事件)。 */
|
|
51
|
-
export function isSgrLeftPress(packet: SgrMousePacket): boolean {
|
|
52
|
-
const baseButton = packet.code & ~(4 | 8 | 16 | 32);
|
|
53
|
-
return packet.final === "M" && baseButton === 0 && (packet.code & 32) === 0;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** 是否为左键松开。 */
|
|
57
|
-
export function isSgrLeftRelease(packet: SgrMousePacket): boolean {
|
|
58
|
-
const baseButton = packet.code & ~(4 | 8 | 16 | 32);
|
|
59
|
-
return packet.final === "m" && baseButton === 0 && (packet.code & 32) === 0;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** 仅剥离终端序列、保留原布局(换行/空白不动),用于命中区间计算。 */
|
|
63
|
-
export function stripTerminalSequencesPreservingLayout(value: string): string {
|
|
64
|
-
return value
|
|
65
|
-
.replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, "")
|
|
66
|
-
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** 剥离终端序列并折叠空白(用于纯文本比较)。 */
|
|
70
|
-
export function stripTerminalSequences(value: string): string {
|
|
71
|
-
return stripTerminalSequencesPreservingLayout(value).replace(/\s+/g, " ").trim();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
31
|
/** 工具执行组件识别(toolCallId + setExpanded + render)。 */
|
|
75
32
|
export function isToolExecutionComponent(value: any): boolean {
|
|
76
33
|
return Boolean(
|
|
@@ -83,24 +40,13 @@ export function isToolExecutionComponent(value: any): boolean {
|
|
|
83
40
|
}
|
|
84
41
|
|
|
85
42
|
/** 深度收集组件树中的工具执行组件(含 getMountedRoots 分支)。 */
|
|
86
|
-
export function collectToolComponents(component: any, tools: any[]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (Array.isArray(component.children)) {
|
|
94
|
-
for (const child of component.children) collectToolComponents(child, tools, seen);
|
|
95
|
-
}
|
|
96
|
-
try {
|
|
97
|
-
const mounted = component.getMountedRoots?.();
|
|
98
|
-
if (Array.isArray(mounted)) {
|
|
99
|
-
for (const root of mounted) collectToolComponents(root, tools, seen);
|
|
43
|
+
export function collectToolComponents(component: any, tools: any[]): void {
|
|
44
|
+
walkComponentTree(component, (value: any) => {
|
|
45
|
+
if (isToolExecutionComponent(value)) {
|
|
46
|
+
tools.push(value);
|
|
47
|
+
return false;
|
|
100
48
|
}
|
|
101
|
-
}
|
|
102
|
-
// renderer 切换中的惰性 Proxy 可能暂时没有 mounted roots。
|
|
103
|
-
}
|
|
49
|
+
});
|
|
104
50
|
}
|
|
105
51
|
|
|
106
52
|
/** 剥离一行中的零宽帧/视图 marker。 */
|
|
@@ -8,35 +8,39 @@ import {
|
|
|
8
8
|
import { config } from "../../config/config.ts";
|
|
9
9
|
import { isLazyProxyTui } from "../../utils/fullscreen-detect.ts";
|
|
10
10
|
import { parseSgrMousePackets } from "./packets.ts";
|
|
11
|
+
import {
|
|
12
|
+
OFFICIAL_SCROLL_TO_END_KEY,
|
|
13
|
+
patchRegistry,
|
|
14
|
+
SCROLL_BUTTON_STATE_SLOT,
|
|
15
|
+
TOOL_MOUSE_TUI_SLOT,
|
|
16
|
+
} from "../../utils/patch-keys.ts";
|
|
11
17
|
|
|
12
18
|
const ZENTUI_PAGE_UP_INPUT = /^\x1b\[5;9(?::[12])?~$|^\x1b\[57421;9(?::[12])?u$|^\x1b\[1;6A$/;
|
|
13
19
|
const ZENTUI_PAGE_DOWN_INPUT = /^\x1b\[6;9(?::[12])?~$|^\x1b\[57422;9(?::[12])?u$|^\x1b\[1;6B$/;
|
|
14
20
|
const SCROLL_BOTTOM_SHORTCUT = "ctrl+end";
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
* 当前安装的 tui 宿主。宿主放本模块(滚动按钮/调度依赖它),
|
|
18
|
-
* 由 mouse-interaction 经 setToolMouseTui 维护;跨模块一律经绑定/setter 访问。
|
|
19
|
-
*
|
|
20
|
-
* 状态镜像到 globalThis(Symbol 槽):jiti 转译下经 re-export 链读取的
|
|
21
|
-
* 模块级 let 绑定是初始值快照(死绑定,实测恒 null),函数调用才是活引用。
|
|
22
|
-
* 跨模块读取一律用 getToolMouseTui(),避免拿到加载时的快照。
|
|
23
|
-
*/
|
|
24
|
-
const TOOL_MOUSE_TUI_SLOT = Symbol.for("pi.ccstyle.tool-mouse-tui");
|
|
25
|
-
(globalThis as any)[TOOL_MOUSE_TUI_SLOT] ??= null;
|
|
22
|
+
patchRegistry.ensure(TOOL_MOUSE_TUI_SLOT, () => null);
|
|
26
23
|
export function getToolMouseTui(): any {
|
|
27
|
-
return (
|
|
24
|
+
return patchRegistry.get(TOOL_MOUSE_TUI_SLOT);
|
|
28
25
|
}
|
|
29
26
|
export function setToolMouseTui(tui: any): void {
|
|
30
|
-
(
|
|
27
|
+
patchRegistry.install(TOOL_MOUSE_TUI_SLOT, tui);
|
|
31
28
|
}
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
type ScrollButtonState = {
|
|
31
|
+
visible: boolean;
|
|
32
|
+
hovered: boolean;
|
|
33
|
+
widget: any;
|
|
34
|
+
/** 按钮可见期间新落的 transcript 块数(消息 + 工具卡)。 */
|
|
35
|
+
newCount: number;
|
|
36
|
+
};
|
|
37
37
|
function scrollButtonState(): ScrollButtonState {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
return patchRegistry.ensure(SCROLL_BUTTON_STATE_SLOT, () => ({
|
|
39
|
+
visible: false,
|
|
40
|
+
hovered: false,
|
|
41
|
+
widget: null,
|
|
42
|
+
newCount: 0,
|
|
43
|
+
}));
|
|
40
44
|
}
|
|
41
45
|
export function getScrollButtonVisible(): boolean {
|
|
42
46
|
return scrollButtonState().visible;
|
|
@@ -47,8 +51,32 @@ export function getScrollButtonHovered(): boolean {
|
|
|
47
51
|
export function getScrollButtonWidget(): any {
|
|
48
52
|
return scrollButtonState().widget;
|
|
49
53
|
}
|
|
54
|
+
export function getScrollButtonNewCount(): number {
|
|
55
|
+
return scrollButtonState().newCount;
|
|
56
|
+
}
|
|
50
57
|
export function setScrollButtonVisible(visible: boolean): void {
|
|
51
|
-
scrollButtonState()
|
|
58
|
+
const state = scrollButtonState();
|
|
59
|
+
state.visible = visible;
|
|
60
|
+
// 计数只在离开底部期间有效:跟随输出即清零,文案回到 Back to bottom。
|
|
61
|
+
if (!visible) state.newCount = 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 记账一块新落进 transcript 的内容(用户/助手消息、工具卡)。
|
|
66
|
+
* 仅在按钮可见(已滚动离开底部)时累加,并请求重绘让按钮文案立即更新。
|
|
67
|
+
*/
|
|
68
|
+
export function noteNewTranscriptItem(): void {
|
|
69
|
+
const state = scrollButtonState();
|
|
70
|
+
const tui = getToolMouseTui();
|
|
71
|
+
if (!state.visible || !tui) return;
|
|
72
|
+
// 提交新消息时官方可能直接跳回底部(不经过滚动输入):先按实时跟随状态校正,
|
|
73
|
+
// 否则跟随期间的内容会被当成“离开底部时的新消息”计入。
|
|
74
|
+
if (isAtTranscriptBottom(tui)) {
|
|
75
|
+
hideScrollButton(tui);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
state.newCount += 1;
|
|
79
|
+
tui.requestRender?.();
|
|
52
80
|
}
|
|
53
81
|
|
|
54
82
|
/** 返回是否发生变化(调用方据此决定是否需要重渲染)。 */
|
|
@@ -67,15 +95,16 @@ export function resetScrollButtonState(): void {
|
|
|
67
95
|
scrollButtonState().visible = false;
|
|
68
96
|
scrollButtonState().hovered = false;
|
|
69
97
|
scrollButtonState().widget = null;
|
|
98
|
+
scrollButtonState().newCount = 0;
|
|
70
99
|
scrollButtonSyncScheduled = false;
|
|
71
100
|
}
|
|
72
101
|
|
|
73
102
|
let scrollButtonSyncScheduled = false;
|
|
74
103
|
|
|
104
|
+
// 交互开关只取决于配置模式:原实现按 isLazyProxyTui(toolMouseTui) 分两分支,
|
|
105
|
+
// 两分支恒真(0.84+ 惰性 Proxy 下判定不再影响开关),折叠为单条件。
|
|
75
106
|
export function toolMouseInteractionActive(): boolean {
|
|
76
|
-
|
|
77
|
-
if (isLazyProxyTui(getToolMouseTui())) return true;
|
|
78
|
-
return true;
|
|
107
|
+
return config.mode !== "off";
|
|
79
108
|
}
|
|
80
109
|
|
|
81
110
|
/** 惰性 Proxy 官方 fullscreen(TuiAltScreen)判定。 */
|
|
@@ -83,13 +112,12 @@ export function fullscreenLazyTui(tui: any): boolean {
|
|
|
83
112
|
return isLazyProxyTui(tui) && tui.mode === "fullscreen";
|
|
84
113
|
}
|
|
85
114
|
|
|
86
|
-
const OFFICIAL_SCROLL_TO_END_KEY = Symbol.for("pi.ccstyle.official-scroll-to-end");
|
|
87
|
-
|
|
88
115
|
/** 关掉 pi 0.85 Jump to latest overlay,避免和本仓库 dock 按钮叠两层。 */
|
|
89
116
|
export function disableOfficialScrollToEnd(tui: any): void {
|
|
90
117
|
if (!tui) return;
|
|
91
118
|
const current = tui.scrollToEndIndicator;
|
|
92
119
|
if (typeof current !== "function") return;
|
|
120
|
+
// 原函数放 object 里,避免惰性 Proxy 对 function 属性再包一层。
|
|
93
121
|
if (!tui[OFFICIAL_SCROLL_TO_END_KEY]) {
|
|
94
122
|
tui[OFFICIAL_SCROLL_TO_END_KEY] = { original: current };
|
|
95
123
|
}
|
|
@@ -210,12 +238,19 @@ export function updateScrollButtonFromInput(tui: any, data: string): void {
|
|
|
210
238
|
if (matchesKey(data, "enter") || matchesKey(data, "return")) hideScrollButton(tui);
|
|
211
239
|
}
|
|
212
240
|
|
|
241
|
+
/** 无新内容时提示原文案;有新内容时换成累计条数。 */
|
|
242
|
+
function scrollButtonText(): string {
|
|
243
|
+
const count = getScrollButtonNewCount();
|
|
244
|
+
const shortcut = formatShortcut(SCROLL_BOTTOM_SHORTCUT);
|
|
245
|
+
if (count <= 0) return `Back to bottom · ${shortcut}`;
|
|
246
|
+
return `${count} new message${count === 1 ? "" : "s"} · ${shortcut}`;
|
|
247
|
+
}
|
|
248
|
+
|
|
213
249
|
export function renderScrollButton(width: number, theme: any): string[] {
|
|
214
250
|
if (!getScrollButtonVisible() || !fullscreenLazyTui(getToolMouseTui())) return [];
|
|
215
|
-
const shortcut = formatShortcut(SCROLL_BOTTOM_SHORTCUT);
|
|
216
251
|
const label = theme.fg(
|
|
217
252
|
getScrollButtonHovered() ? "text" : "accent",
|
|
218
|
-
`[ ↓
|
|
253
|
+
`[ ↓ ${scrollButtonText()} ]`,
|
|
219
254
|
);
|
|
220
255
|
const leftPad = Math.max(0, Math.floor((width - visibleWidth(label)) / 2));
|
|
221
256
|
return [`${" ".repeat(leftPad)}${truncateToWidth(label, width, "…")}`];
|
package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
const ANSI_SGR_PATTERN = /\x1b\[([0-9
|
|
2
|
-
const ANSI_SGR_WITH_COLON_PATTERN = /\x1b\[([0-9;:]*)m/g;
|
|
1
|
+
const ANSI_SGR_PATTERN = /\x1b\[([0-9;:]*)m/g;
|
|
3
2
|
const STYLE_RESET_PARAMS = [39, 22, 23, 24, 25, 27, 28, 29, 59] as const;
|
|
4
3
|
|
|
5
4
|
export { ANSI_SGR_PATTERN, STYLE_RESET_PARAMS };
|
|
@@ -89,12 +88,35 @@ export function stripBackgroundSgrParams(params: readonly number[]): number[] {
|
|
|
89
88
|
return sanitized;
|
|
90
89
|
}
|
|
91
90
|
|
|
91
|
+
function isKeptColonSgr(token: string): boolean {
|
|
92
|
+
const parts = token.split(":");
|
|
93
|
+
if (parts[0] === "48") return false;
|
|
94
|
+
if (parts[0] !== "38") return true;
|
|
95
|
+
const channels =
|
|
96
|
+
parts[1] === "5" && parts.length === 3
|
|
97
|
+
? parts.slice(2)
|
|
98
|
+
: parts[1] === "2" && (parts.length === 5 || parts.length === 6)
|
|
99
|
+
? parts.slice(-3)
|
|
100
|
+
: undefined;
|
|
101
|
+
return !!channels?.every((c) => /^\d+$/.test(c) && Number(c) <= 255);
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
export function filterSgrSequences(text: string, filter: (params: number[]) => number[]): string {
|
|
93
105
|
if (!text || !text.includes("\x1b[")) {
|
|
94
106
|
return text;
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
return text.replace(ANSI_SGR_PATTERN, (_sequence, rawParams: string) => {
|
|
110
|
+
if (rawParams.includes(":")) {
|
|
111
|
+
// 冒号形式 (ISO 8613-6):逐段处理;去掉 48:*,校验 38:*,其余原样保留
|
|
112
|
+
const kept = rawParams.split(";").flatMap((token) => {
|
|
113
|
+
if (!token.includes(":")) {
|
|
114
|
+
return token ? filter(toSgrParams(token)).map(String) : [];
|
|
115
|
+
}
|
|
116
|
+
return isKeptColonSgr(token) ? [token] : [];
|
|
117
|
+
});
|
|
118
|
+
return kept.length > 0 ? `\x1b[${kept.join(";")}m` : "";
|
|
119
|
+
}
|
|
98
120
|
const parsed = toSgrParams(rawParams);
|
|
99
121
|
if (parsed.length === 0) {
|
|
100
122
|
return "";
|
|
@@ -109,60 +131,6 @@ export function filterSgrSequences(text: string, filter: (params: number[]) => n
|
|
|
109
131
|
});
|
|
110
132
|
}
|
|
111
133
|
|
|
112
|
-
function isValidColonForeground(segment: string): boolean {
|
|
113
|
-
const params = segment.split(":");
|
|
114
|
-
const isByte = (value: string | undefined) =>
|
|
115
|
-
value !== undefined && /^\d+$/.test(value) && Number(value) <= 255;
|
|
116
|
-
if (params[0] !== "38") return false;
|
|
117
|
-
if (params[1] === "5") return params.length === 3 && isByte(params[2]);
|
|
118
|
-
return (
|
|
119
|
-
params[1] === "2" &&
|
|
120
|
-
params.length === 6 &&
|
|
121
|
-
(params[2] === "" || /^\d+$/.test(params[2] ?? "")) &&
|
|
122
|
-
params.slice(3).every(isByte)
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function sanitizeColonSgr(rawParams: string): string {
|
|
127
|
-
const segments = rawParams.split(";");
|
|
128
|
-
const sanitized: string[] = [];
|
|
129
|
-
for (let index = 0; index < segments.length; index++) {
|
|
130
|
-
const segment = segments[index] ?? "";
|
|
131
|
-
if (segment.includes(":")) {
|
|
132
|
-
const code = Number.parseInt(segment, 10);
|
|
133
|
-
if (code !== 48 && (code !== 38 || isValidColonForeground(segment))) {
|
|
134
|
-
sanitized.push(segment);
|
|
135
|
-
}
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
const param = Number.parseInt(segment, 10);
|
|
139
|
-
if (!Number.isFinite(param)) continue;
|
|
140
|
-
if (param === 0) {
|
|
141
|
-
sanitized.push(...STYLE_RESET_PARAMS.map(String));
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
if (param === 49 || (param >= 40 && param <= 47) || (param >= 100 && param <= 107)) {
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (param === 38 || param === 48) {
|
|
148
|
-
const mode = Number.parseInt(segments[index + 1] ?? "", 10);
|
|
149
|
-
const advance = mode === 5 ? 2 : mode === 2 ? 4 : 0;
|
|
150
|
-
if (advance > 0) {
|
|
151
|
-
if (param === 38) sanitized.push(...segments.slice(index, index + advance + 1));
|
|
152
|
-
index += advance;
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
sanitized.push(segment);
|
|
157
|
-
}
|
|
158
|
-
return sanitized.length > 0 ? `\x1b[${sanitized.join(";")}m` : "";
|
|
159
|
-
}
|
|
160
|
-
|
|
161
134
|
export function sanitizeAnsiForThemedOutput(text: string): string {
|
|
162
|
-
|
|
163
|
-
return text.replace(ANSI_SGR_WITH_COLON_PATTERN, (sequence, rawParams: string) =>
|
|
164
|
-
rawParams.includes(":")
|
|
165
|
-
? sanitizeColonSgr(rawParams)
|
|
166
|
-
: filterSgrSequences(sequence, stripBackgroundSgrParams),
|
|
167
|
-
);
|
|
135
|
+
return filterSgrSequences(text, stripBackgroundSgrParams);
|
|
168
136
|
}
|
package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-component.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_TOOL_DISPLAY_CONFIG,
|
|
3
|
+
type DiffIndicatorMode,
|
|
4
|
+
type ToolDisplayConfig,
|
|
5
|
+
} from "../../../config/config.ts";
|
|
6
|
+
import { stripTerminalSequencesPreservingLayout } from "../../../utils/ansi-text.ts";
|
|
7
|
+
import { RICH_DIFF_COMPONENT } from "../../../utils/patch-keys.ts";
|
|
8
|
+
import type { DiffPresentationMode } from "./diff-presentation.ts";
|
|
9
|
+
export { RICH_DIFF_COMPONENT };
|
|
10
|
+
|
|
11
|
+
/** Snapshot or live getter — panel changes must apply on the next paint. */
|
|
12
|
+
export type DisplayConfigInput = ToolDisplayConfig | (() => ToolDisplayConfig);
|
|
13
|
+
|
|
14
|
+
export interface DiffRenderOptions {
|
|
15
|
+
expanded: boolean;
|
|
16
|
+
filePath?: string;
|
|
17
|
+
previousContent?: string;
|
|
18
|
+
fileExistedBeforeWrite?: boolean;
|
|
19
|
+
headerLabel?: string;
|
|
20
|
+
/** Live hover state for the collapsed hint row (muted → text on hover). */
|
|
21
|
+
isHovered?: () => boolean;
|
|
22
|
+
invalidate?: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isRichDiffComponent(value: unknown): boolean {
|
|
26
|
+
return Boolean(
|
|
27
|
+
value &&
|
|
28
|
+
typeof value === "object" &&
|
|
29
|
+
(value as Record<symbol, unknown>)[RICH_DIFF_COMPONENT] === true,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function resolveLiveDisplayConfig(input: DisplayConfigInput): ToolDisplayConfig {
|
|
34
|
+
return typeof input === "function" ? input() : input;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 比对用归一化:ANSI、缩进前缀和右侧填充不影响判断。
|
|
39
|
+
* 折叠态 remainder 行里有任意正文,入口必须先由组件声明再比对文本。
|
|
40
|
+
*/
|
|
41
|
+
export function normalizeCollapsedHintLine(line: string | undefined): string | undefined {
|
|
42
|
+
if (line === undefined) return undefined;
|
|
43
|
+
return stripTerminalSequencesPreservingLayout(line).replace(/\s+/g, " ").trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Cache key fragment so indicator/wrap/limits invalidate without host recreate. */
|
|
47
|
+
export function displayConfigCacheKey(config: ToolDisplayConfig): string {
|
|
48
|
+
return [
|
|
49
|
+
config.diffViewMode,
|
|
50
|
+
config.diffIndicatorMode,
|
|
51
|
+
String(config.diffSplitMinWidth),
|
|
52
|
+
String(config.editDiffCollapsedLines),
|
|
53
|
+
String(config.writeDiffCollapsedLines),
|
|
54
|
+
config.diffWordWrap ? "1" : "0",
|
|
55
|
+
].join(":");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function resolveDiffIndicatorMode(
|
|
59
|
+
config: Partial<Pick<ToolDisplayConfig, "diffIndicatorMode">>,
|
|
60
|
+
): DiffIndicatorMode {
|
|
61
|
+
return config.diffIndicatorMode ?? DEFAULT_TOOL_DISPLAY_CONFIG.diffIndicatorMode;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createDiffRenderCache() {
|
|
65
|
+
let cachedWidth: number | undefined;
|
|
66
|
+
let cachedExpanded: boolean | undefined;
|
|
67
|
+
let cachedMode: DiffPresentationMode | undefined;
|
|
68
|
+
let cachedConfigKey: string | undefined;
|
|
69
|
+
let cachedHovered: boolean | undefined;
|
|
70
|
+
let cachedLines: string[] | undefined;
|
|
71
|
+
/** 与 cachedLines 同一次渲染的折叠态 remainder 行文本。 */
|
|
72
|
+
let cachedHintLine: string | undefined;
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
get(
|
|
76
|
+
width: number,
|
|
77
|
+
expanded: boolean,
|
|
78
|
+
mode: DiffPresentationMode,
|
|
79
|
+
configKey: string,
|
|
80
|
+
hovered: boolean,
|
|
81
|
+
): string[] | undefined {
|
|
82
|
+
if (
|
|
83
|
+
cachedLines &&
|
|
84
|
+
cachedWidth === width &&
|
|
85
|
+
cachedExpanded === expanded &&
|
|
86
|
+
cachedMode === mode &&
|
|
87
|
+
cachedConfigKey === configKey &&
|
|
88
|
+
cachedHovered === hovered
|
|
89
|
+
) {
|
|
90
|
+
return cachedLines;
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
},
|
|
94
|
+
getHintLine(): string | undefined {
|
|
95
|
+
return cachedHintLine;
|
|
96
|
+
},
|
|
97
|
+
set(
|
|
98
|
+
width: number,
|
|
99
|
+
expanded: boolean,
|
|
100
|
+
mode: DiffPresentationMode,
|
|
101
|
+
configKey: string,
|
|
102
|
+
hovered: boolean,
|
|
103
|
+
lines: string[],
|
|
104
|
+
hintLine?: string,
|
|
105
|
+
): string[] {
|
|
106
|
+
cachedWidth = width;
|
|
107
|
+
cachedExpanded = expanded;
|
|
108
|
+
cachedMode = mode;
|
|
109
|
+
cachedConfigKey = configKey;
|
|
110
|
+
cachedHovered = hovered;
|
|
111
|
+
cachedLines = lines;
|
|
112
|
+
cachedHintLine = hintLine;
|
|
113
|
+
return lines;
|
|
114
|
+
},
|
|
115
|
+
invalidate(): void {
|
|
116
|
+
cachedWidth = undefined;
|
|
117
|
+
cachedExpanded = undefined;
|
|
118
|
+
cachedMode = undefined;
|
|
119
|
+
cachedConfigKey = undefined;
|
|
120
|
+
cachedHovered = undefined;
|
|
121
|
+
cachedLines = undefined;
|
|
122
|
+
cachedHintLine = undefined;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|