Skip to content

Commit

Permalink
feat: 🎸 simplify external terminal logic
Browse files Browse the repository at this point in the history
  • Loading branch information
danielpinto8zz6 committed Feb 15, 2023
1 parent c78bda2 commit 0cdd2d4
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 94 deletions.
86 changes: 86 additions & 0 deletions src/external-terminal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { exec } from "child_process";
import { lookpath } from "lookpath";
import { Configuration } from "./configuration";
import { ShellType } from "./enums/shell-type";
import { Notification } from "./notification";
import { terminal } from "./terminal";
import { getPath } from "./utils/shell-utils";
import { escapeStringAppleScript, isStringNullOrWhiteSpace } from "./utils/string-utils";

class ExternalTerminal {
public async runInExternalTerminal(command: string, cwd: string, shell: ShellType) {
const parsedOutputLocation = await getPath(cwd, shell);

const externalCommand = await this.getExternalCommand(command, parsedOutputLocation, shell);
if (isStringNullOrWhiteSpace(externalCommand)) {
return;
}

exec(externalCommand, { cwd: cwd });
}

private async getExternalCommand(runCommand: string, outputLocation: string, shell: ShellType): Promise<string> {
switch (process.platform) {
case "win32":
switch (shell) {
case ShellType.powerShell:
return `start ${terminal} -Command "cd ${outputLocation};${runCommand};Write-Host;Write-Host -NoNewLine 'Press any key to continue...';$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');"`;
default:
return `start cmd /c "cd ${outputLocation} & ${runCommand} & echo. & pause"`;
}

case "darwin":
const osxTerminal: string = Configuration.osxTerminal();
switch (osxTerminal) {
case "iTerm.app":
return "osascript -e 'tell application \"iTerm\"' "
+ "-e 'set newWindow to (create window with default profile)' "
+ "-e 'tell current session of newWindow' "
+ `-e 'write text "cd ${outputLocation}"' `
+ `-e 'write text "${escapeStringAppleScript(runCommand)}"' `
+ "-e 'end tell' "
+ "-e 'end tell' ";
default:
return `osascript -e 'do shell script "open -a Terminal " & "${outputLocation}"' -e 'delay 0.3' -e `
+ `'tell application "Terminal" to do script ("${escapeStringAppleScript(runCommand)}") in first window'`;
}

case "linux":
const linuxTerminal: string = Configuration.linuxTerminal();

if (isStringNullOrWhiteSpace(linuxTerminal)
|| isStringNullOrWhiteSpace(await lookpath(linuxTerminal))) {
Notification.showErrorMessage(`${terminal} not found! Try to enter a valid terminal in 'terminal.external.linuxExec' `
+ "settings!(gnome - terminal, xterm, konsole)");

return null;
}

switch (linuxTerminal) {
case "xterm":
return `${linuxTerminal} -T 'C/C++ Compile Run' -e '${runCommand}; echo; read -n1 -p \"Press any key to continue...\"'`;
case "gnome-terminal":
case "tilix":
case "mate-terminal":
return `${linuxTerminal} -t 'C/C++ Compile Run' -x bash -c '${runCommand}; echo; read -n1 -p \"Press any key to continue...\"'`;
case "xfce4-terminal":
return `${linuxTerminal} --title 'C/C++ Compile Run' -x bash -c '${runCommand}; echo; read -n1 -p \"Press any key to continue...\"'`;
case "konsole":
return `${linuxTerminal} -p tabtitle='C/C++ Compile Run' --noclose -e bash -c '${runCommand}; echo;'`;
case "io.elementary.terminal":
return `${linuxTerminal} -n -w '${outputLocation}' -x '${runCommand}'`;
default:
Notification.showErrorMessage(`${linuxTerminal} isn't supported! Try to enter a supported terminal in `
+ "'terminal.external.linuxExec' settings! (gnome-terminal, xterm, konsole)");

return null;
}
default:
Notification.showErrorMessage("Unsupported platform!");

return null;
}
}
}

export const externalTerminal: ExternalTerminal = new ExternalTerminal();
85 changes: 8 additions & 77 deletions src/runner.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { exec } from "child_process";
import { existsSync } from "fs";
import { lookpath } from "lookpath";
import { Configuration } from "./configuration";
import { ShellType } from "./enums/shell-type";
import { File } from "./models/file";
import { Notification } from "./notification";
import { terminal } from "./terminal";
import { promptRunArguments } from "./utils/prompt-utils";
import { currentWindowsShell, getPath, getRunPrefix, parseShell } from "./utils/shell-utils";
import { escapeStringAppleScript, isStringNullOrWhiteSpace } from "./utils/string-utils";
import { currentShell, getPath, getRunPrefix, parseShell } from "./utils/shell-utils";
import { isStringNullOrWhiteSpace } from "./utils/string-utils";
import path = require("path");
import { basename, extname } from "path";
import { basename } from "path";
import { externalTerminal } from "./external-terminal";

export class Runner {
private file: File;
Expand Down Expand Up @@ -42,88 +42,19 @@ export class Runner {

const shell = this.getShell(shouldRunInExternalTerminal);

const parsedOutputLocation = await getPath(outputLocation, shell);
const parsedExecutable = await getPath(this.file.executable, shell);

const runCommand = this.buildRunCommand(parsedExecutable, args, customPrefix, shell);
const runCommand = this.getRunCommand(parsedExecutable, args, customPrefix, shell);

if (shouldRunInExternalTerminal) {
const command = await this.getExternalCommand(runCommand, parsedOutputLocation, shell);
if (isStringNullOrWhiteSpace(command)) {
return;
}

exec(command, { cwd: outputLocation });
await externalTerminal.runInExternalTerminal(runCommand, outputLocation, shell);
}
else {
await terminal.runInTerminal(runCommand, { name: "C/C++ Compile Run", cwd: outputLocation });
}
}

private async getExternalCommand(runCommand: string, outputLocation: string, shell: ShellType): Promise<string> {
switch (process.platform) {
case "win32":
switch (shell) {
case ShellType.powerShell:
return `start ${terminal} -Command "cd ${outputLocation};${runCommand};Write-Host;Write-Host -NoNewLine 'Press any key to continue...';$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');"`;
default:
return `start cmd /c "cd ${outputLocation} & ${runCommand} & echo. & pause"`;
}

case "darwin":
const osxTerminal: string = Configuration.osxTerminal();
switch (osxTerminal) {
case "iTerm.app":
return "osascript -e 'tell application \"iTerm\"' "
+ "-e 'set newWindow to (create window with default profile)' "
+ "-e 'tell current session of newWindow' "
+ `-e 'write text "cd ${outputLocation}"' `
+ `-e 'write text "${escapeStringAppleScript(runCommand)}"' `
+ "-e 'end tell' "
+ "-e 'end tell' ";
default:
return `osascript -e 'do shell script "open -a Terminal " & "${outputLocation}"' -e 'delay 0.3' -e `
+ `'tell application "Terminal" to do script ("${escapeStringAppleScript(runCommand)}") in first window'`;
}

case "linux":
const linuxTerminal: string = Configuration.linuxTerminal();

if (isStringNullOrWhiteSpace(linuxTerminal)
|| isStringNullOrWhiteSpace(await lookpath(linuxTerminal))) {
Notification.showErrorMessage(`${terminal} not found! Try to enter a valid terminal in 'terminal.external.linuxExec' `
+ "settings!(gnome - terminal, xterm, konsole)");

return null;
}

switch (linuxTerminal) {
case "xterm":
return `${linuxTerminal} -T '${this.file.title}' -e '${runCommand}; echo; read -n1 -p \"Press any key to continue...\"'`;
case "gnome-terminal":
case "tilix":
case "mate-terminal":
return `${linuxTerminal} -t '${this.file.title}' -x bash -c '${runCommand}; echo; read -n1 -p \"Press any key to continue...\"'`;
case "xfce4-terminal":
return `${linuxTerminal} --title '${this.file.title}' -x bash -c '${runCommand}; echo; read -n1 -p \"Press any key to continue...\"'`;
case "konsole":
return `${linuxTerminal} -p tabtitle='${this.file.title}' --noclose -e bash -c '${runCommand}; echo;'`;
case "io.elementary.terminal":
return `${linuxTerminal} -n -w '${outputLocation}' -x '${runCommand}'`;
default:
Notification.showErrorMessage(`${linuxTerminal} isn't supported! Try to enter a supported terminal in `
+ "'terminal.external.linuxExec' settings! (gnome-terminal, xterm, konsole)");

return null;
}
default:
Notification.showErrorMessage("Unsupported platform!");

return null;
}
}

buildRunCommand(executable: string, args: string, customPrefix: string, shell: ShellType) {
getRunCommand(executable: string, args: string, customPrefix: string, shell: ShellType) {
const prefix = getRunPrefix(shell);

if (customPrefix) {
Expand All @@ -143,7 +74,7 @@ export class Runner {
return ShellType.others;
}
} else {
return currentWindowsShell();
return currentShell();
}
}
}
Expand Down
13 changes: 4 additions & 9 deletions src/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

import * as vscode from "vscode";
import { ShellType } from "./enums/shell-type";
import { executeCommand } from "./utils/cp-utils";
import { currentWindowsShell, getCDCommand, getCommand } from "./utils/shell-utils";
import { currentShell, getCDCommand, getCommand } from "./utils/shell-utils";

export interface ITerminalOptions {
addNewLine?: boolean;
Expand All @@ -28,15 +27,15 @@ class Terminal implements vscode.Disposable {
this.terminals[name] = vscode.window.createTerminal({ name, env, cwd: terminalCwd });
// Workaround for WSL custom envs.
// See: https://github.com/Microsoft/vscode/issues/71267
if (currentWindowsShell() === ShellType.wsl) {
if (currentShell() === ShellType.wsl) {
setupEnvForWSL(this.terminals[name], env);
}
}
this.terminals[name].show();
if (cwd) {
this.terminals[name].sendText(await getCDCommand(cwd, currentWindowsShell()), true);
this.terminals[name].sendText(await getCDCommand(cwd, currentShell()), true);
}
this.terminals[name].sendText(getCommand(command, currentWindowsShell()), addNewLine);
this.terminals[name].sendText(getCommand(command, currentShell()), addNewLine);
return this.terminals[name];
}

Expand All @@ -53,10 +52,6 @@ class Terminal implements vscode.Disposable {
}
}

export async function toWinPath(filepath: string): Promise<string> {
return (await executeCommand("wsl", ["wslpath", "-w", `"${filepath}"`])).trim();
}

export const terminal: Terminal = new Terminal();

function setupEnvForWSL(term: vscode.Terminal, env: { [envKey: string]: string }): void {
Expand Down
14 changes: 6 additions & 8 deletions src/utils/shell-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ShellType } from "../enums/shell-type";
import { outputChannel } from "../output-channel";
import { executeCommand } from "./cp-utils";

export function parseShell(executable: string) : ShellType {
export function parseShell(executable: string): ShellType {
switch (executable.toLowerCase()) {
case "cmd.exe":
return ShellType.cmd;
Expand Down Expand Up @@ -88,17 +88,15 @@ function toDefaultWslPath(p: string): string {
}

export function getRunPrefix(shell: ShellType): string {
if (process.platform === "win32") {
if (shell === ShellType.cmd || shell === ShellType.powerShell) {
return ".\\";
}
if (shell === ShellType.cmd || shell === ShellType.powerShell) {
return ".\\";
}

return "./";
}

export function currentWindowsShell(): ShellType {
const currentWindowsShellPath: string = env.shell;
const executable: string = path.basename(currentWindowsShellPath);
export function currentShell(): ShellType {
const currentShellPath: string = env.shell;
const executable: string = path.basename(currentShellPath);
return parseShell(executable);
}

0 comments on commit 0cdd2d4

Please sign in to comment.