Skip to content

Commit 3939251

Browse files
committed
Improve shell command formatting
Consolidates shell command formatting logic into a shared utility function that is used for running in terminal and PET command execution, among other places
1 parent ef67c74 commit 3939251

File tree

4 files changed

+19
-24
lines changed

4 files changed

+19
-24
lines changed

src/extension.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from './common/window.apis';
2020
import { getConfiguration } from './common/workspace.apis';
2121
import { createManagerReady } from './features/common/managerReady';
22+
import { identifyTerminalShell } from './features/common/shellDetector';
2223
import { AutoFindProjects } from './features/creators/autoFindProjects';
2324
import { ExistingProjects } from './features/creators/existingProjects';
2425
import { NewPackageProject } from './features/creators/newPackageProject';
@@ -49,7 +50,7 @@ import { PythonProjectManagerImpl } from './features/projectManager';
4950
import { getPythonApi, setPythonApi } from './features/pythonApi';
5051
import { registerCompletionProvider } from './features/settings/settingCompletions';
5152
import { setActivateMenuButtonContext } from './features/terminal/activateMenuButton';
52-
import { normalizeShellPath } from './features/terminal/shells/common/shellUtils';
53+
import { getShellCommandAsString, normalizeShellPath } from './features/terminal/shells/common/shellUtils';
5354
import {
5455
clearShellProfileCache,
5556
createShellEnvProviders,
@@ -435,6 +436,7 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
435436
commands.registerCommand('python-envs.runPetInTerminal', async () => {
436437
try {
437438
const petPath = await getNativePythonToolsPath();
439+
let command: { subcommand: string; args?: string[] } | undefined;
438440

439441
// Show quick pick menu for PET operation selection
440442
const selectedOption = await window.showQuickPick(
@@ -467,8 +469,7 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
467469

468470
if (selectedOption.label === 'Find All Environments') {
469471
// Run pet find --verbose
470-
terminal.sendText(`"${petPath}" find --verbose`, true);
471-
traceInfo(`Running PET find command: ${petPath} find --verbose`);
472+
command = { subcommand: 'find', args: ['--verbose'] };
472473
} else if (selectedOption.label === 'Resolve Environment...') {
473474
// Show input box for path
474475
const placeholder = isWindows() ? 'C:\\path\\to\\python\\executable' : '/path/to/python/executable';
@@ -489,8 +490,15 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
489490
}
490491

491492
// Run pet resolve with the provided path
492-
terminal.sendText(`"${petPath}" resolve "${inputPath.trim()}"`, true);
493-
traceInfo(`Running PET resolve command: ${petPath} resolve "${inputPath.trim()}"`);
493+
command = { subcommand: 'resolve', args: [inputPath.trim()] };
494+
}
495+
496+
if (command) {
497+
const execString = getShellCommandAsString(identifyTerminalShell(terminal), [
498+
{ executable: petPath, args: [command.subcommand, ...(command.args || [])] },
499+
]);
500+
terminal.sendText(execString, true);
501+
traceInfo(`Running PET ${command.subcommand} command: ${execString}`);
494502
}
495503
} catch (error) {
496504
traceError('Error running PET in terminal', error);

src/features/execution/execUtils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export function quoteStringIfNecessary(arg: string): string {
2+
arg = arg.trim();
23
if (arg.indexOf(' ') >= 0 && !(arg.startsWith('"') && arg.endsWith('"'))) {
34
return `"${arg}"`;
45
}

src/features/terminal/runInTerminal.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import { Terminal, TerminalShellExecution } from 'vscode';
22
import { PythonEnvironment, PythonTerminalExecutionOptions } from '../../api';
33
import { createDeferred } from '../../common/utils/deferred';
44
import { onDidEndTerminalShellExecution } from '../../common/window.apis';
5-
import { ShellConstants } from '../common/shellConstants';
65
import { identifyTerminalShell } from '../common/shellDetector';
7-
import { quoteArgs } from '../execution/execUtils';
6+
import { getShellCommandAsString } from './shells/common/shellUtils';
87

98
export async function runInTerminal(
109
environment: PythonEnvironment,
@@ -29,25 +28,11 @@ export async function runInTerminal(
2928
}
3029
});
3130

32-
const shouldSurroundWithQuotes =
33-
executable.includes(' ') && !executable.startsWith('"') && !executable.endsWith('"');
34-
// Handle case where executable contains white-spaces.
35-
if (shouldSurroundWithQuotes) {
36-
executable = `"${executable}"`;
37-
}
38-
39-
if (shellType === ShellConstants.PWSH && !executable.startsWith('&')) {
40-
// PowerShell requires commands to be prefixed with '&' to run them.
41-
executable = `& ${executable}`;
42-
}
31+
executable = getShellCommandAsString(shellType, [{ executable }]);
4332
execution = terminal.shellIntegration.executeCommand(executable, allArgs);
4433
await deferred.promise;
4534
} else {
46-
let text = quoteArgs([executable, ...allArgs]).join(' ');
47-
if (shellType === ShellConstants.PWSH && !text.startsWith('&')) {
48-
// PowerShell requires commands to be prefixed with '&' to run them.
49-
text = `& ${text}`;
50-
}
35+
const text = getShellCommandAsString(shellType, [{ executable, args: allArgs }]);
5136
terminal.sendText(`${text}\n`);
5237
}
5338
}

src/features/terminal/shells/common/shellUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { ShellConstants } from '../../../common/shellConstants';
66
import { quoteArgs } from '../../../execution/execUtils';
77

88
function getCommandAsString(command: PythonCommandRunConfiguration[], shell: string, delimiter: string): string {
9-
const parts = [];
9+
let parts = [];
1010
for (const cmd of command) {
1111
const args = cmd.args ?? [];
1212
parts.push(quoteArgs([normalizeShellPath(cmd.executable, shell), ...args]).join(' '));
1313
}
1414
if (shell === ShellConstants.PWSH) {
15+
parts = parts.map((p) => (p.startsWith('"') ? p : `& ${p}`));
1516
if (parts.length === 1) {
1617
return parts[0];
1718
}

0 commit comments

Comments
 (0)