Skip to content

Commit c38e2cb

Browse files
throttle convert requests to 10Hz
1 parent f9d3eb3 commit c38e2cb

File tree

3 files changed

+119
-64
lines changed

3 files changed

+119
-64
lines changed

package-lock.json

+47
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,7 @@
13971397
"@types/chai-subset": "^1.3.5",
13981398
"@types/glob": "^7.1.6",
13991399
"@types/lcov-parse": "^1.0.2",
1400+
"@types/lodash.throttle": "^4.1.9",
14001401
"@types/mocha": "^10.0.10",
14011402
"@types/mock-fs": "^4.13.4",
14021403
"@types/node": "^18.19.71",
@@ -1419,6 +1420,7 @@
14191420
"esbuild": "^0.24.2",
14201421
"eslint": "^8.57.0",
14211422
"eslint-config-prettier": "^10.0.1",
1423+
"lodash.throttle": "^4.1.1",
14221424
"mocha": "^10.8.2",
14231425
"mock-fs": "^5.4.1",
14241426
"node-pty": "^1.0.0",

src/documentation/DocumentationPreviewEditor.ts

+70-64
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { RenderNode, WebviewContent, WebviewMessage } from "./webview/WebviewMes
1919
import { WorkspaceContext } from "../WorkspaceContext";
2020
import { DocCDocumentationRequest, DocCDocumentationResponse } from "../sourcekit-lsp/extensions";
2121
import { LSPErrorCodes, ResponseError } from "vscode-languageclient";
22+
// eslint-disable-next-line @typescript-eslint/no-require-imports
23+
import throttle = require("lodash.throttle");
2224

2325
export enum PreviewEditorConstant {
2426
VIEW_TYPE = "swift.previewDocumentationEditor",
@@ -178,73 +180,77 @@ export class DocumentationPreviewEditor implements vscode.Disposable {
178180
}
179181
}
180182

181-
private async convertDocumentation(textEditor: vscode.TextEditor): Promise<void> {
182-
const document = textEditor.document;
183-
if (
184-
document.uri.scheme !== "file" ||
185-
!["markdown", "tutorial", "swift"].includes(document.languageId)
186-
) {
187-
this.postMessage({
188-
type: "update-content",
189-
content: {
190-
type: "error",
191-
errorMessage: PreviewEditorConstant.UNSUPPORTED_EDITOR_ERROR_MESSAGE,
192-
},
193-
});
194-
return;
195-
}
183+
private convertDocumentation = throttle(
184+
async (textEditor: vscode.TextEditor): Promise<void> => {
185+
const document = textEditor.document;
186+
if (
187+
document.uri.scheme !== "file" ||
188+
!["markdown", "tutorial", "swift"].includes(document.languageId)
189+
) {
190+
this.postMessage({
191+
type: "update-content",
192+
content: {
193+
type: "error",
194+
errorMessage: PreviewEditorConstant.UNSUPPORTED_EDITOR_ERROR_MESSAGE,
195+
},
196+
});
197+
return;
198+
}
196199

197-
try {
198-
const response = await this.context.languageClientManager.useLanguageClient(
199-
async (client): Promise<DocCDocumentationResponse> => {
200-
return await client.sendRequest(DocCDocumentationRequest.type, {
201-
textDocument: {
202-
uri: document.uri.toString(),
203-
},
204-
position: textEditor.selection.start,
205-
});
206-
}
207-
);
208-
this.postMessage({
209-
type: "update-content",
210-
content: {
211-
type: "render-node",
212-
renderNode: this.parseRenderNode(response.renderNode),
213-
},
214-
});
215-
} catch (error) {
216-
// Update the preview editor to reflect what error occurred
217-
let livePreviewErrorMessage = "An internal error occurred";
218-
const baseLogErrorMessage = `SourceKit-LSP request "${DocCDocumentationRequest.method}" failed: `;
219-
if (error instanceof ResponseError) {
220-
if (error.code === LSPErrorCodes.RequestCancelled) {
221-
// We can safely ignore cancellations
222-
return undefined;
200+
try {
201+
const response = await this.context.languageClientManager.useLanguageClient(
202+
async (client): Promise<DocCDocumentationResponse> => {
203+
return await client.sendRequest(DocCDocumentationRequest.type, {
204+
textDocument: {
205+
uri: document.uri.toString(),
206+
},
207+
position: textEditor.selection.start,
208+
});
209+
}
210+
);
211+
this.postMessage({
212+
type: "update-content",
213+
content: {
214+
type: "render-node",
215+
renderNode: this.parseRenderNode(response.renderNode),
216+
},
217+
});
218+
} catch (error) {
219+
// Update the preview editor to reflect what error occurred
220+
let livePreviewErrorMessage = "An internal error occurred";
221+
const baseLogErrorMessage = `SourceKit-LSP request "${DocCDocumentationRequest.method}" failed: `;
222+
if (error instanceof ResponseError) {
223+
if (error.code === LSPErrorCodes.RequestCancelled) {
224+
// We can safely ignore cancellations
225+
return undefined;
226+
}
227+
switch (error.code) {
228+
case LSPErrorCodes.RequestFailed:
229+
// RequestFailed response errors can be shown to the user
230+
livePreviewErrorMessage = error.message;
231+
break;
232+
default:
233+
// We should log additional info for other response errors
234+
this.context.outputChannel.log(
235+
baseLogErrorMessage + JSON.stringify(error.toJson(), undefined, 2)
236+
);
237+
break;
238+
}
239+
} else {
240+
this.context.outputChannel.log(baseLogErrorMessage + `${error}`);
223241
}
224-
switch (error.code) {
225-
case LSPErrorCodes.RequestFailed:
226-
// RequestFailed response errors can be shown to the user
227-
livePreviewErrorMessage = error.message;
228-
break;
229-
default:
230-
// We should log additional info for other response errors
231-
this.context.outputChannel.log(
232-
baseLogErrorMessage + JSON.stringify(error.toJson(), undefined, 2)
233-
);
234-
break;
235-
}
236-
} else {
237-
this.context.outputChannel.log(baseLogErrorMessage + `${error}`);
242+
this.postMessage({
243+
type: "update-content",
244+
content: {
245+
type: "error",
246+
errorMessage: livePreviewErrorMessage,
247+
},
248+
});
238249
}
239-
this.postMessage({
240-
type: "update-content",
241-
content: {
242-
type: "error",
243-
errorMessage: livePreviewErrorMessage,
244-
},
245-
});
246-
}
247-
}
250+
},
251+
100 /* 10 times per second */,
252+
{ trailing: true }
253+
);
248254

249255
private parseRenderNode(content: string): RenderNode {
250256
const renderNode: RenderNode = JSON.parse(content);

0 commit comments

Comments
 (0)