Skip to content

Commit fe0256d

Browse files
acuaricaHuachao
andauthored
Add Markdown support to run requests with code lenses (#933)
* Support sending requests from Markdown code blocks * Activate the extension on Markdown as well * Add docs for Markdown code lenses * Fix linting error Co-authored-by: Huachao Mao <[email protected]>
1 parent b55aa79 commit fe0256d

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ REST Client allows you to send HTTP request and view the response in Visual Stud
5757
- Support navigate to symbol definitions(request and file level custom variable) in open `http` file
5858
- CodeLens support to add an actionable link to send request
5959
- Fold/Unfold for request block
60+
* Support for Markdown fenced code blocks with either `http` or `rest`
6061

6162
## Usage
6263
In editor, type an HTTP request as simple as below:

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
"onCommand:rest-client.copy-request-as-curl",
5555
"onCommand:rest-client.fold-response",
5656
"onCommand:rest-client.unfold-response",
57-
"onLanguage:http"
57+
"onLanguage:http",
58+
"onLanguage:markdown"
5859
],
5960
"main": "./dist/extension",
6061
"contributes": {

src/extension.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { FileVariableReferencesCodeLensProvider } from './providers/fileVariable
1515
import { HttpCodeLensProvider } from './providers/httpCodeLensProvider';
1616
import { HttpCompletionItemProvider } from './providers/httpCompletionItemProvider';
1717
import { HttpDocumentSymbolProvider } from './providers/httpDocumentSymbolProvider';
18+
import { MarkdownCodeLensProvider } from './providers/markdownCodeLensProvider';
1819
import { RequestVariableCompletionItemProvider } from "./providers/requestVariableCompletionItemProvider";
1920
import { RequestVariableDefinitionProvider } from './providers/requestVariableDefinitionProvider';
2021
import { RequestVariableHoverProvider } from './providers/requestVariableHoverProvider';
@@ -54,6 +55,10 @@ export async function activate(context: ExtensionContext) {
5455
{ language: 'http', scheme: '*' }
5556
];
5657

58+
const mdDocumentSelector = [
59+
{ language: 'markdown', scheme: '*' }
60+
];
61+
5762
context.subscriptions.push(languages.registerCompletionItemProvider(documentSelector, new HttpCompletionItemProvider()));
5863
context.subscriptions.push(languages.registerCompletionItemProvider(documentSelector, new RequestVariableCompletionItemProvider(), '.'));
5964
context.subscriptions.push(languages.registerHoverProvider(documentSelector, new EnvironmentOrFileVariableHoverProvider()));
@@ -66,6 +71,10 @@ export async function activate(context: ExtensionContext) {
6671
new ConfigurationDependentRegistration(
6772
() => languages.registerCodeLensProvider(documentSelector, new FileVariableReferencesCodeLensProvider()),
6873
s => s.enableCustomVariableReferencesCodeLens));
74+
context.subscriptions.push(
75+
new ConfigurationDependentRegistration(
76+
() => languages.registerCodeLensProvider(mdDocumentSelector, new MarkdownCodeLensProvider()),
77+
s => s.enableSendRequestCodeLens));
6978
context.subscriptions.push(languages.registerDocumentLinkProvider(documentSelector, new RequestBodyDocumentLinkProvider()));
7079
context.subscriptions.push(languages.registerDefinitionProvider(documentSelector, new FileVariableDefinitionProvider()));
7180
context.subscriptions.push(languages.registerDefinitionProvider(documentSelector, new RequestVariableDefinitionProvider()));
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { CancellationToken, CodeLens, CodeLensProvider, Command, Range, TextDocument } from 'vscode';
2+
import { Selector } from '../utils/selector';
3+
4+
export class MarkdownCodeLensProvider implements CodeLensProvider {
5+
6+
public provideCodeLenses(document: TextDocument, _token: CancellationToken): Promise<CodeLens[]> {
7+
const blocks: CodeLens[] = [];
8+
9+
for (const range of Selector.getMarkdownRestSnippets(document)) {
10+
const snippetRange = new Range(range.start.line + 1, 0, range.end.line, 0);
11+
const cmd: Command = {
12+
arguments: [document, snippetRange],
13+
title: 'Send Request',
14+
command: 'rest-client.request',
15+
};
16+
blocks.push(new CodeLens(range, cmd));
17+
}
18+
19+
return Promise.resolve(blocks);
20+
}
21+
22+
}

src/utils/selector.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { EOL } from 'os';
2-
import { Range, TextEditor, window } from 'vscode';
2+
import { Position, Range, TextDocument, TextEditor, window } from 'vscode';
33
import * as Constants from '../common/constants';
44
import { fromString as ParseReqMetaKey, RequestMetadata } from '../models/requestMetadata';
55
import { SelectedRequest } from '../models/SelectedRequest';
@@ -28,7 +28,19 @@ export class Selector {
2828
let selectedText: string | null;
2929
if (editor.selection.isEmpty || range) {
3030
const activeLine = range?.start.line ?? editor.selection.active.line;
31-
selectedText = this.getDelimitedText(editor.document.getText(), activeLine);
31+
if (editor.document.languageId === 'markdown') {
32+
selectedText = null;
33+
34+
for (const r of Selector.getMarkdownRestSnippets(editor.document)) {
35+
const snippetRange = new Range(r.start.line + 1, 0, r.end.line, 0);
36+
if (snippetRange.contains(new Position(activeLine, 0))) {
37+
selectedText = editor.document.getText(snippetRange);
38+
}
39+
}
40+
41+
} else {
42+
selectedText = this.getDelimitedText(editor.document.getText(), activeLine);
43+
}
3244
} else {
3345
selectedText = editor.document.getText(editor.selection);
3446
}
@@ -231,6 +243,31 @@ export class Selector {
231243
.map(([index, ]) => +index);
232244
}
233245

246+
public static* getMarkdownRestSnippets(document: TextDocument): Generator<Range> {
247+
const snippetStartRegx = new RegExp('^\`\`\`(' + ['http', 'rest'].join('|') + ')$');
248+
const snippetEndRegx = /^\`\`\`$/;
249+
250+
let snippetStart: number | null = null;
251+
for (let i = 0; i < document.lineCount; i++) {
252+
const lineText = document.lineAt(i).text;
253+
254+
const matchEnd = lineText.match(snippetEndRegx);
255+
if (snippetStart !== null && matchEnd) {
256+
const snippetEnd = i;
257+
258+
const range = new Range(snippetStart, 0, snippetEnd, 0);
259+
yield range;
260+
261+
snippetStart = null;
262+
} else {
263+
const matchStart = lineText.match(snippetStartRegx);
264+
if (matchStart) {
265+
snippetStart = i;
266+
}
267+
}
268+
}
269+
}
270+
234271
private static handlePromptMetadata(metadatas: Map<RequestMetadata, string | undefined> , text: string) {
235272
const promptVarDef = this.getPrompVariableDefinition(text);
236273
if (promptVarDef) {

0 commit comments

Comments
 (0)