-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
228 additions
and
43 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
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 @@ | ||
export const EXTENSION_NAME = 'vscode-just'; |
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,26 @@ | ||
import { spawn } from 'child_process'; | ||
import * as vscode from 'vscode'; | ||
|
||
import { EXTENSION_NAME } from './const'; | ||
import { LOGGER } from './extension'; | ||
|
||
export const formatWithExecutable = (fsPath: string) => { | ||
const justPath = | ||
(vscode.workspace.getConfiguration(EXTENSION_NAME).get('justPath') as string) || | ||
'just'; | ||
const args = ['-f', fsPath, '--fmt', '--unstable']; | ||
|
||
const childProcess = spawn(justPath, args); | ||
childProcess.stdout.on('data', (data: string) => { | ||
LOGGER.info(data); | ||
}); | ||
childProcess.stderr.on('data', (data: string) => { | ||
// TODO: successfully formatted documents also log to stderr | ||
// so treat everything as info for now | ||
LOGGER.info(data); | ||
// showErrorWithLink('Error formatting document.'); | ||
}); | ||
childProcess.on('close', (code) => { | ||
console.debug(`just --fmt exited with ${code}`); | ||
}); | ||
}; |
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,120 @@ | ||
import { exec, spawn } from 'child_process'; | ||
import { promisify } from 'util'; | ||
import * as vscode from 'vscode'; | ||
import yargsParser from 'yargs-parser'; | ||
|
||
import { EXTENSION_NAME } from './const'; | ||
import { LOGGER } from './extension'; | ||
import { RecipeParameterKind, RecipeParsed, RecipeResponse } from './types'; | ||
import { workspaceRoot } from './utils'; | ||
|
||
const asyncExec = promisify(exec); | ||
|
||
export const runRecipeCommand = async () => { | ||
const recipes = await getRecipes(); | ||
if (!recipes.length) return; | ||
|
||
const choices: vscode.QuickPickItem[] = recipes | ||
.map((r) => ({ | ||
label: r.name, | ||
description: r.doc, | ||
detail: r.groups.length ? `Groups: ${r.groups.sort().join(', ')}` : '', | ||
})) | ||
.sort((a, b) => a.label.localeCompare(b.label)); | ||
|
||
const recipeToRun = await vscode.window.showQuickPick(choices, { | ||
placeHolder: 'Select a recipe to run', | ||
}); | ||
if (!recipeToRun) return; | ||
|
||
const recipe = recipes.find((r) => r.name === recipeToRun?.label); | ||
if (!recipe) { | ||
const errorMsg = 'Failed to find recipe'; | ||
vscode.window.showErrorMessage(errorMsg); | ||
LOGGER.error(errorMsg); | ||
return; | ||
} | ||
|
||
let args: string | undefined = ''; | ||
if (recipe.parameters.length) { | ||
args = await vscode.window.showInputBox({ | ||
placeHolder: `Enter arguments: ${paramsToString(recipe.parameters)}`, | ||
}); | ||
} | ||
|
||
if (args === undefined) return; | ||
runRecipe(recipe, yargsParser(args)); | ||
}; | ||
|
||
const getRecipes = async (): Promise<RecipeParsed[]> => { | ||
const justPath = | ||
(vscode.workspace.getConfiguration(EXTENSION_NAME).get('justPath') as string) || | ||
'just'; | ||
|
||
const cmd = `${justPath} --dump --dump-format=json`; | ||
try { | ||
const { stdout, stderr } = await asyncExec(cmd, { cwd: workspaceRoot() ?? '~' }); | ||
|
||
if (stderr) { | ||
vscode.window.showErrorMessage('Failed to fetch recipes.'); | ||
LOGGER.error(stderr); | ||
return []; | ||
} | ||
|
||
return parseRecipes(stdout); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
vscode.window.showErrorMessage('Failed to fetch recipes.'); | ||
LOGGER.error(error.message); | ||
} else { | ||
vscode.window.showErrorMessage('Failed to fetch recipes.'); | ||
LOGGER.error('An unknown error occurred.'); | ||
} | ||
|
||
return []; | ||
} | ||
}; | ||
|
||
const parseRecipes = (output: string): RecipeParsed[] => { | ||
return (Object.values(JSON.parse(output).recipes) as RecipeResponse[]) | ||
.filter((r) => !r.private && !r.attributes.some((attr) => attr === 'private')) | ||
.map((r) => ({ | ||
name: r.name, | ||
doc: r.doc, | ||
parameters: r.parameters, | ||
groups: r.attributes | ||
.filter((attr) => typeof attr === 'object' && attr.group) | ||
.map((attr) => (attr as Record<string, string>).group), | ||
})); | ||
}; | ||
|
||
const paramsToString = (params: RecipeParsed['parameters']): string => { | ||
return params | ||
.sort((a, b) => | ||
a.kind === RecipeParameterKind.PLUS ? 1 : a.name.localeCompare(b.name), | ||
) | ||
.map((p) => { | ||
let formatted = `${p.kind === RecipeParameterKind.PLUS ? '+' : ''}${p.name}`; | ||
if (p.default != null) formatted += `=${p.default}`; | ||
return formatted; | ||
}) | ||
.join(' '); | ||
}; | ||
|
||
const runRecipe = async (recipe: RecipeParsed, optionalArgs: yargsParser.Arguments) => { | ||
const justPath = | ||
(vscode.workspace.getConfiguration(EXTENSION_NAME).get('justPath') as string) || | ||
'just'; | ||
const args = [recipe.name, ...optionalArgs._.map((arg) => arg.toString())]; | ||
|
||
const childProcess = spawn(justPath, args, { cwd: workspaceRoot() ?? '~' }); | ||
childProcess.stdout.on('data', (data: string) => { | ||
LOGGER.info(data); | ||
}); | ||
childProcess.stderr.on('data', (data: string) => { | ||
// TODO: successfully run recipes also log to stderr | ||
// so treat everything as info for now | ||
LOGGER.info(data); | ||
// showErrorWithLink('Error running recipe.'); | ||
}); | ||
}; |
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,27 @@ | ||
export enum RecipeParameterKind { | ||
SINGULAR = 'singular', | ||
PLUS = 'plus', | ||
} | ||
|
||
export interface RecipeParameter { | ||
default: string; | ||
kind: RecipeParameterKind; | ||
name: string; | ||
[key: string]: unknown; | ||
} | ||
|
||
export interface RecipeResponse { | ||
name: string; | ||
doc: string; | ||
parameters: RecipeParameter[]; | ||
attributes: (Record<string, string> | string)[]; | ||
private: boolean; | ||
[key: string]: unknown; | ||
} | ||
|
||
export interface RecipeParsed { | ||
name: string; | ||
doc: string; | ||
parameters: Pick<RecipeParameter, 'default' | 'kind' | 'name'>[]; | ||
groups: string[]; | ||
} |
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,17 @@ | ||
import * as vscode from 'vscode'; | ||
|
||
import { LOGGER } from './extension'; | ||
|
||
export const showErrorWithLink = (message: string) => { | ||
const outputButton = 'Output'; | ||
vscode.window | ||
.showErrorMessage(message, outputButton) | ||
.then((selection) => selection === outputButton && LOGGER.show()); | ||
}; | ||
|
||
export const workspaceRoot = (): string | null => { | ||
const workspaceFolders = vscode.workspace.workspaceFolders; | ||
return workspaceFolders && workspaceFolders.length > 0 | ||
? workspaceFolders[0].uri.fsPath | ||
: null; | ||
}; |
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 |
---|---|---|
|
@@ -310,6 +310,11 @@ | |
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.93.0.tgz#1cd7573e0272aef9c357bafc635b6177c154013e" | ||
integrity sha512-kUK6jAHSR5zY8ps42xuW89NLcBpw1kOabah7yv38J8MyiYuOHxLQBi0e7zeXbQgVefDy/mZZetqEFC+Fl5eIEQ== | ||
|
||
"@types/yargs-parser@^21.0.3": | ||
version "21.0.3" | ||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" | ||
integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== | ||
|
||
"@typescript-eslint/[email protected]": | ||
version "7.18.0" | ||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" | ||
|