@mrclrchtr/supi-lsp 7.2.1 → 7.3.1
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/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/README.md +10 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +3 -2
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/session-capabilities.ts +188 -0
- package/node_modules/@mrclrchtr/supi-core/src/session.ts +17 -0
- package/node_modules/@mrclrchtr/supi-core/src/tui.ts +141 -0
- package/node_modules/ignore/index.js +25 -6
- package/node_modules/ignore/legacy.js +22 -6
- package/node_modules/ignore/package.json +1 -1
- package/node_modules/vscode-jsonrpc/lib/common/connection.js +2 -2
- package/node_modules/vscode-jsonrpc/lib/node/main.d.ts +1 -0
- package/node_modules/vscode-jsonrpc/lib/node/main.js +7 -0
- package/node_modules/vscode-jsonrpc/package.json +2 -2
- package/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayHint.d.ts +2 -2
- package/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineCompletion.d.ts +2 -2
- package/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineValue.d.ts +2 -2
- package/node_modules/vscode-languageserver-protocol/package.json +4 -4
- package/node_modules/vscode-languageserver-types/package.json +2 -2
- package/package.json +3 -3
|
@@ -23,6 +23,7 @@ pnpm add @mrclrchtr/supi-core
|
|
|
23
23
|
- `@mrclrchtr/supi-core/api` — reusable helpers for other packages and extensions
|
|
24
24
|
- `@mrclrchtr/supi-core/llm` — PI-owned direct model requests and JSON helpers
|
|
25
25
|
- `@mrclrchtr/supi-core/report` — shared text/report rendering helpers for TUI and plain-text summaries
|
|
26
|
+
- `@mrclrchtr/supi-core/tui` — shared terminal UI helpers for list titles, rows, menus, and descriptions
|
|
26
27
|
|
|
27
28
|
## What you get from the API
|
|
28
29
|
|
|
@@ -70,6 +71,14 @@ Both completion helpers require a stable `affinityScope`. PI owns auth and endpo
|
|
|
70
71
|
- active-branch session helper: `getActiveBranchEntries()`
|
|
71
72
|
- terminal helpers such as `formatTitle()`, `signalWaiting()`, and `signalDone()`
|
|
72
73
|
|
|
74
|
+
### TUI helpers
|
|
75
|
+
|
|
76
|
+
- `formatTuiTitleLine()` — use the shared title style in terminal lists
|
|
77
|
+
- `renderSelectableRow()` — render a selected row with an aligned value
|
|
78
|
+
- `renderDescriptionViewport()` — show a fixed-height description preview
|
|
79
|
+
- `renderTuiHintLine()` — render short key hints in one line
|
|
80
|
+
- `createSelectListMenu()` — build an action menu with shared key hints
|
|
81
|
+
|
|
73
82
|
### Report helpers
|
|
74
83
|
|
|
75
84
|
- `clampReportWidth()` — enforce a minimum readable report width
|
|
@@ -125,3 +134,4 @@ export default function myExtension(pi: ExtensionAPI) {
|
|
|
125
134
|
- `src/debug-timing.ts` — monotonic total and phase timers for Debug Event Producers
|
|
126
135
|
- `src/settings/` — settings registry, schema, scope resolution, and persistence
|
|
127
136
|
- `src/report.ts` — shared text/report rendering helpers
|
|
137
|
+
- `src/tui.ts` — shared terminal UI list and action-menu helpers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.1",
|
|
4
4
|
"description": "Shared settings, configuration, reporting, and session infrastructure",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"./settings": "./src/settings.ts",
|
|
68
68
|
"./spinner-frames": "./src/spinner-frames.ts",
|
|
69
69
|
"./status-spinner": "./src/status-spinner.ts",
|
|
70
|
-
"./terminal": "./src/terminal.ts"
|
|
70
|
+
"./terminal": "./src/terminal.ts",
|
|
71
|
+
"./tui": "./src/tui.ts"
|
|
71
72
|
}
|
|
72
73
|
}
|
|
@@ -38,3 +38,5 @@ export * from "./spinner-frames.ts";
|
|
|
38
38
|
export * from "./status-spinner.ts";
|
|
39
39
|
// biome-ignore lint/performance/noReExportAll: intentional convenience barrel
|
|
40
40
|
export * from "./terminal.ts";
|
|
41
|
+
// biome-ignore lint/performance/noReExportAll: intentional convenience barrel
|
|
42
|
+
export * from "./tui.ts";
|
|
@@ -34,3 +34,5 @@ export * from "./settings.ts";
|
|
|
34
34
|
export * from "./status-spinner.ts";
|
|
35
35
|
// biome-ignore lint/performance/noReExportAll: intentional convenience barrel
|
|
36
36
|
export * from "./terminal.ts";
|
|
37
|
+
// biome-ignore lint/performance/noReExportAll: intentional convenience barrel
|
|
38
|
+
export * from "./tui.ts";
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/** Session-only tool and skill visibility state. */
|
|
2
|
+
export interface SessionCapabilityState {
|
|
3
|
+
version: 1;
|
|
4
|
+
eligibleToolNames: string[];
|
|
5
|
+
initiallyInactiveToolNames: string[];
|
|
6
|
+
toolDenylist: string[];
|
|
7
|
+
/** Tools that the user explicitly enabled for this session. */
|
|
8
|
+
toolEnabledNames?: string[];
|
|
9
|
+
hiddenSkillNames: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** A model-visible skill that a provider can offer to the selector. */
|
|
13
|
+
export interface SessionCapabilitySkill {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Skill inventory provider registered by the skills extension. */
|
|
19
|
+
export interface SessionCapabilitySkillProvider<TContext = unknown> {
|
|
20
|
+
listEligibleSkills(
|
|
21
|
+
context: TContext,
|
|
22
|
+
): Promise<SessionCapabilitySkill[]> | SessionCapabilitySkill[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Custom session-entry type used for hidden capability snapshots. */
|
|
26
|
+
export const SESSION_CAPABILITIES_ENTRY = "supi-capabilities";
|
|
27
|
+
|
|
28
|
+
const REGISTRY_PREFIX = "@mrclrchtr/supi-core/session-capabilities/";
|
|
29
|
+
const STATE_KEY = Symbol.for(`${REGISTRY_PREFIX}state`);
|
|
30
|
+
const PROVIDER_KEY = Symbol.for(`${REGISTRY_PREFIX}skill-providers`);
|
|
31
|
+
const FORK_KEY = Symbol.for(`${REGISTRY_PREFIX}pending-forks`);
|
|
32
|
+
|
|
33
|
+
type GlobalRegistry = typeof globalThis & Record<symbol, unknown>;
|
|
34
|
+
|
|
35
|
+
type SkillProviderMap = Map<string, SessionCapabilitySkillProvider<unknown>>;
|
|
36
|
+
type ForkStateMap = Map<string, SessionCapabilityState>;
|
|
37
|
+
|
|
38
|
+
function getStateMap(): Map<string, SessionCapabilityState> {
|
|
39
|
+
const target = globalThis as GlobalRegistry;
|
|
40
|
+
let map = target[STATE_KEY] as Map<string, SessionCapabilityState> | undefined;
|
|
41
|
+
if (!map) {
|
|
42
|
+
map = new Map();
|
|
43
|
+
target[STATE_KEY] = map;
|
|
44
|
+
}
|
|
45
|
+
return map;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getProviderMap(): SkillProviderMap {
|
|
49
|
+
const target = globalThis as GlobalRegistry;
|
|
50
|
+
let map = target[PROVIDER_KEY] as SkillProviderMap | undefined;
|
|
51
|
+
if (!map) {
|
|
52
|
+
map = new Map();
|
|
53
|
+
target[PROVIDER_KEY] = map;
|
|
54
|
+
}
|
|
55
|
+
return map;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getForkMap(): ForkStateMap {
|
|
59
|
+
const target = globalThis as GlobalRegistry;
|
|
60
|
+
let map = target[FORK_KEY] as ForkStateMap | undefined;
|
|
61
|
+
if (!map) {
|
|
62
|
+
map = new Map();
|
|
63
|
+
target[FORK_KEY] = map;
|
|
64
|
+
}
|
|
65
|
+
return map;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function stringList(value: unknown): string[] {
|
|
69
|
+
if (!Array.isArray(value)) return [];
|
|
70
|
+
return Array.from(new Set(value.filter((item): item is string => typeof item === "string")));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Create an empty state snapshot. */
|
|
74
|
+
export function createEmptySessionCapabilityState(): SessionCapabilityState {
|
|
75
|
+
return {
|
|
76
|
+
version: 1,
|
|
77
|
+
eligibleToolNames: [],
|
|
78
|
+
initiallyInactiveToolNames: [],
|
|
79
|
+
toolDenylist: [],
|
|
80
|
+
toolEnabledNames: [],
|
|
81
|
+
hiddenSkillNames: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Validate and copy one stored snapshot. */
|
|
86
|
+
export function decodeSessionCapabilities(value: unknown): SessionCapabilityState | undefined {
|
|
87
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
88
|
+
const record = value as Record<string, unknown>;
|
|
89
|
+
if (record.version !== 1) return undefined;
|
|
90
|
+
|
|
91
|
+
const initiallyInactiveToolNames = stringList(record.initiallyInactiveToolNames);
|
|
92
|
+
const initiallyInactive = new Set(initiallyInactiveToolNames);
|
|
93
|
+
const eligibleToolNames = stringList(record.eligibleToolNames).filter(
|
|
94
|
+
(name) => !initiallyInactive.has(name),
|
|
95
|
+
);
|
|
96
|
+
const eligible = new Set(eligibleToolNames);
|
|
97
|
+
const toolDenylist = stringList(record.toolDenylist).filter((name) => eligible.has(name));
|
|
98
|
+
const denied = new Set(toolDenylist);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
version: 1,
|
|
102
|
+
eligibleToolNames,
|
|
103
|
+
initiallyInactiveToolNames,
|
|
104
|
+
toolDenylist,
|
|
105
|
+
toolEnabledNames: stringList(record.toolEnabledNames).filter(
|
|
106
|
+
(name) => eligible.has(name) && !denied.has(name),
|
|
107
|
+
),
|
|
108
|
+
hiddenSkillNames: stringList(record.hiddenSkillNames),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Return a safe copy of the latest valid snapshot in all session entries. */
|
|
113
|
+
export function findSessionCapabilities(
|
|
114
|
+
entries: readonly unknown[],
|
|
115
|
+
): SessionCapabilityState | undefined {
|
|
116
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
117
|
+
const entry = entries[index];
|
|
118
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
119
|
+
const record = entry as Record<string, unknown>;
|
|
120
|
+
if (record.type !== "custom" || record.customType !== SESSION_CAPABILITIES_ENTRY) continue;
|
|
121
|
+
const state = decodeSessionCapabilities(record.data);
|
|
122
|
+
if (state) return state;
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Shared session state. Session IDs keep sessions in the same cwd separate. */
|
|
128
|
+
export const sessionCapabilityState = {
|
|
129
|
+
get(sessionId: string): SessionCapabilityState | undefined {
|
|
130
|
+
const state = getStateMap().get(sessionId);
|
|
131
|
+
return state ? decodeSessionCapabilities(state) : undefined;
|
|
132
|
+
},
|
|
133
|
+
set(sessionId: string, state: SessionCapabilityState): void {
|
|
134
|
+
const decoded = decodeSessionCapabilities(state);
|
|
135
|
+
if (decoded) getStateMap().set(sessionId, decoded);
|
|
136
|
+
},
|
|
137
|
+
clear(sessionId: string): void {
|
|
138
|
+
getStateMap().delete(sessionId);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/** Register the current session's skill inventory provider. */
|
|
143
|
+
export function registerSessionCapabilitySkillProvider<TContext>(
|
|
144
|
+
sessionId: string,
|
|
145
|
+
provider: SessionCapabilitySkillProvider<TContext>,
|
|
146
|
+
): () => void {
|
|
147
|
+
const providers = getProviderMap();
|
|
148
|
+
providers.set(sessionId, provider as SessionCapabilitySkillProvider<unknown>);
|
|
149
|
+
return () => {
|
|
150
|
+
if (providers.get(sessionId) === provider) providers.delete(sessionId);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Get the current session's skill inventory provider, if one is loaded. */
|
|
155
|
+
export function getSessionCapabilitySkillProvider<TContext = unknown>(
|
|
156
|
+
sessionId: string,
|
|
157
|
+
): SessionCapabilitySkillProvider<TContext> | undefined {
|
|
158
|
+
return getProviderMap().get(sessionId) as SessionCapabilitySkillProvider<TContext> | undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function forkKey(sourceSessionFile: string | undefined): string {
|
|
162
|
+
return sourceSessionFile ?? "<memory-session>";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Hold a state copy until PI starts the forked session. */
|
|
166
|
+
export function setPendingSessionCapabilityFork(
|
|
167
|
+
sourceSessionFile: string | undefined,
|
|
168
|
+
state: SessionCapabilityState,
|
|
169
|
+
): void {
|
|
170
|
+
const decoded = decodeSessionCapabilities(state);
|
|
171
|
+
if (decoded) getForkMap().set(forkKey(sourceSessionFile), decoded);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Take the state copy for one fork. The copy is used once. */
|
|
175
|
+
export function readPendingSessionCapabilityFork(
|
|
176
|
+
sourceSessionFile: string | undefined,
|
|
177
|
+
): SessionCapabilityState | undefined {
|
|
178
|
+
const forks = getForkMap();
|
|
179
|
+
const key = forkKey(sourceSessionFile);
|
|
180
|
+
const state = forks.get(key);
|
|
181
|
+
forks.delete(key);
|
|
182
|
+
return state ? decodeSessionCapabilities(state) : undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Clear pending fork copies after a cancelled or unrelated transition. */
|
|
186
|
+
export function clearPendingSessionCapabilityForks(): void {
|
|
187
|
+
getForkMap().clear();
|
|
188
|
+
}
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
// supi-core session domain — session utilities and registries.
|
|
2
2
|
|
|
3
3
|
export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
|
|
4
|
+
export type {
|
|
5
|
+
SessionCapabilitySkill,
|
|
6
|
+
SessionCapabilitySkillProvider,
|
|
7
|
+
SessionCapabilityState,
|
|
8
|
+
} from "./session-capabilities.ts";
|
|
9
|
+
export {
|
|
10
|
+
clearPendingSessionCapabilityForks,
|
|
11
|
+
createEmptySessionCapabilityState,
|
|
12
|
+
decodeSessionCapabilities,
|
|
13
|
+
findSessionCapabilities,
|
|
14
|
+
getSessionCapabilitySkillProvider,
|
|
15
|
+
readPendingSessionCapabilityFork,
|
|
16
|
+
registerSessionCapabilitySkillProvider,
|
|
17
|
+
SESSION_CAPABILITIES_ENTRY,
|
|
18
|
+
sessionCapabilityState,
|
|
19
|
+
setPendingSessionCapabilityFork,
|
|
20
|
+
} from "./session-capabilities.ts";
|
|
4
21
|
export type { SessionNameTrackerHost } from "./session-utils.ts";
|
|
5
22
|
export {
|
|
6
23
|
createSessionNameTracker,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import {
|
|
3
|
+
type SelectItem,
|
|
4
|
+
SelectList,
|
|
5
|
+
type TuiMouseEvent,
|
|
6
|
+
type TuiMouseEventResult,
|
|
7
|
+
truncateToWidth,
|
|
8
|
+
visibleWidth,
|
|
9
|
+
wrapTextWithAnsi,
|
|
10
|
+
} from "@earendil-works/pi-tui";
|
|
11
|
+
|
|
12
|
+
/** The theme methods used by the shared TUI list renderers. */
|
|
13
|
+
export type TuiTheme = Pick<Theme, "fg" | "bold">;
|
|
14
|
+
|
|
15
|
+
/** Settings for one selectable row in a themed list. */
|
|
16
|
+
export interface SelectableRowOptions {
|
|
17
|
+
/** The row label. */
|
|
18
|
+
label: string;
|
|
19
|
+
/** The value shown beside the label. */
|
|
20
|
+
value: string;
|
|
21
|
+
/** The row indent in terminal columns. */
|
|
22
|
+
indent: number;
|
|
23
|
+
/** The largest indent used by the list. */
|
|
24
|
+
maxIndent: number;
|
|
25
|
+
/** The label column width. */
|
|
26
|
+
maxLabelWidth: number;
|
|
27
|
+
/** The row width in terminal columns. */
|
|
28
|
+
width: number;
|
|
29
|
+
/** True when this row is selected. */
|
|
30
|
+
selected: boolean;
|
|
31
|
+
/** Theme used for row colors. */
|
|
32
|
+
theme: TuiTheme;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Settings for a shared action menu. */
|
|
36
|
+
export interface SelectListMenuOptions {
|
|
37
|
+
/** The title shown above the choices. */
|
|
38
|
+
title: string;
|
|
39
|
+
/** The choices shown in the menu. */
|
|
40
|
+
items: SelectItem[];
|
|
41
|
+
/** Theme used for menu colors. */
|
|
42
|
+
theme: TuiTheme;
|
|
43
|
+
/** Called when the user selects a choice. */
|
|
44
|
+
onSelect: (item: SelectItem) => void;
|
|
45
|
+
/** Called when the user closes the menu without a choice. */
|
|
46
|
+
onCancel: () => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Component methods for a shared action menu. */
|
|
50
|
+
export interface SelectListMenuComponent {
|
|
51
|
+
render(width: number): string[];
|
|
52
|
+
invalidate(): void;
|
|
53
|
+
handleInput(data: string): void;
|
|
54
|
+
handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Build a title line with optional right-side tabs in the shared TUI style. */
|
|
58
|
+
export function formatTuiTitleLine(title: string, theme: TuiTheme, trailing = ""): string {
|
|
59
|
+
const titleText = theme.fg("accent", theme.bold(title));
|
|
60
|
+
return ` ${titleText}${trailing ? ` ${trailing}` : ""}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Render one row with a selected marker and an aligned value column. */
|
|
64
|
+
export function renderSelectableRow(options: SelectableRowOptions): string {
|
|
65
|
+
const indent = Math.max(0, options.indent);
|
|
66
|
+
const maxIndent = Math.max(indent, options.maxIndent);
|
|
67
|
+
const maxLabelWidth = Math.max(0, options.maxLabelWidth);
|
|
68
|
+
const width = Math.max(0, options.width);
|
|
69
|
+
const label = truncateToWidth(options.label, maxLabelWidth, "");
|
|
70
|
+
const labelWidth = visibleWidth(label);
|
|
71
|
+
const prefix = options.selected
|
|
72
|
+
? `${" ".repeat(Math.max(0, indent - 2))}${options.theme.fg("accent", "→ ")}`
|
|
73
|
+
: " ".repeat(indent);
|
|
74
|
+
const labelPadding = " ".repeat(maxIndent - indent + maxLabelWidth - labelWidth);
|
|
75
|
+
const valueWidth = Math.max(0, width - maxIndent - maxLabelWidth - 4);
|
|
76
|
+
const value = truncateToWidth(options.value, valueWidth, "");
|
|
77
|
+
const labelText = options.theme.fg(options.selected ? "accent" : "text", label + labelPadding);
|
|
78
|
+
const valueText = options.theme.fg(options.selected ? "accent" : "muted", value);
|
|
79
|
+
|
|
80
|
+
return truncateToWidth(`${prefix}${labelText} ${valueText}`, width);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Render a fixed-height, four-line description preview for a selected row. */
|
|
84
|
+
export function renderDescriptionViewport(
|
|
85
|
+
description: string | undefined,
|
|
86
|
+
width: number,
|
|
87
|
+
): string[] {
|
|
88
|
+
const height = 4;
|
|
89
|
+
const indent = " ";
|
|
90
|
+
const contentWidth = Math.max(1, width - 4);
|
|
91
|
+
const wrapped = description ? wrapTextWithAnsi(description, contentWidth) : [];
|
|
92
|
+
const visible = wrapped.slice(0, height);
|
|
93
|
+
|
|
94
|
+
if (wrapped.length > height) {
|
|
95
|
+
const lastIndex = height - 1;
|
|
96
|
+
visible[lastIndex] = truncateToWidth(`${visible[lastIndex] ?? ""}…`, contentWidth, "…");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
while (visible.length < height) visible.push("");
|
|
100
|
+
return visible.map((line) => (line ? `${indent}${line}` : ""));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Render a dimmed hint line with the shared separator and truncation rules. */
|
|
104
|
+
export function renderTuiHintLine(hints: string[], theme: TuiTheme, width: number): string {
|
|
105
|
+
return truncateToWidth(theme.fg("dim", hints.join(" · ")), width);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Build the shared title, choices, and key hints for an action menu. */
|
|
109
|
+
export function createSelectListMenu(options: SelectListMenuOptions): SelectListMenuComponent {
|
|
110
|
+
const { items, onSelect, onCancel, theme, title } = options;
|
|
111
|
+
const selectList = new SelectList(items, Math.min(items.length + 2, 15), {
|
|
112
|
+
selectedPrefix: (text) => theme.fg("accent", text),
|
|
113
|
+
selectedText: (text) => theme.fg("accent", text),
|
|
114
|
+
description: (text) => theme.fg("muted", text),
|
|
115
|
+
scrollInfo: (text) => theme.fg("dim", text),
|
|
116
|
+
noMatch: (text) => theme.fg("warning", text),
|
|
117
|
+
});
|
|
118
|
+
selectList.onSelect = onSelect;
|
|
119
|
+
selectList.onCancel = onCancel;
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
render(width) {
|
|
123
|
+
return [
|
|
124
|
+
truncateToWidth(theme.fg("accent", ` ${title}`), width),
|
|
125
|
+
...selectList.render(width),
|
|
126
|
+
"",
|
|
127
|
+
renderTuiHintLine([" ↑↓ navigate", "Enter select", "Esc cancel"], theme, width),
|
|
128
|
+
];
|
|
129
|
+
},
|
|
130
|
+
invalidate() {
|
|
131
|
+
selectList.invalidate();
|
|
132
|
+
},
|
|
133
|
+
handleInput(data) {
|
|
134
|
+
selectList.handleInput(data);
|
|
135
|
+
},
|
|
136
|
+
handleMouse(event) {
|
|
137
|
+
if (event.y < 1) return undefined;
|
|
138
|
+
return selectList.handleMouse({ ...event, y: event.y - 1 });
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -727,6 +727,20 @@ const WILDCARD = '[^\\/]*'
|
|
|
727
727
|
// The source is read one token at a time -- a wildcard, a single-character
|
|
728
728
|
// piece (a literal, an escape, a class), or a parenthesised group or anchor
|
|
729
729
|
// that ends the run -- so only a genuine wildcard is touched.
|
|
730
|
+
|
|
731
|
+
// The fixed pieces between the wildcard at `at` and the next wildcard of the
|
|
732
|
+
// run, joined as they appear in the source. A run never holds two wildcards
|
|
733
|
+
// in a row, so there is always at least one piece.
|
|
734
|
+
const separatorAfter = (run, at) => {
|
|
735
|
+
let separator = EMPTY
|
|
736
|
+
|
|
737
|
+
for (let index = at + 1; index < run.length && !run[index].wildcard; index ++) {
|
|
738
|
+
separator += run[index].single
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
return separator
|
|
742
|
+
}
|
|
743
|
+
|
|
730
744
|
const pinWildcards = source => {
|
|
731
745
|
if (source.indexOf(WILDCARD) < 0) {
|
|
732
746
|
return source
|
|
@@ -814,14 +828,19 @@ const pinWildcards = source => {
|
|
|
814
828
|
return
|
|
815
829
|
}
|
|
816
830
|
|
|
817
|
-
// A wildcard that is not the last in the run is
|
|
818
|
-
//
|
|
819
|
-
//
|
|
820
|
-
//
|
|
821
|
-
// the
|
|
831
|
+
// A wildcard that is not the last in the run is pinned to the whole
|
|
832
|
+
// fixed piece that separates it from the next wildcard, not just to
|
|
833
|
+
// that piece's first character: stopping at the first character alone
|
|
834
|
+
// would let the wildcard hand over at a place where the rest of the
|
|
835
|
+
// separator cannot follow, and the pin leaves no way back, so
|
|
836
|
+
// `f*o/*/*` would miss `foo/b/c` -- the first `o` of `foo` is not the
|
|
837
|
+
// one the `o/` after it needs. Every piece matches exactly one
|
|
838
|
+
// character, so pinning to the first place the whole separator fits
|
|
839
|
+
// is the leftmost place it can sit, and the wildcards that follow
|
|
840
|
+
// take up whatever is left.
|
|
822
841
|
out += at === lastWildcard
|
|
823
842
|
? WILDCARD
|
|
824
|
-
: `(?:(?!${run
|
|
843
|
+
: `(?:(?!${separatorAfter(run, at)})[^\\/])*`
|
|
825
844
|
})
|
|
826
845
|
|
|
827
846
|
run = []
|
|
@@ -632,6 +632,17 @@ var WILDCARD = '[^\\/]*';
|
|
|
632
632
|
// The source is read one token at a time -- a wildcard, a single-character
|
|
633
633
|
// piece (a literal, an escape, a class), or a parenthesised group or anchor
|
|
634
634
|
// that ends the run -- so only a genuine wildcard is touched.
|
|
635
|
+
|
|
636
|
+
// The fixed pieces between the wildcard at `at` and the next wildcard of the
|
|
637
|
+
// run, joined as they appear in the source. A run never holds two wildcards
|
|
638
|
+
// in a row, so there is always at least one piece.
|
|
639
|
+
var separatorAfter = function separatorAfter(run, at) {
|
|
640
|
+
var separator = EMPTY;
|
|
641
|
+
for (var index = at + 1; index < run.length && !run[index].wildcard; index++) {
|
|
642
|
+
separator += run[index].single;
|
|
643
|
+
}
|
|
644
|
+
return separator;
|
|
645
|
+
};
|
|
635
646
|
var pinWildcards = function pinWildcards(source) {
|
|
636
647
|
if (source.indexOf(WILDCARD) < 0) {
|
|
637
648
|
return source;
|
|
@@ -714,12 +725,17 @@ var pinWildcards = function pinWildcards(source) {
|
|
|
714
725
|
return;
|
|
715
726
|
}
|
|
716
727
|
|
|
717
|
-
// A wildcard that is not the last in the run is
|
|
718
|
-
//
|
|
719
|
-
//
|
|
720
|
-
//
|
|
721
|
-
// the
|
|
722
|
-
|
|
728
|
+
// A wildcard that is not the last in the run is pinned to the whole
|
|
729
|
+
// fixed piece that separates it from the next wildcard, not just to
|
|
730
|
+
// that piece's first character: stopping at the first character alone
|
|
731
|
+
// would let the wildcard hand over at a place where the rest of the
|
|
732
|
+
// separator cannot follow, and the pin leaves no way back, so
|
|
733
|
+
// `f*o/*/*` would miss `foo/b/c` -- the first `o` of `foo` is not the
|
|
734
|
+
// one the `o/` after it needs. Every piece matches exactly one
|
|
735
|
+
// character, so pinning to the first place the whole separator fits
|
|
736
|
+
// is the leftmost place it can sit, and the wildcards that follow
|
|
737
|
+
// take up whatever is left.
|
|
738
|
+
out += at === lastWildcard ? WILDCARD : "(?:(?!".concat(separatorAfter(run, at), ")[^\\/])*");
|
|
723
739
|
});
|
|
724
740
|
run = [];
|
|
725
741
|
};
|
|
@@ -781,7 +781,8 @@ function createMessageConnection(messageReader, messageWriter, _logger, options)
|
|
|
781
781
|
}
|
|
782
782
|
}
|
|
783
783
|
}
|
|
784
|
-
|
|
784
|
+
const error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : '';
|
|
785
|
+
tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms.${error}`, data);
|
|
785
786
|
}
|
|
786
787
|
else {
|
|
787
788
|
logLSPMessage('send-response', message);
|
|
@@ -1145,7 +1146,6 @@ function createMessageConnection(messageReader, messageWriter, _logger, options)
|
|
|
1145
1146
|
responsePromises.delete(id);
|
|
1146
1147
|
responsePromise.reject(new messages_1.ResponseError(messages_1.ErrorCodes.MessageWriteError, error.message ? error.message : 'Unknown reason'));
|
|
1147
1148
|
logger.error(`Sending request failed.`);
|
|
1148
|
-
throw error;
|
|
1149
1149
|
}
|
|
1150
1150
|
});
|
|
1151
1151
|
},
|
|
@@ -50,6 +50,7 @@ export interface PipeTransport {
|
|
|
50
50
|
export declare function createClientPipeTransport(pipeName: string, encoding?: RAL.MessageBufferEncoding): Promise<PipeTransport>;
|
|
51
51
|
export declare function createServerPipeTransport(pipeName: string, encoding?: RAL.MessageBufferEncoding): [MessageReader, MessageWriter];
|
|
52
52
|
export interface SocketTransport {
|
|
53
|
+
port(): number;
|
|
53
54
|
onConnected(): Promise<[MessageReader, MessageWriter]>;
|
|
54
55
|
}
|
|
55
56
|
export declare function createClientSocketTransport(port: number, encoding?: RAL.MessageBufferEncoding): Promise<SocketTransport>;
|
|
@@ -255,7 +255,14 @@ function createClientSocketTransport(port, encoding = 'utf-8') {
|
|
|
255
255
|
server.on('error', reject);
|
|
256
256
|
server.listen(port, '127.0.0.1', () => {
|
|
257
257
|
server.removeListener('error', reject);
|
|
258
|
+
const address = server.address();
|
|
259
|
+
if (address === null || typeof address === 'string') {
|
|
260
|
+
reject(new Error(`Unexpected server address: ${address}`));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const boundPort = address.port;
|
|
258
264
|
resolve({
|
|
265
|
+
port: () => boundPort,
|
|
259
266
|
onConnected: () => { return connected; }
|
|
260
267
|
});
|
|
261
268
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-jsonrpc",
|
|
3
3
|
"description": "A json rpc implementation over streams",
|
|
4
|
-
"version": "9.0.
|
|
4
|
+
"version": "9.0.3",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"msgpack-lite": "^0.1.26"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"prepublishOnly": "
|
|
37
|
+
"prepublishOnly": "npm run all:publish",
|
|
38
38
|
"prepack": "npm run all:publish",
|
|
39
39
|
"preversion": "npm test",
|
|
40
40
|
"compile": "tsc -b ./tsconfig.json",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RequestHandler, RequestHandler0 } from 'vscode-jsonrpc';
|
|
2
2
|
import { Range, TextDocumentIdentifier, InlayHint } from 'vscode-languageserver-types';
|
|
3
3
|
import { CM, MessageDirection, ProtocolRequestType, ProtocolRequestType0 } from './messages';
|
|
4
|
-
import { type StaticRegistrationOptions, type TextDocumentRegistrationOptions, type WorkDoneProgressOptions, type WorkDoneProgressParams } from './protocol';
|
|
4
|
+
import { type PartialResultParams, type StaticRegistrationOptions, type TextDocumentRegistrationOptions, type WorkDoneProgressOptions, type WorkDoneProgressParams } from './protocol';
|
|
5
5
|
/**
|
|
6
6
|
* @since 3.18.0
|
|
7
7
|
*/
|
|
@@ -67,7 +67,7 @@ export type InlayHintRegistrationOptions = InlayHintOptions & TextDocumentRegist
|
|
|
67
67
|
*
|
|
68
68
|
* @since 3.17.0
|
|
69
69
|
*/
|
|
70
|
-
export type InlayHintParams = WorkDoneProgressParams & {
|
|
70
|
+
export type InlayHintParams = WorkDoneProgressParams & PartialResultParams & {
|
|
71
71
|
/**
|
|
72
72
|
* The text document.
|
|
73
73
|
*/
|
package/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineCompletion.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InlineCompletionItem, InlineCompletionContext, InlineCompletionList } from 'vscode-languageserver-types';
|
|
2
2
|
import { RequestHandler } from 'vscode-jsonrpc';
|
|
3
3
|
import { CM, MessageDirection, ProtocolRequestType } from './messages';
|
|
4
|
-
import { type TextDocumentRegistrationOptions, type WorkDoneProgressOptions, type StaticRegistrationOptions, type WorkDoneProgressParams, type TextDocumentPositionParams } from './protocol';
|
|
4
|
+
import { type TextDocumentRegistrationOptions, type WorkDoneProgressOptions, type StaticRegistrationOptions, type WorkDoneProgressParams, type TextDocumentPositionParams, type PartialResultParams } from './protocol';
|
|
5
5
|
/**
|
|
6
6
|
* Client capabilities specific to inline completions.
|
|
7
7
|
*
|
|
@@ -30,7 +30,7 @@ export type InlineCompletionRegistrationOptions = InlineCompletionOptions & Text
|
|
|
30
30
|
*
|
|
31
31
|
* @since 3.18.0
|
|
32
32
|
*/
|
|
33
|
-
export type InlineCompletionParams = WorkDoneProgressParams & TextDocumentPositionParams & {
|
|
33
|
+
export type InlineCompletionParams = WorkDoneProgressParams & TextDocumentPositionParams & PartialResultParams & {
|
|
34
34
|
/**
|
|
35
35
|
* Additional information about the context in which inline completions were
|
|
36
36
|
* requested.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TextDocumentIdentifier, Range, InlineValue, InlineValueContext } from 'vscode-languageserver-types';
|
|
2
2
|
import { RequestHandler, RequestHandler0 } from 'vscode-jsonrpc';
|
|
3
3
|
import { CM, MessageDirection, ProtocolRequestType, ProtocolRequestType0 } from './messages';
|
|
4
|
-
import { type TextDocumentRegistrationOptions, type WorkDoneProgressOptions, type StaticRegistrationOptions, type WorkDoneProgressParams } from './protocol';
|
|
4
|
+
import { type TextDocumentRegistrationOptions, type WorkDoneProgressOptions, type StaticRegistrationOptions, type WorkDoneProgressParams, type PartialResultParams } from './protocol';
|
|
5
5
|
/**
|
|
6
6
|
* Client capabilities specific to inline values.
|
|
7
7
|
*
|
|
@@ -47,7 +47,7 @@ export type InlineValueRegistrationOptions = InlineValueOptions & TextDocumentRe
|
|
|
47
47
|
*
|
|
48
48
|
* @since 3.17.0
|
|
49
49
|
*/
|
|
50
|
-
export type InlineValueParams = WorkDoneProgressParams & {
|
|
50
|
+
export type InlineValueParams = WorkDoneProgressParams & PartialResultParams & {
|
|
51
51
|
/**
|
|
52
52
|
* The text document.
|
|
53
53
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-languageserver-protocol",
|
|
3
3
|
"description": "VSCode Language Server Protocol implementation",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.4",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"vscode-jsonrpc": "9.0.
|
|
31
|
-
"vscode-languageserver-types": "3.18.
|
|
30
|
+
"vscode-jsonrpc": "9.0.3",
|
|
31
|
+
"vscode-languageserver-types": "3.18.4"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
|
-
"prepublishOnly": "
|
|
34
|
+
"prepublishOnly": "npm run all:publish",
|
|
35
35
|
"prepack": "npm run all:publish",
|
|
36
36
|
"postpublish": "node ../build/npm/post-publish.js",
|
|
37
37
|
"preversion": "npm test",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-languageserver-types",
|
|
3
3
|
"description": "Types used by the Language server for node",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.4",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
|
-
"prepublishOnly": "
|
|
26
|
+
"prepublishOnly": "npm run all:publish",
|
|
27
27
|
"prepack": "npm run all:publish",
|
|
28
28
|
"compile": "tsc -b ./tsconfig.json",
|
|
29
29
|
"clean": "rimraf lib",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-lsp",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.1",
|
|
4
4
|
"description": "Language Server Protocol runtime for SuPi code intelligence",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"vscode-jsonrpc": "^9.0.0",
|
|
38
38
|
"vscode-languageserver-protocol": "^3.18.0",
|
|
39
39
|
"vscode-languageserver-types": "^3.18.0",
|
|
40
|
-
"@mrclrchtr/supi-
|
|
41
|
-
"@mrclrchtr/supi-
|
|
40
|
+
"@mrclrchtr/supi-core": "7.3.1",
|
|
41
|
+
"@mrclrchtr/supi-code-runtime": "7.3.1"
|
|
42
42
|
},
|
|
43
43
|
"bundledDependencies": [
|
|
44
44
|
"@mrclrchtr/supi-code-runtime",
|