Polish extension
This commit is contained in:
59
vscode-extensions/vscode-spring-cli/README.md
Normal file
59
vscode-extensions/vscode-spring-cli/README.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# Spring CLI Extension
|
||||||
|
|
||||||
|
The extension integrates into Visual Studio Code UI [Spring CLI](https://docs.spring.io/spring-cli/reference/) which increases productivity when new Spring Boot projects are created or new functionality added to existing projects.
|
||||||
|
|
||||||
|
Easy way to add new functionality to Spring Boot projects from predefined projects registered with Spring CLI or from Gen AI by right-clikcing on the project's `pom.xml`
|
||||||
|
|
||||||
|
![Add-Functionality][Add-Functionality]
|
||||||
|
|
||||||
|
Easy access to the Gen AI generated Mardown file with an easy way to apply it:
|
||||||
|
|
||||||
|
![Gen-AI-Markdown][Gen-AI-markdown]
|
||||||
|
|
||||||
|
Applying the Gen AI response markdown guide to a project shows a diff view of what is about to happen to the project and can be undone via IDE provided "Undo" functionality
|
||||||
|
|
||||||
|
![Prewview-Changes][Preview-Changes]
|
||||||
|
|
||||||
|
Furthermore, managing Spring CLI projects, projects catalogs and user defined commands is nicely wrapped into VSCode quick-pick UI elements via commands.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
**IMPORTANT** The extension requires Spring CLI to be installed on your system. See [Spring CLI Installation Guide](https://docs.spring.io/spring-cli/reference/installation.html). If Spring CLI executable is on the `PATH` environment variable then please use Spring CLI Extension setting `spring-cli.executable` to specify the path to Spring CLI executable file.
|
||||||
|
|
||||||
|
## Supported Features
|
||||||
|
|
||||||
|
Create new Spring Boot project using predefined Spring Boot projects known to Spring CLI (`boot new` CLI command). The command is available via:
|
||||||
|
- Command Palette: **Spring CLI: New Boot Project**
|
||||||
|
|
||||||
|
Add functionality to a Spring Boot project from a list of predefined Spring Boot projects known to Spring CLI (`boot add` CLI command). The command is available via:
|
||||||
|
- Right-click menu item on `pom.xml`: **Add to Boot Project**
|
||||||
|
- Command Palette: **Spring CLI: Add to Boot Project**
|
||||||
|
|
||||||
|
Add functionality to a Spring Boot project from answer received from Gen AI (`ai add` CLI command). The command is available via:
|
||||||
|
- Right-click menu item on `pom.xml`: **Add from AI**
|
||||||
|
- Command Palette: **Spring CLI: Add from AI**
|
||||||
|
|
||||||
|
Apply changes outlined in the Markdown guide file received as an answer to user query from Gen AI (`guide apply` CLI command). The command is available via:
|
||||||
|
- Right-click menu item on `README-ai-*.md`: **Apply Guide**
|
||||||
|
- Command Palette: **Spring CLI: Apply Guide**
|
||||||
|
|
||||||
|
Add/Remove predefined projects catalog (`project-catalog add/remove` CLI commands). Available via:
|
||||||
|
- Command Palette: **Spring CLI: Add Project Catalog**
|
||||||
|
- Command Palette: **Spring CLI: Remove Project Catalog**
|
||||||
|
|
||||||
|
Add/Remove predefined projects (`project add/remove` CLI commands). Available via:
|
||||||
|
- Command Palette: **Spring CLI: Add Project**
|
||||||
|
- Command Palette: **Spring CLI: Remove Project**
|
||||||
|
|
||||||
|
New/Add/Remove user-defined command (`command new/add/remove` CLI commands). Commands can be created/added/removed locally to the workspace or globally. Available via:
|
||||||
|
- Command Palette: **Spring CLI: New User-Defined Command** (Create the command skeleton which then needs to be adjusted to user needs)
|
||||||
|
- Command Palette: **Spring CLI: Add User-Defined Command** (Adds a command to Spring CLI from a Git repo)
|
||||||
|
- Command Palette: **Spring CLI: Remove User-Defined Command**
|
||||||
|
|
||||||
|
Execute user-defined command. Allows user to select user-defined command either locally in the workpsace or globally, then the sub-command and then enter the parameters for the selected command and finally execute it. Available via:
|
||||||
|
- Command Palette: **Spring CLI: Execute User-Defined Command**
|
||||||
|
|
||||||
|
[Add-Functionality]: ./doc-images/Add-Functionality.png
|
||||||
|
[Gen-AI-markdown]: ./doc-images/AI-Markdown.png
|
||||||
|
[Preview-Changes]: ./doc-images/Preview-Changes.png
|
||||||
|
|
||||||
|
|
||||||
BIN
vscode-extensions/vscode-spring-cli/doc-images/AI-Markdown.png
Normal file
BIN
vscode-extensions/vscode-spring-cli/doc-images/AI-Markdown.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 197 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "vscode-spring-cli",
|
"name": "vscode-spring-cli",
|
||||||
"version": "1.52.0",
|
"version": "1.55.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "vscode-spring-cli",
|
"name": "vscode-spring-cli",
|
||||||
"version": "1.52.0",
|
"version": "1.55.0",
|
||||||
"license": "EPL-1.0",
|
"license": "EPL-1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"displayName": "Spring CLI Support",
|
"displayName": "Spring CLI Support",
|
||||||
"description": "Spring CLI integrated into IDE",
|
"description": "Spring CLI integrated into IDE",
|
||||||
"icon": "spring-boot-logo.png",
|
"icon": "spring-boot-logo.png",
|
||||||
"version": "1.55.0",
|
"version": "1.0.0",
|
||||||
"publisher": "vmware",
|
"publisher": "vmware",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -33,13 +33,13 @@
|
|||||||
"group": "Spring-CLI"
|
"group": "Spring-CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": "resourceFilename =~ /README-\\S+.md/",
|
"when": "resourceFilename == pom.xml",
|
||||||
"command": "vscode-spring-cli.guide.apply",
|
"command": "vscode-spring-cli.ai.add",
|
||||||
"group": "Spring-CLI"
|
"group": "Spring-CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": "resourceFilename =~ /README-\\S+.md/",
|
"when": "resourceFilename =~ /README-\\S+.md/",
|
||||||
"command": "vscode-spring-cli.guide.run",
|
"command": "vscode-spring-cli.guide.apply",
|
||||||
"group": "Spring-CLI"
|
"group": "Spring-CLI"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -50,13 +50,13 @@
|
|||||||
"group": "Spring-CLI"
|
"group": "Spring-CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": "resourceFilename =~ /README-\\S+.md/",
|
"when": "resourceFilename == pom.xml",
|
||||||
"command": "vscode-spring-cli.guide.apply",
|
"command": "vscode-spring-cli.ai.add",
|
||||||
"group": "Spring-CLI"
|
"group": "Spring-CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": "resourceFilename =~ /README-\\S+.md/",
|
"when": "resourceFilename =~ /README-\\S+.md/",
|
||||||
"command": "vscode-spring-cli.guide.run",
|
"command": "vscode-spring-cli.guide.apply",
|
||||||
"group": "Spring-CLI"
|
"group": "Spring-CLI"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -94,22 +94,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "vscode-spring-cli.command.add",
|
"command": "vscode-spring-cli.command.add",
|
||||||
"title": "Add User Defined Command",
|
"title": "Add User-Defined Command",
|
||||||
"category": "Spring CLI"
|
"category": "Spring CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "vscode-spring-cli.command.remove",
|
"command": "vscode-spring-cli.command.remove",
|
||||||
"title": "Remove User Defined Command",
|
"title": "Remove User-Defined Command",
|
||||||
"category": "Spring CLI"
|
"category": "Spring CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "vscode-spring-cli.command.new",
|
"command": "vscode-spring-cli.command.new",
|
||||||
"title": "New User Defined Command",
|
"title": "New User-Defined Command",
|
||||||
"category": "Spring CLI"
|
"category": "Spring CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "vscode-spring-cli.command.execute",
|
"command": "vscode-spring-cli.command.execute",
|
||||||
"title": "Execute User Defined Command",
|
"title": "Execute User-Defined Command",
|
||||||
"category": "Spring CLI"
|
"category": "Spring CLI"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -121,11 +121,6 @@
|
|||||||
"command": "vscode-spring-cli.guide.apply",
|
"command": "vscode-spring-cli.guide.apply",
|
||||||
"title": "Apply Guide",
|
"title": "Apply Guide",
|
||||||
"category": "Spring CLI"
|
"category": "Spring CLI"
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "vscode-spring-cli.guide.run",
|
|
||||||
"title": "Run Guide",
|
|
||||||
"category": "Spring CLI"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"configuration": {
|
"configuration": {
|
||||||
|
|||||||
@@ -2,19 +2,33 @@ import { Uri, commands, window } from "vscode";
|
|||||||
import { CLI } from "./extension";
|
import { CLI } from "./extension";
|
||||||
import { enterText, getTargetPomXml } from "./utils";
|
import { enterText, getTargetPomXml } from "./utils";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { handleGuideApply } from "./guide";
|
import { handleGuideApplyWorkspaceEdit } from "./guide";
|
||||||
|
import { CANCELLED } from "./cli";
|
||||||
|
|
||||||
export async function handleAiAdd(pom: Uri) {
|
export async function handleAiAdd(pom: Uri) {
|
||||||
if (!pom) {
|
let question: string;
|
||||||
pom = await getTargetPomXml();
|
try {
|
||||||
|
if (!pom) {
|
||||||
|
pom = await getTargetPomXml();
|
||||||
|
}
|
||||||
|
question = await enterText({
|
||||||
|
title: "Question",
|
||||||
|
prompt: "Enter question to LLM",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// ignore: cancellation via UI
|
||||||
}
|
}
|
||||||
const question = await enterText({
|
try {
|
||||||
title: "Question",
|
if (question.trim().length > 0) {
|
||||||
prompt: "Enter question to LLM",
|
const uri = await CLI.aiAdd(question, path.dirname(pom.fsPath));
|
||||||
});
|
await commands.executeCommand("markdown.showPreview", uri);
|
||||||
const uri = await CLI.aiAdd(question, path.dirname(pom.fsPath));
|
if ("Yes" === await window.showInformationMessage(`Apply guide '${path.basename(uri.fsPath)}' to the project?`, "Yes", "No")) {
|
||||||
await commands.executeCommand("markdown.showPreview", uri);
|
handleGuideApplyWorkspaceEdit(uri);
|
||||||
if ("Yes" === await window.showInformationMessage(`Apply guide '${path.basename(uri.fsPath)}' to the project?`, "Yes", "No")) {
|
}
|
||||||
handleGuideApply(uri);
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== CANCELLED) {
|
||||||
|
window.showErrorMessage(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { WorkspaceEdit } from "vscode-languageclient";
|
|||||||
|
|
||||||
export const SPRING_CLI_TASK_TYPE = 'spring-cli';
|
export const SPRING_CLI_TASK_TYPE = 'spring-cli';
|
||||||
|
|
||||||
|
export const CANCELLED = "Cancelled";
|
||||||
|
|
||||||
export class Cli {
|
export class Cli {
|
||||||
|
|
||||||
get executable(): string {
|
get executable(): string {
|
||||||
@@ -46,7 +48,7 @@ export class Cli {
|
|||||||
"--file",
|
"--file",
|
||||||
uri.fsPath
|
uri.fsPath
|
||||||
];
|
];
|
||||||
return this.fetchJson("Running guide", uri.fsPath, args, cwd || path.dirname(uri.fsPath));
|
return this.fetchJson("Running guide", uri.fsPath, args, cwd || path.dirname(uri.fsPath), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
aiAdd(question: string, cwd: string): Thenable<Uri> {
|
aiAdd(question: string, cwd: string): Thenable<Uri> {
|
||||||
@@ -70,23 +72,31 @@ export class Cli {
|
|||||||
|
|
||||||
return new Promise<Uri>(async (resolve, reject) => {
|
return new Promise<Uri>(async (resolve, reject) => {
|
||||||
if (cancellation.isCancellationRequested) {
|
if (cancellation.isCancellationRequested) {
|
||||||
reject("Cancelled");
|
reject(CANCELLED);
|
||||||
}
|
}
|
||||||
const processOpts = { cwd: cwd || getWorkspaceRoot()?.fsPath || homedir() };
|
const processOpts = { cwd: cwd || getWorkspaceRoot()?.fsPath || homedir() };
|
||||||
const process = this.executable.endsWith(".jar") ? await cp.exec(`java -jar ${this.executable} ${args.join(" ")}`, processOpts) : await cp.exec(`${this.executable} ${args.join(" ")}`, processOpts);
|
const process = this.executable.endsWith(".jar") ? await cp.exec(`java -jar ${this.executable} ${args.join(" ")}`, processOpts) : await cp.exec(`${this.executable} ${args.join(" ")}`, processOpts);
|
||||||
cancellation.onCancellationRequested(() => process.kill());
|
cancellation.onCancellationRequested(() => process.kill());
|
||||||
const errorMessageChunks = [];
|
const errorMessageChunks = [];
|
||||||
let guideFileName;
|
let guideFileName;
|
||||||
|
let errorMessageInStdOut;
|
||||||
process.stdout.on("data", s => {
|
process.stdout.on("data", s => {
|
||||||
const res = /README-\S+.md/.exec(s);
|
const res = /README-\S+.md/.exec(s);
|
||||||
if (res.length) {
|
if (res && res.length) {
|
||||||
guideFileName = res[0].trim();
|
guideFileName = res[0].trim();
|
||||||
|
} else {
|
||||||
|
errorMessageInStdOut = s;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
process.stderr.on("data", s => errorMessageChunks.push(s))
|
process.stderr.on("data", s => errorMessageChunks.push(s))
|
||||||
process.on("exit", (code) => {
|
process.on("exit", (code) => {
|
||||||
if (code) {
|
if (code) {
|
||||||
reject(`Failed to get response from LLM. ${errorMessageChunks.join()}`);
|
if (cancellation.isCancellationRequested) {
|
||||||
|
reject(CANCELLED);
|
||||||
|
} else {
|
||||||
|
const errorMessage = (errorMessageChunks.length == 0 ? errorMessageInStdOut : errorMessageChunks.join()) || "";
|
||||||
|
reject(`Failed to get response from LLM. ${errorMessage}`);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
resolve(Uri.file(path.join(cwd, guideFileName)));
|
resolve(Uri.file(path.join(cwd, guideFileName)));
|
||||||
}
|
}
|
||||||
@@ -159,12 +169,20 @@ export class Cli {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
commandNew(cwd: string) {
|
commandNew(cwd: string, commandName?: string, subCommandName?: string) {
|
||||||
const args = [
|
const args = [
|
||||||
"command",
|
"command",
|
||||||
"new",
|
"new",
|
||||||
];
|
];
|
||||||
return this.exec("Remove Command", undefined, args, cwd);
|
if (commandName) {
|
||||||
|
args.push("--command-name")
|
||||||
|
args.push(commandName);
|
||||||
|
}
|
||||||
|
if (subCommandName) {
|
||||||
|
args.push("--sub-command-name")
|
||||||
|
args.push(subCommandName);
|
||||||
|
}
|
||||||
|
return this.exec("New Command", undefined, args, cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
commandExecute(metadata: CommandExecuteMetadata, cwd: string) {
|
commandExecute(metadata: CommandExecuteMetadata, cwd: string) {
|
||||||
@@ -309,7 +327,7 @@ export class Cli {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchJson<T>(title: string, message: string, args: string[], cwd?: string) : Promise<T> {
|
private async fetchJson<T>(title: string, message: string, args: string[], cwd?: string, omitJsonParam?: boolean) : Promise<T> {
|
||||||
|
|
||||||
return window.withProgress({
|
return window.withProgress({
|
||||||
location: ProgressLocation.Window,
|
location: ProgressLocation.Window,
|
||||||
@@ -323,16 +341,20 @@ export class Cli {
|
|||||||
|
|
||||||
return new Promise<T>(async (resolve, reject) => {
|
return new Promise<T>(async (resolve, reject) => {
|
||||||
if (cancellation.isCancellationRequested) {
|
if (cancellation.isCancellationRequested) {
|
||||||
reject("Cancelled");
|
reject(CANCELLED);
|
||||||
}
|
}
|
||||||
const processOpts = { cwd: cwd || getWorkspaceRoot()?.fsPath || homedir() };
|
const processOpts = { cwd: cwd || getWorkspaceRoot()?.fsPath || homedir() };
|
||||||
const process = this.executable.endsWith(".jar") ? await cp.exec(`java -jar ${this.executable} ${args.join(" ")}`, processOpts) : await cp.exec(`${this.executable} ${args.join(" ")} --json`, processOpts);
|
const process = this.executable.endsWith(".jar") ? await cp.exec(`java -jar ${this.executable} ${args.join(" ")}`, processOpts) : await cp.exec(`${this.executable} ${args.join(" ")} ${omitJsonParam ? "" : "--json"}`, processOpts);
|
||||||
cancellation.onCancellationRequested(() => process.kill());
|
cancellation.onCancellationRequested(() => process.kill());
|
||||||
const dataChunks: string[] = [];
|
const dataChunks: string[] = [];
|
||||||
process.stdout.on("data", s => dataChunks.push(s));
|
process.stdout.on("data", s => dataChunks.push(s));
|
||||||
process.on("exit", (code) => {
|
process.on("exit", (code) => {
|
||||||
if (code) {
|
if (code) {
|
||||||
reject(`Failed to fetch data: ${dataChunks.join()}`);
|
if (cancellation.isCancellationRequested) {
|
||||||
|
reject(CANCELLED);
|
||||||
|
} else {
|
||||||
|
reject(`Failed to fetch data: ${dataChunks.join()}`);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
resolve(JSON.parse(dataChunks.join()) as T);
|
resolve(JSON.parse(dataChunks.join()) as T);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { enterText } from "./utils";
|
|||||||
import { CLI } from "./extension";
|
import { CLI } from "./extension";
|
||||||
import { homedir } from "os";
|
import { homedir } from "os";
|
||||||
import { CommandInfo } from "./cli-types";
|
import { CommandInfo } from "./cli-types";
|
||||||
|
import { CANCELLED } from "./cli";
|
||||||
|
|
||||||
interface SubCommandQuickPickItem extends QuickPickItem {
|
interface SubCommandQuickPickItem extends QuickPickItem {
|
||||||
info?: CommandInfo;
|
info?: CommandInfo;
|
||||||
@@ -50,22 +51,50 @@ export async function handleCommandAdd(uri?: Uri) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function handleCommandRemove(uri?: Uri) {
|
export async function handleCommandRemove(uri?: Uri) {
|
||||||
// Enter CWD for CLI (global vs workspace folder local command)
|
try {
|
||||||
const cwd = await enterCwd(uri);
|
// Enter CWD for CLI (global vs workspace folder local command)
|
||||||
// Select the command
|
const cwd = await enterCwd(uri);
|
||||||
const command = await pickCommand(cwd);
|
// Select the command
|
||||||
// Select the subcommand
|
const command = await pickCommand(cwd);
|
||||||
const subcommand = (await pickSubCommand(cwd, command))?.label;
|
if (!command) {
|
||||||
return CLI.commandRemove({
|
return;
|
||||||
command,
|
}
|
||||||
subcommand,
|
// Select the subcommand
|
||||||
cwd
|
const subcommand = (await pickSubCommand(cwd, command))?.label;
|
||||||
});
|
if (!subcommand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return CLI.commandRemove({
|
||||||
|
command,
|
||||||
|
subcommand,
|
||||||
|
cwd
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== CANCELLED) {
|
||||||
|
window.showErrorMessage(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleCommandNew(uri?: Uri) {
|
export async function handleCommandNew(uri?: Uri) {
|
||||||
const cwd = await enterCwd(uri);
|
const cwd = await enterCwd(uri);
|
||||||
return CLI.commandNew(cwd);
|
const cmdName = await enterText({
|
||||||
|
prompt: "Enter Command Name",
|
||||||
|
title: "Command Name",
|
||||||
|
defaultValue: "hello"
|
||||||
|
});
|
||||||
|
if (!cmdName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const subCmdName = await enterText({
|
||||||
|
prompt: "Enter Sub-Command Name",
|
||||||
|
title: "Sub-Command Name",
|
||||||
|
defaultValue: "new"
|
||||||
|
});
|
||||||
|
if (!subCmdName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return CLI.commandNew(cwd, cmdName, subCmdName);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleCommandExecute(uri?: Uri) {
|
export async function handleCommandExecute(uri?: Uri) {
|
||||||
@@ -73,39 +102,51 @@ export async function handleCommandExecute(uri?: Uri) {
|
|||||||
const cwd = await enterCwd(uri);
|
const cwd = await enterCwd(uri);
|
||||||
// Select the command
|
// Select the command
|
||||||
const command = await pickCommand(cwd);
|
const command = await pickCommand(cwd);
|
||||||
|
if (!command) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Select the subcommand
|
// Select the subcommand
|
||||||
const subcommand = (await pickSubCommand(cwd, command));
|
const subcommand = (await pickSubCommand(cwd, command));
|
||||||
|
if (!subcommand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const params = {};
|
const params = {};
|
||||||
|
|
||||||
if (Array.isArray(subcommand?.info?.options)) {
|
try {
|
||||||
for (const o of subcommand.info.options) {
|
if (Array.isArray(subcommand?.info?.options)) {
|
||||||
let value;
|
for (const o of subcommand.info.options) {
|
||||||
if (o.choices) {
|
let value;
|
||||||
const quickPickItems = Object.keys(o.choices).map(s => ({
|
if (o.choices) {
|
||||||
label: s,
|
const quickPickItems = Object.keys(o.choices).map(s => ({
|
||||||
value: o.choices[s]
|
label: s,
|
||||||
}) as ChoiceQuickPickItem);
|
value: o.choices[s]
|
||||||
value = (await window.showQuickPick(quickPickItems, { canPickMany: false, ignoreFocusOut: true })).value;
|
}) as ChoiceQuickPickItem);
|
||||||
} else {
|
value = (await window.showQuickPick(quickPickItems, { canPickMany: false, ignoreFocusOut: true })).value;
|
||||||
value = await enterText({
|
} else {
|
||||||
title: o.paramLabel || o.name,
|
value = await enterText({
|
||||||
defaultValue: o.defaultValue,
|
title: o.paramLabel || o.name,
|
||||||
placeholder: o.defaultValue,
|
defaultValue: o.defaultValue,
|
||||||
prompt: `Enter ${o.paramLabel || o.name}${o.description ? " - " : ""}${o.description}`
|
placeholder: o.defaultValue,
|
||||||
});
|
prompt: `Enter ${o.paramLabel || o.name}${o.description ? " - " : ""}${o.description}`
|
||||||
}
|
});
|
||||||
if (value) {
|
}
|
||||||
params[o.name] = value;
|
if (value) {
|
||||||
}
|
params[o.name] = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLI.commandExecute({
|
||||||
|
command,
|
||||||
|
subcommand: subcommand.label,
|
||||||
|
params
|
||||||
|
}, cwd);
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== CANCELLED) {
|
||||||
|
window.showErrorMessage(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CLI.commandExecute({
|
|
||||||
command,
|
|
||||||
subcommand: subcommand.label,
|
|
||||||
params
|
|
||||||
}, cwd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapFolderToQuickPickItem(folder: WorkspaceFolder): QuickPickItem {
|
function mapFolderToQuickPickItem(folder: WorkspaceFolder): QuickPickItem {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { handleProjectAdd, handleProjectRemove } from "./project";
|
|||||||
import { handleCommandAdd, handleCommandExecute, handleCommandNew, handleCommandRemove } from "./command";
|
import { handleCommandAdd, handleCommandExecute, handleCommandNew, handleCommandRemove } from "./command";
|
||||||
import { ExtensionContext, commands, tasks } from "vscode";
|
import { ExtensionContext, commands, tasks } from "vscode";
|
||||||
import { handleAiAdd } from "./ai";
|
import { handleAiAdd } from "./ai";
|
||||||
import { handleGuideApply, handleGuideRun } from "./guide";
|
import { handleGuideApplyWorkspaceEdit } from "./guide";
|
||||||
|
|
||||||
export const CLI = new Cli();
|
export const CLI = new Cli();
|
||||||
|
|
||||||
@@ -29,8 +29,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
|
|||||||
|
|
||||||
commands.registerCommand('vscode-spring-cli.ai.add', handleAiAdd),
|
commands.registerCommand('vscode-spring-cli.ai.add', handleAiAdd),
|
||||||
|
|
||||||
commands.registerCommand('vscode-spring-cli.guide.apply', handleGuideApply),
|
commands.registerCommand('vscode-spring-cli.guide.apply', handleGuideApplyWorkspaceEdit),
|
||||||
commands.registerCommand('vscode-spring-cli.guide.run', handleGuideRun),
|
|
||||||
|
|
||||||
tasks.registerTaskProvider(SPRING_CLI_TASK_TYPE, new CliTaskProvider(CLI))
|
tasks.registerTaskProvider(SPRING_CLI_TASK_TYPE, new CliTaskProvider(CLI))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import { getTargetGuideMardown } from "./utils";
|
|||||||
import { CLI } from "./extension";
|
import { CLI } from "./extension";
|
||||||
import { createConverter } from "vscode-languageclient/lib/common/protocolConverter";
|
import { createConverter } from "vscode-languageclient/lib/common/protocolConverter";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
import { CANCELLED } from "./cli";
|
||||||
|
|
||||||
|
const APPLY = "Apply";
|
||||||
|
const PREVIEW = "Preview"
|
||||||
|
|
||||||
const CONVERTER = createConverter(undefined, true, true);
|
const CONVERTER = createConverter(undefined, true, true);
|
||||||
export async function handleGuideApply(uri: Uri) {
|
export async function handleGuideApply(uri: Uri) {
|
||||||
@@ -12,23 +16,41 @@ export async function handleGuideApply(uri: Uri) {
|
|||||||
return CLI.guideApply(uri);
|
return CLI.guideApply(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleGuideRun(uri: Uri) {
|
export async function handleGuideApplyWorkspaceEdit(uri: Uri) {
|
||||||
if (!uri) {
|
try {
|
||||||
uri = await getTargetGuideMardown();
|
if (!uri) {
|
||||||
}
|
uri = await getTargetGuideMardown();
|
||||||
const lspEdit = await CLI.guideLspEdit(uri);
|
|
||||||
const workspaceEdit = await CONVERTER.asWorkspaceEdit(lspEdit);
|
|
||||||
|
|
||||||
// This is some sort of workaround for undo
|
|
||||||
// If editors for existing doc not opened then undo isn't properly working
|
|
||||||
await Promise.all(workspaceEdit.entries().map(async ([uri, edits]) => {
|
|
||||||
if (fs.existsSync(uri.fsPath)) {
|
|
||||||
const doc = await workspace.openTextDocument(uri.fsPath);
|
|
||||||
await window.showTextDocument(doc);
|
|
||||||
}
|
}
|
||||||
}));
|
const lspEdit = await CLI.guideLspEdit(uri);
|
||||||
|
|
||||||
|
if (lspEdit.changeAnnotations && Object.keys(lspEdit.changeAnnotations).length > 0) {
|
||||||
|
const answer = await window.showInformationMessage("Do you want to apply changes right away or preview before applying?", APPLY, PREVIEW);
|
||||||
|
if (!answer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const preview = answer === PREVIEW;
|
||||||
|
Object.keys(lspEdit.changeAnnotations).forEach(changeId => {
|
||||||
|
lspEdit.changeAnnotations[changeId].needsConfirmation = preview;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const workspaceEdit = await CONVERTER.asWorkspaceEdit(lspEdit);
|
||||||
|
|
||||||
return await workspace.applyEdit(workspaceEdit, {
|
// This is some sort of workaround for undo
|
||||||
isRefactoring: true
|
// If editors for existing doc not opened then undo isn't properly working
|
||||||
});
|
await Promise.all(workspaceEdit.entries().map(async ([uri, edits]) => {
|
||||||
|
if (fs.existsSync(uri.fsPath)) {
|
||||||
|
const doc = await workspace.openTextDocument(uri.fsPath);
|
||||||
|
await window.showTextDocument(doc);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return await workspace.applyEdit(workspaceEdit, {
|
||||||
|
isRefactoring: true
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== CANCELLED) {
|
||||||
|
window.showErrorMessage(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user