-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement "go to definition" for task
- Loading branch information
Showing
8 changed files
with
361 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import os from "node:os"; | ||
import vscode from "vscode"; | ||
import { isMiseExtensionEnabled } from "../configuration"; | ||
import type { MiseService } from "../miseService"; | ||
import { expandPath } from "../utils/fileUtils"; | ||
import { | ||
type MiseTomlType, | ||
TomlParser, | ||
findTaskDefinition, | ||
} from "../utils/miseFileParser"; | ||
import { DEPENDS_KEYWORDS } from "../utils/miseUtilts"; | ||
|
||
export class TaskDefinitionProvider implements vscode.DefinitionProvider { | ||
private miseService: MiseService; | ||
constructor(miseService: MiseService) { | ||
this.miseService = miseService; | ||
} | ||
|
||
public async provideDefinition( | ||
document: vscode.TextDocument, | ||
position: vscode.Position, | ||
): Promise<vscode.LocationLink[]> { | ||
if (!isMiseExtensionEnabled()) { | ||
return []; | ||
} | ||
|
||
const tasks = await this.miseService.getTasks({ includeHidden: true }); | ||
const tasksSources = tasks.map((t) => expandPath(t.source)); | ||
if (!tasksSources.includes(document.uri.fsPath)) { | ||
return []; | ||
} | ||
|
||
const tomParser = new TomlParser<MiseTomlType>(document.getText()); | ||
|
||
const keyAtPosition = tomParser.getKeyAtPosition(position); | ||
const keyPath = keyAtPosition?.key ?? []; | ||
if (!keyPath.length) { | ||
return []; | ||
} | ||
|
||
if (!DEPENDS_KEYWORDS.includes(keyPath.at(-1) || "")) { | ||
return []; | ||
} | ||
|
||
const taskNameRange = document.getWordRangeAtPosition(position, /[\w:-]+/); | ||
if (!taskNameRange) { | ||
return []; | ||
} | ||
|
||
const taskName = document.getText(taskNameRange); | ||
|
||
const task = tasks.find((t) => t.name === taskName); | ||
if (!task) { | ||
return []; | ||
} | ||
|
||
const uri = vscode.Uri.file(task.source.replace(/^~/, os.homedir())); | ||
const taskDocument = await vscode.workspace.openTextDocument(uri); | ||
|
||
const foundPosition = findTaskDefinition(taskDocument, task.name); | ||
|
||
return [ | ||
{ | ||
originSelectionRange: taskNameRange, | ||
targetUri: vscode.Uri.parse(task.source), | ||
targetSelectionRange: new vscode.Range( | ||
foundPosition.start, | ||
foundPosition.end, | ||
), | ||
targetRange: new vscode.Range( | ||
foundPosition.start, | ||
foundPosition.end.translate(100, 100), // hack to make the range visible, improve later | ||
), | ||
}, | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { describe, expect, it } from "bun:test"; | ||
|
||
import { type MiseTomlType, TomlParser } from "./miseFileParser"; | ||
|
||
describe("miseFileParser", () => { | ||
it("mise.toml", () => { | ||
const tomlParser = new TomlParser<MiseTomlType>( | ||
` | ||
[tasks.example] | ||
depends = [ | ||
"example2" | ||
] | ||
`.trim(), | ||
); | ||
|
||
expect(tomlParser.parsed).toEqual({ | ||
tasks: { example: { depends: ["example2"] } }, | ||
}); | ||
|
||
expect(tomlParser.getAllPositions()).toEqual([ | ||
{ | ||
keyStart: { line: 0, character: 0 }, | ||
keyEnd: { line: 0, character: 5 }, | ||
valueStart: { line: 0, character: 0 }, | ||
valueEnd: { line: 0, character: 5 }, | ||
key: ["tasks"], | ||
value: { example: { depends: ["example2"] } }, | ||
}, | ||
{ | ||
keyStart: { line: 0, character: 6 }, | ||
keyEnd: { line: 0, character: 13 }, | ||
valueStart: { line: 0, character: 0 }, | ||
valueEnd: { line: 0, character: 14 }, | ||
key: ["tasks", "example"], | ||
value: { depends: ["example2"] }, | ||
}, | ||
{ | ||
keyStart: { line: 1, character: 0 }, | ||
keyEnd: { line: 1, character: 7 }, | ||
valueStart: { line: 1, character: 10 }, | ||
valueEnd: { line: 3, character: 1 }, | ||
key: ["tasks", "example", "depends"], | ||
value: ["example2"], | ||
}, | ||
]); | ||
|
||
expect(tomlParser.getKeyAtPosition({ line: 0, character: 0 })).toEqual({ | ||
keyStart: { line: 0, character: 6 }, | ||
keyEnd: { line: 0, character: 13 }, | ||
valueStart: { line: 0, character: 0 }, | ||
valueEnd: { line: 0, character: 14 }, | ||
key: ["tasks", "example"], | ||
value: { depends: ["example2"] }, | ||
}); | ||
|
||
expect(tomlParser.getKeyAtPosition({ line: 2, character: 5 })).toEqual({ | ||
keyStart: { line: 1, character: 0 }, | ||
keyEnd: { line: 1, character: 7 }, | ||
valueStart: { line: 1, character: 10 }, | ||
valueEnd: { line: 3, character: 1 }, | ||
key: ["tasks", "example", "depends"], | ||
value: ["example2"], | ||
}); | ||
}); | ||
|
||
it("task files", () => { | ||
const tomlParser = new TomlParser<object>( | ||
` | ||
ci = { depends = ["format", "build", "test"] } | ||
`.trim(), | ||
); | ||
|
||
expect(tomlParser.parsed).toEqual({ | ||
ci: { depends: ["format", "build", "test"] }, | ||
}); | ||
|
||
expect(tomlParser.getAllPositions()).toEqual([ | ||
{ | ||
keyStart: { line: 0, character: 0 }, | ||
keyEnd: { line: 0, character: 1 }, | ||
valueStart: { line: 0, character: 4 }, | ||
valueEnd: { line: 0, character: 45 }, | ||
key: ["ci"], | ||
value: { depends: ["format", "build", "test"] }, | ||
}, | ||
{ | ||
keyStart: { line: 0, character: 6 }, | ||
keyEnd: { line: 0, character: 13 }, | ||
valueStart: { line: 0, character: 16 }, | ||
valueEnd: { line: 0, character: 43 }, | ||
key: ["ci", "depends"], | ||
value: ["format", "build", "test"], | ||
}, | ||
]); | ||
}); | ||
}); |
Oops, something went wrong.