Skip to content

Commit 4b35e13

Browse files
Feat add Ctrl+Q to fetch global documentation from selection and print to Output (#17)
Add Ctrl+Q shortcut to fetch global documentation for the current selection/line and print the response to the Output.
1 parent fee5628 commit 4b35e13

File tree

10 files changed

+194
-2
lines changed

10 files changed

+194
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Auto-indent dot syntax on Enter for `objectscript`/`objectscript-int` (replicates leading dots). (#6)
99
- Added `resolveContextExpression` command: posts current line/routine to API, inserts returned code on success, shows error otherwise. (#7)
1010
- Refactor API: extracted request util and updated endpoints (#8)
11+
- Add Ctrl+Q shortcut to fetch “global documentation” for the current selection/line and print the response to the Output. (#14)
1112

1213
## [3.0.6] 09-Sep-2025
1314

package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@
127127
"command": "vscode-objectscript.viewOthers",
128128
"when": "vscode-objectscript.connectActive"
129129
},
130+
{
131+
"command": "vscode-objectscript.getGlobalDocumentation",
132+
"when": "editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive"
133+
},
130134
{
131135
"command": "vscode-objectscript.subclass",
132136
"when": "editorLangId =~ /^objectscript/ && vscode-objectscript.connectActive"
@@ -840,6 +844,12 @@
840844
"command": "vscode-objectscript.resolveContextExpression",
841845
"title": "Resolve Context Expression"
842846
},
847+
{
848+
"category": "ObjectScript",
849+
"command": "vscode-objectscript.getGlobalDocumentation",
850+
"title": "Show Global Documentation",
851+
"enablement": "vscode-objectscript.connectActive"
852+
},
843853
{
844854
"category": "ObjectScript",
845855
"command": "vscode-objectscript.compile",
@@ -939,6 +949,12 @@
939949
"enablement": "vscode-objectscript.connectActive",
940950
"title": "View Other"
941951
},
952+
{
953+
"category": "ObjectScript",
954+
"command": "vscode-objectscript.getGlobalDocumentation",
955+
"enablement": "vscode-objectscript.connectActive",
956+
"title": "Show Global Documentation"
957+
},
942958
{
943959
"category": "ObjectScript",
944960
"command": "vscode-objectscript.subclass",
@@ -1220,6 +1236,12 @@
12201236
"mac": "Cmd+Alt+Space",
12211237
"when": "editorTextFocus && editorLangId =~ /^objectscript/"
12221238
},
1239+
{
1240+
"command": "vscode-objectscript.getGlobalDocumentation",
1241+
"key": "Ctrl+Q",
1242+
"mac": "Cmd+Q",
1243+
"when": "editorTextFocus && editorLangId =~ /^objectscript/"
1244+
},
12231245
{
12241246
"command": "vscode-objectscript.viewOthers",
12251247
"key": "Ctrl+Shift+V",

src/api/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,10 @@ export class AtelierAPI {
719719
});
720720
}
721721

722+
public getGlobalDocumentation(body: { selectedText: string }): Promise<Atelier.Response> {
723+
return this.request(1, "POST", `${this.ns}/action/getglobaldocumentation`, body);
724+
}
725+
722726
// v1+
723727
public actionCompile(docs: string[], flags?: string, source = false): Promise<Atelier.Response> {
724728
docs = docs.map((doc) => this.transformNameIfCsp(doc));
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as vscode from "vscode";
2+
3+
import { GlobalDocumentationClient } from "../sourcecontrol/clients/globalDocumentationClient";
4+
import { handleError, outputChannel } from "../../utils";
5+
6+
const sharedClient = new GlobalDocumentationClient();
7+
8+
function getSelectedOrCurrentLineText(editor: vscode.TextEditor): string {
9+
const { selection, document } = editor;
10+
11+
if (!selection || selection.isEmpty) {
12+
return document.lineAt(selection.active.line).text.trim();
13+
}
14+
15+
return document.getText(selection).trim();
16+
}
17+
18+
export async function showGlobalDocumentation(): Promise<void> {
19+
const editor = vscode.window.activeTextEditor;
20+
21+
if (!editor) {
22+
return;
23+
}
24+
25+
const selectedText = getSelectedOrCurrentLineText(editor);
26+
27+
if (!selectedText) {
28+
void vscode.window.showErrorMessage("Selection is empty. Select text or place the cursor on a line with content.");
29+
return;
30+
}
31+
32+
try {
33+
const content = await sharedClient.fetch(editor.document, { selectedText });
34+
35+
if (!content || !content.trim()) {
36+
void vscode.window.showInformationMessage("Global documentation did not return any content.");
37+
return;
38+
}
39+
40+
outputChannel.appendLine("==================== Global Documentation ====================");
41+
for (const line of content.split(/\r?\n/)) {
42+
outputChannel.appendLine(line);
43+
}
44+
outputChannel.show(true);
45+
} catch (error) {
46+
handleError(error, "Failed to retrieve global documentation.");
47+
}
48+
}

src/ccs/core/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ export interface SourceControlError {
88
message: string;
99
cause?: unknown;
1010
}
11+
export interface GlobalDocumentationResponse {
12+
content?: string | string[] | Record<string, unknown> | null;
13+
message?: string;
14+
}

src/ccs/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ export { getCcsSettings, isFlagEnabled, type CcsSettings } from "./config/settin
22
export { logDebug, logError, logInfo, logWarn } from "./core/logging";
33
export { SourceControlApi } from "./sourcecontrol/client";
44
export { resolveContextExpression } from "./commands/contextHelp";
5+
export { showGlobalDocumentation } from "./commands/globalDocumentation";
56
export { ContextExpressionClient } from "./sourcecontrol/clients/contextExpressionClient";
7+
export { GlobalDocumentationClient } from "./sourcecontrol/clients/globalDocumentationClient";
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import * as vscode from "vscode";
2+
3+
import { AtelierAPI } from "../../../api";
4+
import { getCcsSettings } from "../../config/settings";
5+
import { logDebug } from "../../core/logging";
6+
import { SourceControlApi } from "../client";
7+
import { ROUTES } from "../routes";
8+
9+
interface GlobalDocumentationPayload {
10+
selectedText: string;
11+
}
12+
13+
export class GlobalDocumentationClient {
14+
private readonly apiFactory: (api: AtelierAPI) => SourceControlApi;
15+
16+
public constructor(apiFactory: (api: AtelierAPI) => SourceControlApi = SourceControlApi.fromAtelierApi) {
17+
this.apiFactory = apiFactory;
18+
}
19+
20+
public async fetch(document: vscode.TextDocument, payload: GlobalDocumentationPayload): Promise<string> {
21+
const api = new AtelierAPI(document.uri);
22+
23+
let sourceControlApi: SourceControlApi;
24+
try {
25+
sourceControlApi = this.apiFactory(api);
26+
} catch (error) {
27+
logDebug("Failed to create SourceControl API client for global documentation", error);
28+
throw error;
29+
}
30+
31+
const { requestTimeout } = getCcsSettings();
32+
33+
try {
34+
const response = await sourceControlApi.post<string>(ROUTES.getGlobalDocumentation(), payload, {
35+
timeout: requestTimeout,
36+
responseType: "text",
37+
transformResponse: [(data) => data],
38+
validateStatus: (status) => status >= 200 && status < 300,
39+
});
40+
41+
return typeof response.data === "string" ? response.data : "";
42+
} catch (error) {
43+
logDebug("Global documentation request failed", error);
44+
throw error;
45+
}
46+
}
47+
}

src/ccs/sourcecontrol/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const BASE_PATH = "/api/sourcecontrol/vscode" as const;
22

33
export const ROUTES = {
44
resolveContextExpression: () => `/resolveContextExpression`,
5+
getGlobalDocumentation: () => `/getGlobalDocumentation`,
56
} as const;
67

78
export type RouteKey = keyof typeof ROUTES;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as vscode from "vscode";
2+
3+
import { AtelierAPI } from "../api";
4+
import { currentFile, handleError, outputChannel } from "../utils";
5+
6+
function getSelectedOrCurrentLineText(editor: vscode.TextEditor): string {
7+
const { selection, document } = editor;
8+
if (!selection || selection.isEmpty) {
9+
return document.lineAt(selection.active.line).text.trim();
10+
}
11+
return document.getText(selection).trim();
12+
}
13+
14+
export async function showGlobalDocumentation(): Promise<void> {
15+
const file = currentFile();
16+
const editor = vscode.window.activeTextEditor;
17+
18+
if (!file || !editor) {
19+
return;
20+
}
21+
22+
const selectedText = getSelectedOrCurrentLineText(editor);
23+
24+
if (!selectedText) {
25+
void vscode.window.showErrorMessage("Selection is empty. Select text or place the cursor on a line with content.");
26+
return;
27+
}
28+
29+
const api = new AtelierAPI(file.uri);
30+
31+
if (!api.active) {
32+
void vscode.window.showErrorMessage("No active connection to retrieve global documentation.");
33+
return;
34+
}
35+
36+
try {
37+
const response = await api.getGlobalDocumentation({ selectedText });
38+
const content = response?.result?.content;
39+
let output = "";
40+
41+
if (Array.isArray(content)) {
42+
output = content.join("\n");
43+
} else if (typeof content === "string") {
44+
output = content;
45+
} else if (content && typeof content === "object") {
46+
output = JSON.stringify(content, null, 2);
47+
}
48+
49+
if (!output) {
50+
void vscode.window.showInformationMessage("Global documentation did not return any content.");
51+
return;
52+
}
53+
54+
outputChannel.appendLine("==================== Global Documentation ====================");
55+
outputChannel.appendLine(output);
56+
outputChannel.show(true);
57+
} catch (error) {
58+
handleError(error, "Failed to retrieve global documentation.");
59+
}
60+
}

src/extension.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ import {
162162
import { WorkspaceNode, NodeBase } from "./explorer/nodes";
163163
import { showPlanWebview } from "./commands/showPlanPanel";
164164
import { isfsConfig } from "./utils/FileProviderUtil";
165-
import { resolveContextExpression } from "./ccs";
166-
165+
import { resolveContextExpression, showGlobalDocumentation } from "./ccs";
167166
const packageJson = vscode.extensions.getExtension(extensionId).packageJSON;
168167
const extensionVersion = packageJson.version;
169168
const aiKey = packageJson.aiKey;
@@ -1372,6 +1371,10 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
13721371
sendCommandTelemetryEvent("viewOthers");
13731372
viewOthers(false);
13741373
}),
1374+
vscode.commands.registerCommand("vscode-objectscript.getGlobalDocumentation", () => {
1375+
sendCommandTelemetryEvent("getGlobalDocumentation");
1376+
void showGlobalDocumentation();
1377+
}),
13751378
vscode.commands.registerCommand("vscode-objectscript.serverCommands.sourceControl", (uri?: vscode.Uri) => {
13761379
sendCommandTelemetryEvent("serverCommands.sourceControl");
13771380
mainSourceControlMenu(uri);

0 commit comments

Comments
 (0)