Skip to content

Commit d20d478

Browse files
authored
fix: handle nested config files in tasks sidebar (#1111)
1 parent 3b25415 commit d20d478

File tree

3 files changed

+63
-95
lines changed

3 files changed

+63
-95
lines changed

client/src/lsp_extensions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export const registryState = new NotificationType<RegistryStateParams>(
3030

3131
export interface TaskRequestResponse {
3232
name: string;
33+
// TODO(nayeemrmn): `detail` is being renamed to `command`. Eventually update
34+
// the server's serialization of this field to `command` and remove `detail`.
35+
command: string | null;
3336
detail: string;
3437
sourceUri: string;
3538
}

client/src/tasks.ts

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
22

3-
import { task as taskReq } from "./lsp_extensions";
3+
import * as path from "path";
44
import type { DenoExtensionContext } from "./types";
55
import { getDenoCommandName, isWorkspaceFolder } from "./util";
66

77
import * as vscode from "vscode";
88

99
export const TASK_TYPE = "deno";
1010
export const TASK_SOURCE = "deno";
11-
export const TASK_CONFIG_SOURCE = "deno task";
1211

1312
interface DenoConfigTaskDefinition extends vscode.TaskDefinition {
1413
name: string;
@@ -46,23 +45,37 @@ export function buildDenoTask(
4645
);
4746
}
4847

49-
function buildDenoConfigTask(
48+
export function buildDenoConfigTask(
5049
scope: vscode.WorkspaceFolder,
5150
process: string,
5251
name: string,
53-
detail?: string,
52+
command: string | undefined,
53+
sourceUri?: vscode.Uri,
5454
): vscode.Task {
55-
const execution = new vscode.ProcessExecution(process, ["task", name]);
56-
55+
const args = [];
56+
if (
57+
sourceUri &&
58+
vscode.Uri.joinPath(sourceUri, "..").toString() != scope.uri.toString()
59+
) {
60+
const configPath = path.relative(scope.uri.fsPath, sourceUri.fsPath);
61+
args.push("-c", configPath);
62+
}
63+
args.push(name);
5764
const task = new vscode.Task(
58-
{ type: TASK_TYPE, name, detail },
65+
{
66+
type: TASK_TYPE,
67+
name: name,
68+
command: "task",
69+
args,
70+
sourceUri,
71+
},
5972
scope,
6073
name,
61-
TASK_CONFIG_SOURCE,
62-
execution,
74+
TASK_SOURCE,
75+
new vscode.ProcessExecution(process, ["task", ...args]),
6376
["$deno"],
6477
);
65-
task.detail = detail;
78+
task.detail = `$ ${command}`;
6679
return task;
6780
}
6881

@@ -134,31 +147,6 @@ class DenoTaskProvider implements vscode.TaskProvider {
134147
}
135148
}
136149

137-
// we retrieve config tasks from the language server, if the language server
138-
// supports the capability
139-
const client = this.#extensionContext.client;
140-
const supportsConfigTasks = this.#extensionContext.serverCapabilities
141-
?.experimental?.denoConfigTasks;
142-
if (client && supportsConfigTasks) {
143-
try {
144-
const configTasks = await client.sendRequest(taskReq);
145-
for (const workspaceFolder of vscode.workspace.workspaceFolders ?? []) {
146-
if (configTasks) {
147-
for (const { name, detail } of configTasks) {
148-
tasks.push(
149-
buildDenoConfigTask(workspaceFolder, process, name, detail),
150-
);
151-
}
152-
}
153-
}
154-
} catch (err) {
155-
vscode.window.showErrorMessage("Failed to retrieve config tasks.");
156-
this.#extensionContext.outputChannel.appendLine(
157-
`Error retrieving config tasks: ${err}`,
158-
);
159-
}
160-
}
161-
162150
return tasks;
163151
}
164152

client/src/tasks_sidebar.ts

Lines changed: 37 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { task as taskReq } from "./lsp_extensions";
12
import * as path from "path";
23
import {
34
commands,
45
EventEmitter,
56
ExtensionContext,
67
Position,
7-
ProcessExecution,
88
Selection,
99
Task,
1010
TaskProvider,
@@ -25,7 +25,7 @@ import {
2525
readTaskDefinitions,
2626
} from "./util";
2727
import { DenoExtensionContext } from "./types";
28-
import { task as taskReq } from "./lsp_extensions";
28+
import { buildDenoConfigTask, TASK_TYPE } from "./tasks";
2929

3030
class Folder extends TreeItem {
3131
configs: DenoJSON[] = [];
@@ -109,26 +109,6 @@ class DenoTask extends TreeItem {
109109
}
110110
}
111111

112-
function buildDenoConfigTask(
113-
scope: WorkspaceFolder,
114-
process: string,
115-
name: string,
116-
command: string,
117-
sourceUri: Uri,
118-
): Task {
119-
const execution = new ProcessExecution(process, ["task", name]);
120-
const task = new Task(
121-
{ type: "denoTasks", name, command, sourceUri },
122-
scope,
123-
name,
124-
"deno task",
125-
execution,
126-
["$deno"],
127-
);
128-
task.detail = command;
129-
return task;
130-
}
131-
132112
class NoScripts extends TreeItem {
133113
constructor(message: string) {
134114
super(message, TreeItemCollapsibleState.None);
@@ -144,47 +124,46 @@ class DenoTaskProvider implements TaskProvider {
144124
}
145125

146126
async provideTasks(): Promise<Task[]> {
147-
const tasks: Task[] = [];
148-
149127
const process = await getDenoCommandName();
150-
151-
// we retrieve config tasks from the language server, if the language server
152-
// supports the capability
153128
const client = this.#extensionContext.client;
154129
const supportsConfigTasks = this.#extensionContext.serverCapabilities
155130
?.experimental?.denoConfigTasks;
156-
if (client && supportsConfigTasks) {
157-
try {
158-
const configTasks = await client.sendRequest(taskReq);
159-
for (const { name, detail: command, sourceUri } of configTasks ?? []) {
160-
const workspaceFolder = (workspace.workspaceFolders ?? []).find((f) =>
161-
// NOTE: skipEncoding in Uri.toString(), read more at https://github.com/microsoft/vscode/commit/65cb3397673b922c1b6759d145a3a183feb3ee5d
162-
sourceUri
163-
.toLocaleLowerCase()
164-
.startsWith(f.uri.toString(true).toLocaleLowerCase())
165-
);
166-
if (!workspaceFolder) {
167-
continue;
168-
}
169-
170-
tasks.push(
171-
buildDenoConfigTask(
172-
workspaceFolder,
173-
process,
174-
name,
175-
command,
176-
Uri.parse(sourceUri),
177-
),
178-
);
131+
if (!client || !supportsConfigTasks) {
132+
return [];
133+
}
134+
const tasks = [];
135+
try {
136+
const configTasks = await client.sendRequest(taskReq);
137+
for (const configTask of configTasks ?? []) {
138+
const workspaceFolders = Array.from(
139+
workspace.workspaceFolders ?? [],
140+
);
141+
workspaceFolders.reverse();
142+
const workspaceFolder = workspaceFolders.find((f) =>
143+
// NOTE: skipEncoding in Uri.toString(), read more at https://github.com/microsoft/vscode/commit/65cb3397673b922c1b6759d145a3a183feb3ee5d
144+
// See https://github.com/denoland/vscode_deno/issues/991#issuecomment-1825340906.
145+
configTask.sourceUri
146+
.toLocaleLowerCase()
147+
.startsWith(f.uri.toString(true).toLocaleLowerCase())
148+
);
149+
if (!workspaceFolder) {
150+
continue;
179151
}
180-
} catch (err) {
181-
window.showErrorMessage("Failed to retrieve config tasks.");
182-
this.#extensionContext.outputChannel.appendLine(
183-
`Error retrieving config tasks: ${err}`,
152+
const task = buildDenoConfigTask(
153+
workspaceFolder,
154+
process,
155+
configTask.name,
156+
configTask.command ?? configTask.detail,
157+
Uri.parse(configTask.sourceUri),
184158
);
159+
tasks.push(task);
185160
}
161+
} catch (err) {
162+
window.showErrorMessage("Failed to retrieve config tasks.");
163+
this.#extensionContext.outputChannel.appendLine(
164+
`Error retrieving config tasks: ${err}`,
165+
);
186166
}
187-
188167
return tasks;
189168
}
190169

@@ -198,16 +177,13 @@ type TaskTree = Folder[] | DenoJSON[] | NoScripts[];
198177

199178
export class DenoTasksTreeDataProvider implements TreeDataProvider<TreeItem> {
200179
#taskTree: TaskTree | null = null;
201-
#extensionContext: DenoExtensionContext;
202180
#onDidChangeTreeData = new EventEmitter<TreeItem | null>();
203181
readonly onDidChangeTreeData = this.#onDidChangeTreeData.event;
204182

205183
constructor(
206-
context: DenoExtensionContext,
207184
public taskProvider: DenoTaskProvider,
208185
subscriptions: ExtensionContext["subscriptions"],
209186
) {
210-
this.#extensionContext = context;
211187
subscriptions.push(
212188
commands.registerCommand("deno.client.runTask", this.#runTask, this),
213189
);
@@ -401,10 +377,11 @@ export function registerSidebar(
401377
if (!workspace.workspaceFolders) return;
402378

403379
const taskProvider = new DenoTaskProvider(context);
404-
subscriptions.push(tasks.registerTaskProvider("denoTasks", taskProvider));
380+
subscriptions.push(
381+
tasks.registerTaskProvider(TASK_TYPE, taskProvider),
382+
);
405383

406384
const treeDataProvider = new DenoTasksTreeDataProvider(
407-
context,
408385
taskProvider,
409386
subscriptions,
410387
);

0 commit comments

Comments
 (0)