diff --git a/package.json b/package.json index 5afdf999..5d11b1d5 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,11 @@ "title": "Send Request", "category": "Rest Client" }, + { + "command": "rest-client.run-all-requests-sequentialy", + "title": "Send all requests sequentially", + "category": "Rest Client" + }, { "command": "rest-client.rerun-last-request", "title": "Rerun Last Request", @@ -287,6 +292,12 @@ "mac": "cmd+alt+r", "when": "editorTextFocus && editorLangId == 'http'" }, + { + "command": "rest-client.run-all-requests-sequentialy", + "key": "ctrl+shift+r", + "mac": "cmd+shift+r", + "when": "editorTextFocus" + }, { "command": "rest-client.request", "key": "ctrl+alt+r", diff --git a/src/controllers/requestController.ts b/src/controllers/requestController.ts index 3726ca2d..f3783b34 100644 --- a/src/controllers/requestController.ts +++ b/src/controllers/requestController.ts @@ -1,6 +1,6 @@ import { ExtensionContext, Range, TextDocument, ViewColumn, window } from 'vscode'; import Logger from '../logger'; -import { IRestClientSettings, RequestSettings, RestClientSettings } from '../models/configurationSettings'; +import { IRestClientSettings, RequestSettings, RestClientSettings} from '../models/configurationSettings'; import { HistoricalHttpRequest, HttpRequest } from '../models/httpRequest'; import { RequestMetadata } from '../models/requestMetadata'; import { RequestParserFactory } from '../models/requestParserFactory'; @@ -30,6 +30,55 @@ export class RequestController { this._textDocumentView = new HttpResponseTextDocumentView(); } + @trace('Send All Requests Sequentially') + public async runAllSequentially() { + const editor = window.activeTextEditor; + const document = getCurrentTextDocument(); + if (!editor || !document) { + return; + } + + const confirmation = await window.showInformationMessage( + "Are you sure you want to run all requests in this document?", + "Yes", + "No" + ); + + if (confirmation !== "Yes") { + return; + } + + // Get all requests in the document + const requests = await Selector.getAllRequests(editor, document); + if (!requests || requests.length === 0) { + window.showInformationMessage('No HTTP requests found in the current file.'); + return; + } + + const activeColumn = window.activeTextEditor!.viewColumn; + + + for (const selectedRequest of requests) { + const { text, metadatas } = selectedRequest; + const name = metadatas.get(RequestMetadata.Name); + + if (metadatas.has(RequestMetadata.Note)) { + const note = name ? `Are you sure you want to send the request "${name}"?` : 'Are you sure you want to send this request?'; + const userConfirmed = await window.showWarningMessage(note, 'Yes', 'No'); + if (userConfirmed !== 'Yes') { + continue; + } + } + + const requestSettings = new RequestSettings(metadatas); + const settings: IRestClientSettings = new RestClientSettings(requestSettings); + + const httpRequest = await RequestParserFactory.createRequestParser(text, settings).parseHttpRequest(name); + + await this.runCore(httpRequest, settings, activeColumn, document); + } + } + @trace('Request') public async run(range: Range) { const editor = window.activeTextEditor; @@ -59,8 +108,9 @@ export class RequestController { // parse http request const httpRequest = await RequestParserFactory.createRequestParser(text, settings).parseHttpRequest(name); + const activeColumn = window.activeTextEditor!.viewColumn; - await this.runCore(httpRequest, settings, document); + await this.runCore(httpRequest, settings, activeColumn, document); } @trace('Rerun Request') @@ -89,7 +139,13 @@ export class RequestController { } } - private async runCore(httpRequest: HttpRequest, settings: IRestClientSettings, document?: TextDocument) { + private async runCore( + httpRequest: HttpRequest, + settings: IRestClientSettings, + activeColumn?: ViewColumn, + document?: TextDocument, + options?: { appendToPreview?: boolean } + ) { // clear status bar this._requestStatusEntry.update({ state: RequestState.Pending }); @@ -97,7 +153,6 @@ export class RequestController { this._lastPendingRequest = httpRequest; this._lastRequestSettingTuple = [httpRequest, settings]; - // set http request try { const response = await this._httpClient.send(httpRequest, settings); @@ -113,7 +168,6 @@ export class RequestController { } try { - const activeColumn = window.activeTextEditor!.viewColumn; const previewColumn = settings.previewColumn === ViewColumn.Active ? activeColumn : ((activeColumn as number) + 1) as ViewColumn; diff --git a/src/extension.ts b/src/extension.ts index 9f8ad35d..1c0d7cfd 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -39,6 +39,7 @@ export async function activate(context: ExtensionContext) { context.subscriptions.push(codeSnippetController); context.subscriptions.push(environmentController); context.subscriptions.push(commands.registerCommand('rest-client.request', ((document: TextDocument, range: Range) => requestController.run(range)))); + context.subscriptions.push(commands.registerCommand('rest-client.run-all-requests-sequentialy', () => requestController.runAllSequentially())); context.subscriptions.push(commands.registerCommand('rest-client.rerun-last-request', () => requestController.rerun())); context.subscriptions.push(commands.registerCommand('rest-client.cancel-request', () => requestController.cancel())); context.subscriptions.push(commands.registerCommand('rest-client.history', () => historyController.save())); diff --git a/src/models/configurationSettings.ts b/src/models/configurationSettings.ts index 20da7373..64ddc87f 100644 --- a/src/models/configurationSettings.ts +++ b/src/models/configurationSettings.ts @@ -474,5 +474,7 @@ export class RestClientSettings implements IRestClientSettings { private readonly systemSettings = SystemSettings.Instance; public constructor(private readonly requestSettings: RequestSettings) { + + } } diff --git a/src/utils/selector.ts b/src/utils/selector.ts index a1ea6621..bfbcff5f 100644 --- a/src/utils/selector.ts +++ b/src/utils/selector.ts @@ -20,6 +20,42 @@ interface PromptVariableDefinition { export class Selector { private static readonly responseStatusLineRegex = /^\s*HTTP\/[\d.]+/; + public static async getAllRequests(editor: TextEditor, document: TextDocument): Promise { + const requests: SelectedRequest[] = []; + const fullText = document.getText(); + const lines = fullText.split(Constants.LineSplitterRegex); + + // Get all request ranges in the document + const requestRanges = this.getRequestRanges(lines); + + for (const [start, end] of requestRanges) { + const requestLines = lines.slice(start, end + 1); + // Parse metadata for this request + const metadatas = this.parseReqMetadatas(requestLines); + + // Prompt for variables if needed + const promptVariablesDefinitions = this.parsePromptMetadataForVariableDefinitions(metadatas.get(RequestMetadata.Prompt)); + const promptVariables = await this.promptForInput(promptVariablesDefinitions); + if (!promptVariables) { + // If user cancels prompt, skip this request + continue; + } + + + // Remove comment lines for the actual request + const rawLines = requestLines.filter(l => !this.isCommentLine(l)); + const requestText = await VariableProcessor.processRawRequest(rawLines.join(EOL), promptVariables); + + requests.push({ + text: requestText, + metadatas: metadatas + }); + } + + return requests; + } + + public static async getRequest(editor: TextEditor, range: Range | null = null): Promise { if (!editor.document) { return null; diff --git a/src/views/httpResponseTextDocumentView.ts b/src/views/httpResponseTextDocumentView.ts index 803c83a8..d611a400 100644 --- a/src/views/httpResponseTextDocumentView.ts +++ b/src/views/httpResponseTextDocumentView.ts @@ -8,6 +8,22 @@ import { formatHeaders } from '../utils/misc'; import { ResponseFormatUtility } from '../utils/responseFormatUtility'; export class HttpResponseTextDocumentView { + public async append(combined: string, column?: ViewColumn) { + const content = combined; + let document: TextDocument; + if (this.documents.length === 0) { + document = await workspace.openTextDocument({ language: 'http', content }); + this.documents.push(document); + await window.showTextDocument(document, { viewColumn: column, preserveFocus: !this.settings.previewResponsePanelTakeFocus, preview: false }); + } else { + document = this.documents[this.documents.length - 1]; + const editor = await window.showTextDocument(document, { viewColumn: column, preserveFocus: !this.settings.previewResponsePanelTakeFocus, preview: false }); + editor.edit(edit => { + const endPosition = document.lineAt(document.lineCount - 1).range.end; + edit.insert(endPosition, `\n${content}`); + }); + } + } private readonly settings: SystemSettings = SystemSettings.Instance;