From 8e76788fc0632f5fe0c46e94a148bb80a66026fa Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 15:53:31 -0800 Subject: [PATCH 01/10] Create command for copying jack-in command to clipboard - WIP --- package.json | 5 ++ src/extension.ts | 3 +- src/nrepl/jack-in-terminal.ts | 9 ++- src/nrepl/jack-in.ts | 147 ++++++++++++++++++++++++++++------ 4 files changed, 138 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 2332a6d47..5ab6cdff0 100644 --- a/package.json +++ b/package.json @@ -606,6 +606,11 @@ } ], "commands": [ + { + "command": "calva.copyJackInCommandToClipboard", + "title": "Copy Jack-In Command to Clipboard", + "category": "Calva" + }, { "command": "calva.openCalvaDocs", "title": "Open Documentation (calva.io)", diff --git a/src/extension.ts b/src/extension.ts index 25b9487ba..cae9c466b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -132,7 +132,8 @@ async function activate(context: vscode.ExtensionContext) { // COMMANDS context.subscriptions.push(vscode.commands.registerCommand('calva.jackInOrConnect', jackIn.calvaJackInOrConnect)); - context.subscriptions.push(vscode.commands.registerCommand('calva.jackIn', jackIn.calvaJackIn)) + context.subscriptions.push(vscode.commands.registerCommand('calva.jackIn', jackIn.calvaJackIn)); + context.subscriptions.push(vscode.commands.registerCommand('calva.copyJackInCommandToClipboard', jackIn.copyJackInCommandToClipboard)); context.subscriptions.push(vscode.commands.registerCommand('calva.connectNonProjectREPL', connector.connectNonProjectREPLCommand)); context.subscriptions.push(vscode.commands.registerCommand('calva.connect', connector.connectCommand)); context.subscriptions.push(vscode.commands.registerCommand('calva.disconnect', jackIn.calvaDisconnect)); diff --git a/src/nrepl/jack-in-terminal.ts b/src/nrepl/jack-in-terminal.ts index 97fa106a8..26788a591 100644 --- a/src/nrepl/jack-in-terminal.ts +++ b/src/nrepl/jack-in-terminal.ts @@ -12,6 +12,10 @@ export interface JackInTerminalOptions extends vscode.TerminalOptions { isWin: boolean }; +export function createTerminalCommand(executable: string, args: string[]) { + return `${executable} ${args.join(' ')}`; +} + export class JackInTerminal implements vscode.Pseudoterminal { private writeEmitter = new vscode.EventEmitter(); onDidWrite: vscode.Event = this.writeEmitter.event; @@ -53,8 +57,9 @@ export class JackInTerminal implements vscode.Pseudoterminal { } private async startClojureProgram(): Promise { - return new Promise((resolve) => { - this.writeEmitter.fire(`${this.options.executable} ${this.options.args.join(' ')}\r\n`); + return new Promise(() => { + const data = `${createTerminalCommand(this.options.executable, this.options.args)}\r\n`; + this.writeEmitter.fire(data); if (this.process && !this.process.killed) { console.log("Restarting Jack-in process"); this.killProcess(); diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 9c3074624..1384586b4 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -8,7 +8,7 @@ import statusbar from "../statusbar"; import { askForConnectSequence, ReplConnectSequence, CljsTypes } from "./connectSequence"; import * as projectTypes from './project-types'; import * as outputWindow from '../results-output/results-doc'; -import { JackInTerminal, JackInTerminalOptions } from "./jack-in-terminal"; +import { JackInTerminal, JackInTerminalOptions, createTerminalCommand } from "./jack-in-terminal"; import * as namespace from "../namespace"; import * as liveShareSupport from '../liveShareSupport'; @@ -30,21 +30,16 @@ function resolveEnvVariables(entry: any): any { } } -async function executeJackInTask(projectType: projectTypes.ProjectType, projectTypeSelection: any, executable: string, args: any, isWin: boolean, cljTypes: string[], connectSequence: ReplConnectSequence) { - utilities.setLaunchingState(projectTypeSelection); - statusbar.update(); - const jackInEnv = _.mapValues(state.config().jackInEnv as object, resolveEnvVariables); - const env = Object.assign(process.env, jackInEnv) as { - [key: string]: any; - }; - const terminalOptions: JackInTerminalOptions = { - name: `Calva Jack-in: ${connectSequence.name}`, - executable, - args, - env, - isWin, - cwd: state.getProjectRootLocal(), +function getJackInEnv(): any { + return { + ...process.env, + ..._.mapValues(state.config().jackInEnv as object, resolveEnvVariables) }; +} + +async function executeJackInTask(terminalOptions: JackInTerminalOptions, connectSequence: ReplConnectSequence) { + utilities.setLaunchingState(connectSequence.name); + statusbar.update(); // in case we have a running task present try to end it. calvaJackout(); @@ -53,7 +48,8 @@ async function executeJackInTask(projectType: projectTypes.ProjectType, projectT jackInTerminal = undefined; } - state.analytics().logEvent("REPL", "JackInExecuting", JSON.stringify(cljTypes)).send(); + // TODO: Move this out to call site + //state.analytics().logEvent("REPL", "JackInExecuting", JSON.stringify(cljTypes)).send(); try { jackInPTY = new JackInTerminal(terminalOptions, async (_p, hostname: string, port: string) => { @@ -81,6 +77,57 @@ async function executeJackInTask(projectType: projectTypes.ProjectType, projectT } } +// async function executeJackInTask(executable: string, args: any, isWin: boolean, cljTypes: string[], connectSequence: ReplConnectSequence) { +// utilities.setLaunchingState(connectSequence.name); +// statusbar.update(); +// const jackInEnv = _.mapValues(state.config().jackInEnv as object, resolveEnvVariables); +// const env = Object.assign(process.env, jackInEnv) as { +// [key: string]: any; +// }; +// const terminalOptions: JackInTerminalOptions = { +// name: `Calva Jack-in: ${connectSequence.name}`, +// executable, +// args, +// env, +// isWin, +// cwd: state.getProjectRootLocal(), +// }; + +// // in case we have a running task present try to end it. +// calvaJackout(); +// if (jackInTerminal !== undefined) { +// jackInTerminal.dispose(); +// jackInTerminal = undefined; +// } + +// state.analytics().logEvent("REPL", "JackInExecuting", JSON.stringify(cljTypes)).send(); + +// try { +// jackInPTY = new JackInTerminal(terminalOptions, async (_p, hostname: string, port: string) => { +// // Create a watcher to wait for the nREPL port file to appear with new content, and connect + open the repl window at that point. +// utilities.setLaunchingState(null); +// await connector.connect(connectSequence, true, hostname, port); +// outputWindow.append("; Jack-in done."); +// outputWindow.appendPrompt(); +// }, (errorMessage) => { +// outputWindow.append("; Error in Jack-in: unable to read port file"); +// outputWindow.append(`; ${errorMessage}`); +// outputWindow.append("; You may have chosen the wrong jack-in configuration for your project."); +// vscode.window.showErrorMessage("Error in Jack-in: unable to read port file. See output window for more information."); +// cancelJackInTask(); +// }); +// jackInTerminal = (vscode.window).createTerminal({ name: `Calva Jack-in: ${connectSequence.name}`, pty: jackInPTY }); +// if (state.config().autoOpenJackInTerminal) { +// jackInTerminal.show(); +// } +// jackInPTY.onDidClose((e) => { +// calvaJackout(); +// }); +// } catch (exception) { +// console.error("Failed executing task: ", exception.message); +// } +// } + export function calvaJackout() { if (jackInPTY != undefined) { if (projectTypes.isWin) { @@ -108,6 +155,53 @@ export function calvaJackout() { liveShareSupport.didJackOut(); } +function getJackInExecutable(projectReplConnectSequence: ReplConnectSequence): string { + const projectTypeName: string = projectReplConnectSequence.projectType; + let selectedCljsType: CljsTypes; + + if (typeof projectReplConnectSequence.cljsType === "string" && projectReplConnectSequence.cljsType !== CljsTypes.none) { + selectedCljsType = projectReplConnectSequence.cljsType; + } else if (projectReplConnectSequence.cljsType && typeof projectReplConnectSequence.cljsType === "object") { + selectedCljsType = projectReplConnectSequence.cljsType.dependsOn; + } + + const projectType = projectTypes.getProjectTypeForName(projectTypeName); + const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; + return executable; +} + +export async function copyJackInCommandToClipboard(): Promise { + try { + await state.initProjectDir(); + } catch (e) { + console.error("An error occurred while initializing project directory.", e); + return; + } + const cljTypes: string[] = await projectTypes.detectProjectTypes(); + if (cljTypes.length > 1) { + const projectConnectSequence: ReplConnectSequence = await askForConnectSequence(cljTypes.filter(t => t !== 'generic'), 'jack-in-type', "JackInInterrupted"); + + if (projectConnectSequence && projectConnectSequence.projectType !== 'generic') { + const projectTypeName: string = projectConnectSequence.projectType; + let selectedCljsType: CljsTypes; + + if (typeof projectConnectSequence.cljsType == "string" && projectConnectSequence.cljsType != CljsTypes.none) { + selectedCljsType = projectConnectSequence.cljsType; + } else if (projectConnectSequence.cljsType && typeof projectConnectSequence.cljsType == "object") { + selectedCljsType = projectConnectSequence.cljsType.dependsOn; + } + + const projectType = projectTypes.getProjectTypeForName(projectTypeName); + const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; + // Ask the project type to build up the command line. This may prompt for further information. + const args = await projectType.commandLine(projectConnectSequence, selectedCljsType); + vscode.env.clipboard.writeText(createTerminalCommand(executable, args)); + } + } else { // Only 'generic' type left + vscode.window.showInformationMessage('No supported Jack-in project types detected.'); + } +} + export async function calvaJackIn() { try { await state.initProjectDir(); @@ -128,7 +222,7 @@ export async function calvaJackIn() { state.analytics().logEvent("REPL", "JackInInitiated").send(); await outputWindow.initResultsDoc(); outputWindow.append("; Jacking in..."); - const outputDocument = await outputWindow.openResultsDoc(); + await outputWindow.openResultsDoc(); const cljTypes: string[] = await projectTypes.detectProjectTypes(); if (cljTypes.length > 1) { @@ -149,13 +243,20 @@ export async function calvaJackIn() { selectedCljsType = projectConnectSequence.cljsType.dependsOn; } - let projectType = projectTypes.getProjectTypeForName(projectTypeName); - let executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; + const projectType = projectTypes.getProjectTypeForName(projectTypeName); + const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; // Ask the project type to build up the command line. This may prompt for further information. - let args = await projectType.commandLine(projectConnectSequence, selectedCljsType); + const args = await projectType.commandLine(projectConnectSequence, selectedCljsType); - executeJackInTask(projectType, projectConnectSequence.name, executable, args, projectTypes.isWin, cljTypes, projectConnectSequence) - .then(() => { }, () => { }); + const terminalOptions: JackInTerminalOptions = { + name: `Calva Jack-in: ${projectConnectSequence.name}`, + executable, + args, + env: getJackInEnv(), + isWin: projectTypes.isWin, + cwd: state.getProjectRootLocal(), + }; + executeJackInTask(terminalOptions, projectConnectSequence); } else { outputWindow.append("; There is no Jack-in possible for this project type."); } @@ -205,7 +306,7 @@ export async function calvaJackInOrConnect() { commands["Connect to a running REPL server, not in your project"] = "calva.connectNonProjectREPL"; } else { commands["Disconnect from the REPL server"] = "calva.disconnect"; - if(namespace.getSession("clj")) { + if (namespace.getSession("clj")) { commands["Open the Output Window"] = "calva.showOutputWindow"; } } From 8ea321e55bd53ec85c7bf4c530a3e619ef42ba20 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 16:23:00 -0800 Subject: [PATCH 02/10] Add getJackInTerminalOptions function --- src/nrepl/jack-in.ts | 50 +++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 1384586b4..9b0788e9f 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -155,21 +155,6 @@ export function calvaJackout() { liveShareSupport.didJackOut(); } -function getJackInExecutable(projectReplConnectSequence: ReplConnectSequence): string { - const projectTypeName: string = projectReplConnectSequence.projectType; - let selectedCljsType: CljsTypes; - - if (typeof projectReplConnectSequence.cljsType === "string" && projectReplConnectSequence.cljsType !== CljsTypes.none) { - selectedCljsType = projectReplConnectSequence.cljsType; - } else if (projectReplConnectSequence.cljsType && typeof projectReplConnectSequence.cljsType === "object") { - selectedCljsType = projectReplConnectSequence.cljsType.dependsOn; - } - - const projectType = projectTypes.getProjectTypeForName(projectTypeName); - const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; - return executable; -} - export async function copyJackInCommandToClipboard(): Promise { try { await state.initProjectDir(); @@ -202,6 +187,41 @@ export async function copyJackInCommandToClipboard(): Promise { } } +async function getJackInTerminalOptions(projectConnectSequence: ReplConnectSequence) { + try { + await state.initProjectDir(); + } catch (e) { + console.error("An error occurred while initializing project directory.", e); + return; + } + + if (projectConnectSequence.projectType !== 'generic') { + const projectTypeName: string = projectConnectSequence.projectType; + let selectedCljsType: CljsTypes; + + if (typeof projectConnectSequence.cljsType == "string" && projectConnectSequence.cljsType != CljsTypes.none) { + selectedCljsType = projectConnectSequence.cljsType; + } else if (projectConnectSequence.cljsType && typeof projectConnectSequence.cljsType == "object") { + selectedCljsType = projectConnectSequence.cljsType.dependsOn; + } + + const projectType = projectTypes.getProjectTypeForName(projectTypeName); + const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; + // Ask the project type to build up the command line. This may prompt for further information. + const args = await projectType.commandLine(projectConnectSequence, selectedCljsType); + + const terminalOptions: JackInTerminalOptions = { + name: `Calva Jack-in: ${projectConnectSequence.name}`, + executable, + args, + env: getJackInEnv(), + isWin: projectTypes.isWin, + cwd: state.getProjectRootLocal(), + }; + return terminalOptions; + } +} + export async function calvaJackIn() { try { await state.initProjectDir(); From f9342fafac2587de9b85c2969f3cef56f26a5018 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 16:51:32 -0800 Subject: [PATCH 03/10] Refactor. Update changelog. Close #992 --- CHANGELOG.md | 1 + src/nrepl/jack-in.ts | 139 ++++++------------------------------------- 2 files changed, 20 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a93c66de8..673389e7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Changes to Calva. ## [Unreleased] +- [Add command for copying jack-in command to clipboard](https://github.com/BetterThanTomorrow/calva/pull/995) ## [2.0.156] - 2021-01-28 - Fix: [Debug instrumentation decoration not working correctly anymore on Windows](https://github.com/BetterThanTomorrow/calva/issues/969) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 9b0788e9f..562379cff 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -48,9 +48,6 @@ async function executeJackInTask(terminalOptions: JackInTerminalOptions, connect jackInTerminal = undefined; } - // TODO: Move this out to call site - //state.analytics().logEvent("REPL", "JackInExecuting", JSON.stringify(cljTypes)).send(); - try { jackInPTY = new JackInTerminal(terminalOptions, async (_p, hostname: string, port: string) => { // Create a watcher to wait for the nREPL port file to appear with new content, and connect + open the repl window at that point. @@ -77,57 +74,6 @@ async function executeJackInTask(terminalOptions: JackInTerminalOptions, connect } } -// async function executeJackInTask(executable: string, args: any, isWin: boolean, cljTypes: string[], connectSequence: ReplConnectSequence) { -// utilities.setLaunchingState(connectSequence.name); -// statusbar.update(); -// const jackInEnv = _.mapValues(state.config().jackInEnv as object, resolveEnvVariables); -// const env = Object.assign(process.env, jackInEnv) as { -// [key: string]: any; -// }; -// const terminalOptions: JackInTerminalOptions = { -// name: `Calva Jack-in: ${connectSequence.name}`, -// executable, -// args, -// env, -// isWin, -// cwd: state.getProjectRootLocal(), -// }; - -// // in case we have a running task present try to end it. -// calvaJackout(); -// if (jackInTerminal !== undefined) { -// jackInTerminal.dispose(); -// jackInTerminal = undefined; -// } - -// state.analytics().logEvent("REPL", "JackInExecuting", JSON.stringify(cljTypes)).send(); - -// try { -// jackInPTY = new JackInTerminal(terminalOptions, async (_p, hostname: string, port: string) => { -// // Create a watcher to wait for the nREPL port file to appear with new content, and connect + open the repl window at that point. -// utilities.setLaunchingState(null); -// await connector.connect(connectSequence, true, hostname, port); -// outputWindow.append("; Jack-in done."); -// outputWindow.appendPrompt(); -// }, (errorMessage) => { -// outputWindow.append("; Error in Jack-in: unable to read port file"); -// outputWindow.append(`; ${errorMessage}`); -// outputWindow.append("; You may have chosen the wrong jack-in configuration for your project."); -// vscode.window.showErrorMessage("Error in Jack-in: unable to read port file. See output window for more information."); -// cancelJackInTask(); -// }); -// jackInTerminal = (vscode.window).createTerminal({ name: `Calva Jack-in: ${connectSequence.name}`, pty: jackInPTY }); -// if (state.config().autoOpenJackInTerminal) { -// jackInTerminal.show(); -// } -// jackInPTY.onDidClose((e) => { -// calvaJackout(); -// }); -// } catch (exception) { -// console.error("Failed executing task: ", exception.message); -// } -// } - export function calvaJackout() { if (jackInPTY != undefined) { if (projectTypes.isWin) { @@ -162,39 +108,16 @@ export async function copyJackInCommandToClipboard(): Promise { console.error("An error occurred while initializing project directory.", e); return; } - const cljTypes: string[] = await projectTypes.detectProjectTypes(); - if (cljTypes.length > 1) { - const projectConnectSequence: ReplConnectSequence = await askForConnectSequence(cljTypes.filter(t => t !== 'generic'), 'jack-in-type', "JackInInterrupted"); - - if (projectConnectSequence && projectConnectSequence.projectType !== 'generic') { - const projectTypeName: string = projectConnectSequence.projectType; - let selectedCljsType: CljsTypes; - - if (typeof projectConnectSequence.cljsType == "string" && projectConnectSequence.cljsType != CljsTypes.none) { - selectedCljsType = projectConnectSequence.cljsType; - } else if (projectConnectSequence.cljsType && typeof projectConnectSequence.cljsType == "object") { - selectedCljsType = projectConnectSequence.cljsType.dependsOn; - } - - const projectType = projectTypes.getProjectTypeForName(projectTypeName); - const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; - // Ask the project type to build up the command line. This may prompt for further information. - const args = await projectType.commandLine(projectConnectSequence, selectedCljsType); + const projectConnectSequence = await getProjectConnectSequence(); + if (projectConnectSequence) { + const { executable, args } = await getJackInTerminalOptions(projectConnectSequence); + if (executable && args) { vscode.env.clipboard.writeText(createTerminalCommand(executable, args)); } - } else { // Only 'generic' type left - vscode.window.showInformationMessage('No supported Jack-in project types detected.'); } } -async function getJackInTerminalOptions(projectConnectSequence: ReplConnectSequence) { - try { - await state.initProjectDir(); - } catch (e) { - console.error("An error occurred while initializing project directory.", e); - return; - } - +async function getJackInTerminalOptions(projectConnectSequence: ReplConnectSequence): Promise { if (projectConnectSequence.projectType !== 'generic') { const projectTypeName: string = projectConnectSequence.projectType; let selectedCljsType: CljsTypes; @@ -222,6 +145,15 @@ async function getJackInTerminalOptions(projectConnectSequence: ReplConnectSeque } } +async function getProjectConnectSequence(): Promise { + const cljTypes: string[] = await projectTypes.detectProjectTypes(); + if (cljTypes.length > 1) { + return askForConnectSequence(cljTypes.filter(t => t !== 'generic'), 'jack-in-type', "JackInInterrupted"); + } else { // Only 'generic' type left + vscode.window.showInformationMessage('No supported Jack-in project types detected.') + } +} + export async function calvaJackIn() { try { await state.initProjectDir(); @@ -244,45 +176,12 @@ export async function calvaJackIn() { outputWindow.append("; Jacking in..."); await outputWindow.openResultsDoc(); - const cljTypes: string[] = await projectTypes.detectProjectTypes(); - if (cljTypes.length > 1) { - const projectConnectSequence: ReplConnectSequence = await askForConnectSequence(cljTypes.filter(t => t !== 'generic'), 'jack-in-type', "JackInInterrupted"); - - if (!projectConnectSequence) { - state.analytics().logEvent("REPL", "JackInInterrupted", "NoProjectTypeForBuildName").send(); - outputWindow.append("; Aborting Jack-in, since no project type was selected."); - return; - } - if (projectConnectSequence.projectType !== 'generic') { - const projectTypeName: string = projectConnectSequence.projectType; - let selectedCljsType: CljsTypes; - - if (typeof projectConnectSequence.cljsType == "string" && projectConnectSequence.cljsType != CljsTypes.none) { - selectedCljsType = projectConnectSequence.cljsType; - } else if (projectConnectSequence.cljsType && typeof projectConnectSequence.cljsType == "object") { - selectedCljsType = projectConnectSequence.cljsType.dependsOn; - } - - const projectType = projectTypes.getProjectTypeForName(projectTypeName); - const executable = projectTypes.isWin ? projectType.winCmd : projectType.cmd; - // Ask the project type to build up the command line. This may prompt for further information. - const args = await projectType.commandLine(projectConnectSequence, selectedCljsType); - - const terminalOptions: JackInTerminalOptions = { - name: `Calva Jack-in: ${projectConnectSequence.name}`, - executable, - args, - env: getJackInEnv(), - isWin: projectTypes.isWin, - cwd: state.getProjectRootLocal(), - }; - executeJackInTask(terminalOptions, projectConnectSequence); - } else { - outputWindow.append("; There is no Jack-in possible for this project type."); + const projectConnectSequence = await getProjectConnectSequence(); + if (projectConnectSequence) { + const terminalJackInOptions = await getJackInTerminalOptions(projectConnectSequence); + if (terminalJackInOptions) { + executeJackInTask(terminalJackInOptions, projectConnectSequence); } - } else { // Only 'generic' type left - outputWindow.append("; No Jack-in possible."); - vscode.window.showInformationMessage('No supported Jack-in project types detected. Maybe try starting your project manually and use the Connect command?') } liveShareSupport.didJackIn(); From 3901e668ce2ff906d2d92359a219dc704a6c7885 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 17:06:29 -0800 Subject: [PATCH 04/10] Add more error handling and logging --- src/nrepl/jack-in.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 562379cff..79e0cb6fa 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -148,7 +148,12 @@ async function getJackInTerminalOptions(projectConnectSequence: ReplConnectSeque async function getProjectConnectSequence(): Promise { const cljTypes: string[] = await projectTypes.detectProjectTypes(); if (cljTypes.length > 1) { - return askForConnectSequence(cljTypes.filter(t => t !== 'generic'), 'jack-in-type', "JackInInterrupted"); + const connectSequence = await askForConnectSequence(cljTypes.filter(t => t !== 'generic'), 'jack-in-type', "JackInInterrupted"); + if (connectSequence) { + return connectSequence; + } else { + return Promise.reject(); + } } else { // Only 'generic' type left vscode.window.showInformationMessage('No supported Jack-in project types detected.') } @@ -169,19 +174,28 @@ export async function calvaJackIn() { if (state.getProjectRootUri().scheme === "vsls") { outputWindow.append("; Aborting Jack-in, since you're the guest of a live share session."); outputWindow.append("; Please use this command instead: Connect to a running REPL server in the project."); - return + return; } state.analytics().logEvent("REPL", "JackInInitiated").send(); await outputWindow.initResultsDoc(); outputWindow.append("; Jacking in..."); await outputWindow.openResultsDoc(); - const projectConnectSequence = await getProjectConnectSequence(); + let projectConnectSequence: ReplConnectSequence; + try { + projectConnectSequence = await getProjectConnectSequence(); + } catch (e) { + outputWindow.append('; Aborting jack-in. No project type selected.'); + return; + } if (projectConnectSequence) { const terminalJackInOptions = await getJackInTerminalOptions(projectConnectSequence); if (terminalJackInOptions) { executeJackInTask(terminalJackInOptions, projectConnectSequence); } + } else { + outputWindow.append('; No supported project types detected.'); + return; } liveShareSupport.didJackIn(); From 3c371241952968f5b5ce8840c2048bbd7cd1b7c5 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 17:09:37 -0800 Subject: [PATCH 05/10] Add message to say command was copied to clipboard --- src/nrepl/jack-in.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 79e0cb6fa..965c70ef9 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -113,6 +113,7 @@ export async function copyJackInCommandToClipboard(): Promise { const { executable, args } = await getJackInTerminalOptions(projectConnectSequence); if (executable && args) { vscode.env.clipboard.writeText(createTerminalCommand(executable, args)); + vscode.window.showInformationMessage("Jack-in command copied to the clipboard."); } } } From c7f47387c2eec78d940cc3ccd34058e6cb8b6242 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 17:15:51 -0800 Subject: [PATCH 06/10] Handle if user doesn't select project type when copying jack-in command to clipboard --- src/nrepl/jack-in.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 965c70ef9..6b68e7ae9 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -108,7 +108,12 @@ export async function copyJackInCommandToClipboard(): Promise { console.error("An error occurred while initializing project directory.", e); return; } - const projectConnectSequence = await getProjectConnectSequence(); + let projectConnectSequence: ReplConnectSequence; + try { + projectConnectSequence = await getProjectConnectSequence(); + } catch (e) { + return; + } if (projectConnectSequence) { const { executable, args } = await getJackInTerminalOptions(projectConnectSequence); if (executable && args) { @@ -156,7 +161,7 @@ async function getProjectConnectSequence(): Promise { return Promise.reject(); } } else { // Only 'generic' type left - vscode.window.showInformationMessage('No supported Jack-in project types detected.') + vscode.window.showInformationMessage('No supported Jack-in project types detected.'); } } From 9f83c793a7b6da8158ca07827301c2d509572f36 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 17:18:58 -0800 Subject: [PATCH 07/10] Add back note about connect command --- src/nrepl/jack-in.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 6b68e7ae9..f1f5c3107 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -200,7 +200,7 @@ export async function calvaJackIn() { executeJackInTask(terminalJackInOptions, projectConnectSequence); } } else { - outputWindow.append('; No supported project types detected.'); + outputWindow.append('; No supported project types detected. Maybe try starting your project manually and use the Connect command?'); return; } From c2f224da441164464678146650a9cfc01456c234 Mon Sep 17 00:00:00 2001 From: Brandon Ringe Date: Fri, 29 Jan 2021 17:23:24 -0800 Subject: [PATCH 08/10] Improve messaging to user when no project types detected --- src/nrepl/jack-in.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index f1f5c3107..96bc357b5 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -105,7 +105,7 @@ export async function copyJackInCommandToClipboard(): Promise { try { await state.initProjectDir(); } catch (e) { - console.error("An error occurred while initializing project directory.", e); + console.error('An error occurred while initializing project directory.', e); return; } let projectConnectSequence: ReplConnectSequence; @@ -118,8 +118,10 @@ export async function copyJackInCommandToClipboard(): Promise { const { executable, args } = await getJackInTerminalOptions(projectConnectSequence); if (executable && args) { vscode.env.clipboard.writeText(createTerminalCommand(executable, args)); - vscode.window.showInformationMessage("Jack-in command copied to the clipboard."); + vscode.window.showInformationMessage('Jack-in command copied to the clipboard.'); } + } else { + vscode.window.showInformationMessage('No supported project types detected.'); } } @@ -160,8 +162,6 @@ async function getProjectConnectSequence(): Promise { } else { return Promise.reject(); } - } else { // Only 'generic' type left - vscode.window.showInformationMessage('No supported Jack-in project types detected.'); } } @@ -200,7 +200,7 @@ export async function calvaJackIn() { executeJackInTask(terminalJackInOptions, projectConnectSequence); } } else { - outputWindow.append('; No supported project types detected. Maybe try starting your project manually and use the Connect command?'); + vscode.window.showInformationMessage('No supported project types detected. Maybe try starting your project manually and use the Connect command?'); return; } From 0a9332caf1a0b3fe4854886b01d0c3aedaca96df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Str=C3=B6mberg?= Date: Sat, 30 Jan 2021 13:00:27 +0100 Subject: [PATCH 09/10] Remove confusing comment about file watcher --- src/nrepl/jack-in.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 96bc357b5..8abf5505d 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -50,7 +50,6 @@ async function executeJackInTask(terminalOptions: JackInTerminalOptions, connect try { jackInPTY = new JackInTerminal(terminalOptions, async (_p, hostname: string, port: string) => { - // Create a watcher to wait for the nREPL port file to appear with new content, and connect + open the repl window at that point. utilities.setLaunchingState(null); await connector.connect(connectSequence, true, hostname, port); outputWindow.append("; Jack-in done."); From 8a1093624029f0eac0093e7c6a80ea9a62f7d228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Str=C3=B6mberg?= Date: Sat, 30 Jan 2021 13:01:46 +0100 Subject: [PATCH 10/10] Rename command-line creating function --- src/nrepl/jack-in-terminal.ts | 6 +++--- src/nrepl/jack-in.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nrepl/jack-in-terminal.ts b/src/nrepl/jack-in-terminal.ts index 26788a591..f693449ad 100644 --- a/src/nrepl/jack-in-terminal.ts +++ b/src/nrepl/jack-in-terminal.ts @@ -12,7 +12,7 @@ export interface JackInTerminalOptions extends vscode.TerminalOptions { isWin: boolean }; -export function createTerminalCommand(executable: string, args: string[]) { +export function createCommandLine(executable: string, args: string[]) { return `${executable} ${args.join(' ')}`; } @@ -29,7 +29,7 @@ export class JackInTerminal implements vscode.Pseudoterminal { private whenError: (errorMessage: string) => void) {} open(initialDimensions: vscode.TerminalDimensions | undefined): void { - outputWindow.append(`; Starting Jack-in Terminal: ${this.options.executable} ${this.options.args.join(' ')}`); + outputWindow.append(`; Starting Jack-in Terminal: ${createCommandLine(this.options.executable, this.options.args)}`); this.startClojureProgram(); } @@ -58,7 +58,7 @@ export class JackInTerminal implements vscode.Pseudoterminal { private async startClojureProgram(): Promise { return new Promise(() => { - const data = `${createTerminalCommand(this.options.executable, this.options.args)}\r\n`; + const data = `${createCommandLine(this.options.executable, this.options.args)}\r\n`; this.writeEmitter.fire(data); if (this.process && !this.process.killed) { console.log("Restarting Jack-in process"); diff --git a/src/nrepl/jack-in.ts b/src/nrepl/jack-in.ts index 8abf5505d..5aa49caf0 100644 --- a/src/nrepl/jack-in.ts +++ b/src/nrepl/jack-in.ts @@ -8,7 +8,7 @@ import statusbar from "../statusbar"; import { askForConnectSequence, ReplConnectSequence, CljsTypes } from "./connectSequence"; import * as projectTypes from './project-types'; import * as outputWindow from '../results-output/results-doc'; -import { JackInTerminal, JackInTerminalOptions, createTerminalCommand } from "./jack-in-terminal"; +import { JackInTerminal, JackInTerminalOptions, createCommandLine } from "./jack-in-terminal"; import * as namespace from "../namespace"; import * as liveShareSupport from '../liveShareSupport'; @@ -116,7 +116,7 @@ export async function copyJackInCommandToClipboard(): Promise { if (projectConnectSequence) { const { executable, args } = await getJackInTerminalOptions(projectConnectSequence); if (executable && args) { - vscode.env.clipboard.writeText(createTerminalCommand(executable, args)); + vscode.env.clipboard.writeText(createCommandLine(executable, args)); vscode.window.showInformationMessage('Jack-in command copied to the clipboard.'); } } else {