From fc6cb72d800604b680b2b324cb7f38c507e03708 Mon Sep 17 00:00:00 2001 From: ti-ji <1250079251@qq.com> Date: Thu, 24 Mar 2022 13:25:00 +0800 Subject: [PATCH 1/3] Support for setting shell environment variables --- package.json | 13 ++++++++- src/lib/app-integrator-factory.ts | 18 ++++++++++++- src/lib/app-integrator.ts | 5 ++++ src/lib/command-reader.ts | 2 +- src/lib/history-store.ts | 4 +-- src/lib/local-command-store.ts | 42 ++++++++++++++++++++++++++++++ src/lib/shell-command-service.ts | 26 +++++++++++++++++- src/lib/shell-settings-resolver.ts | 10 +++++++ 8 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/lib/local-command-store.ts diff --git a/package.json b/package.json index 4dc4f7c..8873eac 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "edit-with-shell", "displayName": "Edit with Shell Command", "description": "Leverage your favourite shell commands to edit text", - "version": "1.3.0", + "version": "1.3.1", "publisher": "ryu1kn", "license": "SEE LICENSE IN LICENSE.txt", "icon": "images/edit-with-shell.png", @@ -28,6 +28,7 @@ "activationEvents": [ "onCommand:editWithShell.clearCommandHistory", "onCommand:editWithShell.runCommand", + "onCommand:editWithShell.runLocalCommand", "onCommand:editWithShell.runQuickCommand1", "onCommand:editWithShell.runQuickCommand2", "onCommand:editWithShell.runQuickCommand3", @@ -47,6 +48,11 @@ "title": "Run command", "category": "EditWithShell" }, + { + "command": "editWithShell.runLocalCommand", + "title": "Run local command", + "category": "EditWithShell" + }, { "command": "editWithShell.runQuickCommand1", "title": "Run quick command 1", @@ -177,6 +183,11 @@ "/s", "/c" ] + }, + "editWithShell.shellEnv": { + "description": "shell environment variables", + "type": "object", + "default": {} } } } diff --git a/src/lib/app-integrator-factory.ts b/src/lib/app-integrator-factory.ts index bd7816d..8d4093e 100644 --- a/src/lib/app-integrator-factory.ts +++ b/src/lib/app-integrator-factory.ts @@ -3,6 +3,7 @@ import {Editor} from './adapters/editor'; import {ShellCommandService} from './shell-command-service'; import {CommandReader} from './command-reader'; import {HistoryStore} from './history-store'; +import {LocalCommandStore} from './local-command-store'; import {ProcessRunner} from './process-runner'; import {RunInputCommand} from './commands/run-input'; import {ClearHistoryCommand} from './commands/clear-history'; @@ -19,6 +20,7 @@ export class AppIntegratorFactory { private readonly cache: { workspaceAdapter?: WorkspaceAdapter; historyStore?: HistoryStore; + localCommandStore?: LocalCommandStore; }; constructor() { @@ -26,7 +28,7 @@ export class AppIntegratorFactory { } create() { - return new AppIntegrator(this.runCommand, this.clearHistoryCommand, this.createQuickCommand, vscode); + return new AppIntegrator(this.runCommand,this.runLocalCommand, this.clearHistoryCommand, this.createQuickCommand, vscode); } private get runCommand() { @@ -38,6 +40,15 @@ export class AppIntegratorFactory { )); } + private get runLocalCommand() { + return this.wrapCommand(new RunInputCommand( + this.shellCommandService, + new CommandReader(this.localCommandStore, vscode.window), + this.localCommandStore, // Actually no need to store local commands + this.workspaceAdapter + )); + } + private get createQuickCommand() { return (commandNumber: number) => this.wrapCommand(new RunQuickCommand( this.shellCommandService, @@ -65,6 +76,11 @@ export class AppIntegratorFactory { return this.cache.historyStore; } + private get localCommandStore() { + this.cache.localCommandStore = this.cache.localCommandStore || new LocalCommandStore(this.workspaceAdapter); + return this.cache.localCommandStore; + } + private get shellCommandService() { return new ShellCommandService( new ProcessRunner(), diff --git a/src/lib/app-integrator.ts b/src/lib/app-integrator.ts index e4b0159..85399ab 100644 --- a/src/lib/app-integrator.ts +++ b/src/lib/app-integrator.ts @@ -9,6 +9,7 @@ interface CommandHandlerInfo { export class AppIntegrator { constructor(private readonly runCommand: CommandWrap, + private readonly runLocalCommand: CommandWrap, private readonly clearHistoryCommand: CommandWrap, private readonly createQuickCommand: (n: number) => CommandWrap, private readonly vscode: any) {} @@ -44,6 +45,10 @@ export class AppIntegrator { id: `${EXTENSION_NAME}.runCommand`, command: this.runCommand }, + { + id: `${EXTENSION_NAME}.runLocalCommand`, + command: this.runLocalCommand + }, ...[1, 2, 3, 4, 5].map(n => ({ id: `${EXTENSION_NAME}.runQuickCommand${n}`, command: this.createQuickCommand(n) diff --git a/src/lib/command-reader.ts b/src/lib/command-reader.ts index 46a9b9c..790cc4a 100644 --- a/src/lib/command-reader.ts +++ b/src/lib/command-reader.ts @@ -6,7 +6,7 @@ export class CommandReader { private readonly vsWindow: typeof vscode.window) {} async read() { - const history = this.historyStore.getAll(); + const history = await this.historyStore.getAll(); if (history.length === 0) { return this.vsWindow.showInputBox({ placeHolder: 'Enter a command', diff --git a/src/lib/history-store.ts b/src/lib/history-store.ts index 86caa55..081127e 100644 --- a/src/lib/history-store.ts +++ b/src/lib/history-store.ts @@ -1,12 +1,12 @@ export class HistoryStore { - private history: string[]; + protected history: string[]; constructor() { this.history = []; } - getAll() { + async getAll() { return this.history; } diff --git a/src/lib/local-command-store.ts b/src/lib/local-command-store.ts new file mode 100644 index 0000000..e0f8322 --- /dev/null +++ b/src/lib/local-command-store.ts @@ -0,0 +1,42 @@ +import { HistoryStore } from "./history-store"; + +import {ShellSettingsResolver} from './shell-settings-resolver'; +import {Workspace as WorkspaceAdapter} from './adapters/workspace'; +import * as fs from 'fs'; +import * as vscode from 'vscode'; +import * as Path from 'path'; + +export class LocalCommandStore extends HistoryStore { + private readonly shellSettingsResolver: ShellSettingsResolver; + // private readonly workspace: WorkspaceAdapter; + + constructor(workspace : WorkspaceAdapter) { + super(); + // this.workspace = workspace; + this.shellSettingsResolver = new ShellSettingsResolver(workspace, process.platform); + } + + async getAll() { + return new Promise(require=>{ + + const shellEnv = this.shellSettingsResolver.shellEnv(); + const pathSeparator = this.shellSettingsResolver.pathSeparator(); + + const workdir = vscode.workspace.workspaceFolders ? vscode.workspace.getWorkspaceFolder(vscode.workspace.workspaceFolders[0].uri)?.uri?.fsPath || "": "" + + let envpath = shellEnv.PATH || shellEnv.Path; + if(envpath) { + let paths = envpath.split(pathSeparator); + for(let path of paths){ + let files = fs.readdirSync(Path.join(workdir, path)); + files.forEach((file) => { + this.add(file); + }); + + } + } + + require(this.history) + }); + } +} diff --git a/src/lib/shell-command-service.ts b/src/lib/shell-command-service.ts index ecd4c3c..c73bd68 100644 --- a/src/lib/shell-command-service.ts +++ b/src/lib/shell-command-service.ts @@ -4,6 +4,7 @@ import {ShellSettingsResolver} from './shell-settings-resolver'; import {ChildProcess, SpawnOptions} from 'child_process'; import {Workspace} from './adapters/workspace'; import Process = NodeJS.Process; +import { ObjectMap } from './types/collection'; export interface SpawnWrapper { spawn: (command: string, args?: ReadonlyArray, options?: SpawnOptions) => ChildProcess; @@ -31,6 +32,29 @@ export class ShellCommandService { const options = this.getOptions(params); const shell = this.shellSettingsResolver.shellProgramme(); const shellArgs = this.shellSettingsResolver.shellArgs(); + // Why Proxy Object? + const shellEnv = this.shellSettingsResolver.shellEnv(); + const pathSeparator = this.shellSettingsResolver.pathSeparator(); + + // Can't delete member + // delete shellEnv.Path + + const env_path = shellEnv.Path; + const env:ObjectMap = {}; + + // skip env:Path + for (let key in shellEnv){ + if(key.toUpperCase() != "PATH"){ + env[key] = shellEnv[key] + } + } + + Object.assign(options.env, env) + + if(env_path) { + options.env.Path = env_path + pathSeparator + options.env.Path + } + const command = this.childProcess.spawn(shell, [...shellArgs, params.command], options); return this.processRunner.run(command, params.input); } @@ -41,7 +65,7 @@ export class ShellCommandService { env: { ...this.shellCommandExecContext.env, ES_SELECTED: params.input - } + } as ObjectMap }; } } diff --git a/src/lib/shell-settings-resolver.ts b/src/lib/shell-settings-resolver.ts index bbd5cce..e3b4f01 100644 --- a/src/lib/shell-settings-resolver.ts +++ b/src/lib/shell-settings-resolver.ts @@ -1,6 +1,8 @@ import {EXTENSION_NAME} from './const'; import resolveOsKind from './resolve-os-kind'; import {Workspace} from './adapters/workspace'; +import { ObjectMap } from './types/collection'; +import * as path from 'path'; export class ShellSettingsResolver { constructor(private readonly workspaceAdapter: Workspace, @@ -14,6 +16,14 @@ export class ShellSettingsResolver { return this.workspaceAdapter.getConfig(`${EXTENSION_NAME}.shellArgs.${this.osKind}`); } + shellEnv(): ObjectMap { + return this.workspaceAdapter.getConfig>(`${EXTENSION_NAME}.shellEnv`); + } + + pathSeparator(): string { + return path.delimiter; + } + private get osKind() { return resolveOsKind(this.platform); } From dc7bb2eb8dfaf51c14b2bc3766eda1c749b99717 Mon Sep 17 00:00:00 2001 From: ti-ji <1250079251@qq.com> Date: Thu, 24 Mar 2022 22:17:55 +0800 Subject: [PATCH 2/3] Environment variable "PATH" compatible processing --- src/lib/shell-command-service.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lib/shell-command-service.ts b/src/lib/shell-command-service.ts index c73bd68..4bfa959 100644 --- a/src/lib/shell-command-service.ts +++ b/src/lib/shell-command-service.ts @@ -35,12 +35,16 @@ export class ShellCommandService { // Why Proxy Object? const shellEnv = this.shellSettingsResolver.shellEnv(); const pathSeparator = this.shellSettingsResolver.pathSeparator(); + const system_env_path = options.env.Path || options.env.PATH; + const env_path = shellEnv.Path || shellEnv.PATH; + const env:ObjectMap = {}; + // linux&win use 'PATH' + options.env.PATH = options.env.Path; + delete options.env.Path; // Can't delete member // delete shellEnv.Path - - const env_path = shellEnv.Path; - const env:ObjectMap = {}; + // delete shellEnv.PATH // skip env:Path for (let key in shellEnv){ @@ -52,7 +56,7 @@ export class ShellCommandService { Object.assign(options.env, env) if(env_path) { - options.env.Path = env_path + pathSeparator + options.env.Path + options.env.PATH = env_path + pathSeparator + system_env_path; } const command = this.childProcess.spawn(shell, [...shellArgs, params.command], options); From c3c861be64e34dbdfa667c90f898c051e5c93fbc Mon Sep 17 00:00:00 2001 From: ti-ji <1250079251@qq.com> Date: Fri, 25 Mar 2022 09:14:11 +0800 Subject: [PATCH 3/3] Environment variable "PATH" compatible processing --- src/lib/shell-command-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/shell-command-service.ts b/src/lib/shell-command-service.ts index 4bfa959..ee0c976 100644 --- a/src/lib/shell-command-service.ts +++ b/src/lib/shell-command-service.ts @@ -40,7 +40,7 @@ export class ShellCommandService { const env:ObjectMap = {}; // linux&win use 'PATH' - options.env.PATH = options.env.Path; + options.env.PATH = system_env_path; delete options.env.Path; // Can't delete member // delete shellEnv.Path