Skip to content

Commit

Permalink
Merge pull request #704 from BetterThanTomorrow/699-ouput-window-over…
Browse files Browse the repository at this point in the history
…write

Create the output repl file more reliably
  • Loading branch information
PEZ authored Jul 29, 2020
2 parents d472b80 + dffc8c5 commit 021ad36
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 87 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Changes to Calva.

## [Unreleased]
- [Handling ansi code by stripping it](https://github.com/BetterThanTomorrow/calva/issues/696)
- Fix [Repl connection fails if afterCLJJackInCode errors](https://github.com/BetterThanTomorrow/calva/issues/703)
- Fix: [Output window sometimes getting out of synch, needing overwrite](https://github.com/BetterThanTomorrow/calva/issues/699)
- Fix: [The *Calva says* panel + output window opening at startup gets a bit too much](https://github.com/BetterThanTomorrow/calva/issues/702)
- Fix: [Repl connection fails if afterCLJJackInCode errors](https://github.com/BetterThanTomorrow/calva/issues/703)

## [2.0.110] - 2020-07-28
- [Fix Connect Fails on Windows](https://github.com/BetterThanTomorrow/calva/issues/694)
Expand Down
94 changes: 41 additions & 53 deletions src/connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ async function createAndConnectReplWindow(session: NReplSession, mode: "clj" | "
async function connectToHost(hostname, port, connectSequence: ReplConnectSequence) {
state.analytics().logEvent("REPL", "Connecting").send();

let chan = state.outputChannel();
if (nClient) {
nClient["silent"] = true;
nClient.close();
Expand All @@ -44,32 +43,32 @@ async function connectToHost(hostname, port, connectSequence: ReplConnectSequenc
util.setConnectingState(true);
status.update();
try {
chan.appendLine("Hooking up nREPL sessions...");
resultsOutput.appendToResultsDoc("; Hooking up nREPL sessions...");
// Create an nREPL client. waiting for the connection to be established.
nClient = await NReplClient.create({ host: hostname, port: +port })
nClient.addOnCloseHandler(c => {
util.setConnectedState(false);
util.setConnectingState(false);
if (!c["silent"]) // we didn't deliberately close this session, mention this fact.
chan.appendLine("nREPL Connection was closed");
resultsOutput.appendToResultsDoc("; nREPL Connection was closed");
status.update();
})
cljSession = nClient.session;
cljSession.replType = 'clj';
chan.appendLine("Connected session: clj");
util.setConnectingState(false);
util.setConnectedState(true);
state.analytics().logEvent("REPL", "ConnectedCLJ").send();
state.cursor.set('clj', cljSession);
state.cursor.set('cljc', cljSession);
status.update();
const outputDocument = await resultsOutput.openResultsDoc(true);
const outputDocument = await resultsOutput.openResultsDoc();
resultsOutput.appendToResultsDoc(`; Connected session: clj\n${resultsOutput.CLJ_CONNECT_GREETINGS}`);
resultsOutput.setSession(cljSession, nClient.ns);
util.updateREPLSessionType();

// Initialize debugger
await initializeDebugger(cljSession);
chan.appendLine('Debugger initialized');
resultsOutput.appendToResultsDoc('; Debugger initialized');

await createAndConnectReplWindow(cljSession, "clj");

Expand All @@ -86,7 +85,7 @@ async function connectToHost(hostname, port, connectSequence: ReplConnectSequenc
});
}
catch (e) {
chan.appendLine("Evaluation of afterCLJReplJackInCode failed. See the output window.")
resultsOutput.appendToResultsDoc("; Evaluation of afterCLJReplJackInCode failed.")
}
}

Expand All @@ -102,41 +101,39 @@ async function connectToHost(hostname, port, connectSequence: ReplConnectSequenc
state.analytics().logEvent("REPL", "ConnectCljsRepl", isBuiltinType ? connectSequence.cljsType as string : "Custom").send();
}
if (cljsSession) {
await setUpCljsRepl(cljsSession, chan, cljsBuild);
await setUpCljsRepl(cljsSession, cljsBuild);
}
chan.appendLine('cljc files will use the clj REPL.' + (cljsSession ? ' (You can toggle this at will.)' : ''));
} catch (e) {
chan.appendLine("Error while connecting cljs REPL: " + e);
resultsOutput.appendToResultsDoc("; Error while connecting cljs REPL: " + e);
}
status.update();
} catch (e) {
util.setConnectingState(false);
util.setConnectedState(false);
chan.appendLine("Failed connecting.");
resultsOutput.appendToResultsDoc("; Failed connecting.");
state.analytics().logEvent("REPL", "FailedConnectingCLJ").send();
return false;
}

return true;
}

async function setUpCljsRepl(session, chan, build) {
async function setUpCljsRepl(session, build) {
state.cursor.set("cljs", session);
status.update();
chan.appendLine("Connected session: cljs" + (build ? ", repl: " + build : ""));
resultsOutput.appendToResultsDoc(`; Connected session: cljs${(build ? ", repl: " + build : "")}\n${resultsOutput.CLJS_CONNECT_GREETINGS}`);
resultsOutput.setSession(session, 'cljs.user');
util.updateREPLSessionType();
createAndConnectReplWindow(session, "cljs");
}

function getFigwheelMainBuilds() {
let chan = state.outputChannel();
let res = fs.readdirSync(state.getProjectRoot());
let builds = res.filter(x => x.match(/\.cljs\.edn/)).map(x => x.replace(/\.cljs\.edn$/, ""));
if (builds.length == 0) {
vscode.window.showErrorMessage("There are no figwheel build files (.cljs.edn) in the project directory.");
chan.appendLine("There are no figwheel build files (.cljs.edn) in the project directory.");
chan.appendLine("Connection to Figwheel Main aborted.");
resultsOutput.appendToResultsDoc("; There are no figwheel build files (.cljs.edn) in the project directory.");
resultsOutput.appendToResultsDoc("; Connection to Figwheel Main aborted.");
throw "Aborted";
}
return builds;
Expand Down Expand Up @@ -225,14 +222,13 @@ function createCLJSReplType(cljsType: CljsTypeConfig, cljsTypeName: string, conn
hasStarted = cljsType.isStarted,
useDefaultBuild = true,
startedBuilds: string[];
const chan = state.outputChannel(),
// The output processors are used to keep the user informed about the connection process
// The output from Figwheel is meant for printing to the REPL prompt,
// and since we print to Calva says we, only print some of the messages.
printThisPrinter: processOutputFn = x => {
const printThisPrinter: processOutputFn = x => {
if (cljsType.printThisLineRegExp) {
if (x.search(cljsType.printThisLineRegExp) >= 0) {
chan.appendLine(x.replace(/\s*$/, ""));
resultsOutput.appendToResultsDoc('; ' + x.replace(/\s*$/, ""));
}
}
},
Expand All @@ -252,32 +248,32 @@ function createCLJSReplType(cljsType: CljsTypeConfig, cljsTypeName: string, conn
// When the app is ready to start, say so.
if (!haveShownStartMessage && cljsType.isReadyToStartRegExp) {
if (x.search(cljsType.isReadyToStartRegExp) >= 0) {
chan.appendLine("CLJS REPL ready to connect. Please, start your ClojureScript app.");
resultsOutput.appendToResultsDoc("; CLJS REPL ready to connect. Please, start your ClojureScript app.");
haveShownStartMessage = true;
}
}
// If we have an appURL to go with the ”start now” message, say so
if (appURL && haveShownStartMessage && !haveShownAppURL) {
if (cljsType.shouldOpenUrl) {
chan.appendLine(` Opening ClojureScript app in the browser at: ${appURL} ...`);
resultsOutput.appendToResultsDoc(`; Opening ClojureScript app in the browser at: ${appURL} ...`);
open(appURL).catch(reason => {
chan.appendLine("Error opening ClojureScript app in the browser: " + reason);
resultsOutput.appendToResultsDoc("; Error opening ClojureScript app in the browser: " + reason);
});
} else {
chan.appendLine(" Open the app on this URL: " + appURL);
resultsOutput.appendToResultsDoc("; Open the app on this URL: " + appURL);
}
haveShownAppURL = true;
}
// Wait for any appURL to be printed before we round of the ”start now” message.
// (If we do not have the regexp for extracting the appURL, do not wait for appURL.)
if (!haveShownStartSuffix && (haveShownAppURL || (haveShownStartMessage && !cljsType.openUrlRegExp))) {
chan.appendLine(" The CLJS REPL will connect when your app is running.");
resultsOutput.appendToResultsDoc("; The CLJS REPL will connect when your app is running.");
haveShownStartSuffix = true;
}
},
// This processor prints everything. We use it for stderr below.
allPrinter: processOutputFn = x => {
chan.appendLine(util.stripAnsi(x).replace(/\s*$/, ""));
resultsOutput.appendToResultsDoc('; ' + util.stripAnsi(x).replace(/\s*$/, ""));
}

let replType: ReplType = {
Expand Down Expand Up @@ -346,7 +342,7 @@ function createCLJSReplType(cljsType: CljsTypeConfig, cljsTypeName: string, conn
});
}
if (builds) {
chan.appendLine("Starting cljs repl for: " + projectTypeName + "...");
resultsOutput.appendToResultsDoc("; Starting cljs repl for: " + projectTypeName + "...");
state.extensionContext.workspaceState.update('cljsReplTypeHasBuilds', true);
startCode = startCode.replace("%BUILDS%", builds.map(x => { return `"${x}"` }).join(" "));
const result = evalConnectCode(session, startCode, name, checkFn, [startAppNowProcessor, printThisPrinter], [allPrinter]);
Expand All @@ -355,11 +351,11 @@ function createCLJSReplType(cljsType: CljsTypeConfig, cljsTypeName: string, conn
}
return result;
} else {
chan.appendLine("Aborted starting cljs repl.");
resultsOutput.appendToResultsDoc("; Aborted starting cljs repl.");
throw "Aborted";
}
} else {
chan.appendLine("Starting cljs repl for: " + projectTypeName + "...");
resultsOutput.appendToResultsDoc("; Starting cljs repl for: " + projectTypeName + "...");
return evalConnectCode(session, startCode, name, checkFn, [startAppNowProcessor, printThisPrinter], [allPrinter]);
}
} else {
Expand Down Expand Up @@ -387,23 +383,20 @@ function createCLJSReplType(cljsType: CljsTypeConfig, cljsTypeName: string, conn
}

async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: string) {
let chan = state.outputChannel();

chan.appendLine("Creating cljs repl session...");
resultsOutput.appendToResultsDoc("; Creating cljs repl session...");
let newCljsSession = await session.clone();
newCljsSession.replType = 'cljs';
if (newCljsSession) {
chan.show(true);
chan.appendLine("Connecting cljs repl: " + projectTypeName + "...");
chan.appendLine("The Calva Connection Log might have more connection progress information.");
resultsOutput.appendToResultsDoc("; Connecting cljs repl: " + projectTypeName + "...");
resultsOutput.appendToResultsDoc("; The Calva Connection Log might have more connection progress information.");
if (repl.start != undefined) {
if (await repl.start(newCljsSession, repl.name, repl.started)) {
state.analytics().logEvent("REPL", "StartedCLJS", repl.name).send();
chan.appendLine("Cljs builds started");
resultsOutput.appendToResultsDoc("; Cljs builds started");
newCljsSession = await session.clone();
} else {
state.analytics().logEvent("REPL", "FailedStartingCLJS", repl.name).send();
chan.appendLine("Failed starting cljs repl");
resultsOutput.appendToResultsDoc("; Failed starting cljs repl");
state.cursor.set('cljsBuild', null);
return [null, null];
}
Expand All @@ -416,7 +409,7 @@ async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: st
let build = state.deref().get('cljsBuild')
state.analytics().logEvent("REPL", "FailedConnectingCLJS", repl.name).send();
let failed = "Failed starting cljs repl" + (build != null ? ` for build: ${build}. Is the build running and connected?\n See the Output channel "Calva Connection Log" for any hints on what went wrong.` : "");
chan.appendLine(`${failed}`);
resultsOutput.appendToResultsDoc(`; ${failed}`);
state.cursor.set('cljsBuild', null);
vscode.window.showInformationMessage(
failed,
Expand All @@ -433,8 +426,7 @@ async function makeCljsSessionClone(session, repl: ReplType, projectTypeName: st
}

async function promptForNreplUrlAndConnect(port, connectSequence: ReplConnectSequence) {
let current = state.deref(),
chan = state.outputChannel();
let current = state.deref();

let url = await vscode.window.showInputBox({
placeHolder: "Enter existing nREPL hostname:port here...",
Expand All @@ -451,7 +443,7 @@ async function promptForNreplUrlAndConnect(port, connectSequence: ReplConnectSeq
state.cursor.set("port", parsedPort);
await connectToHost(hostname, parsedPort, connectSequence);
} else {
chan.appendLine("Bad url: " + url);
resultsOutput.appendToResultsDoc("; Bad url: " + url);
util.setConnectingState(false);
status.update();
}
Expand All @@ -467,8 +459,7 @@ export let cljSession: NReplSession;
export let cljsSession: NReplSession;

export async function connect(connectSequence: ReplConnectSequence, isAutoConnect, isJackIn) {
const chan = state.outputChannel(),
cljsTypeName = projectTypes.getCljsTypeName(connectSequence);
const cljsTypeName = projectTypes.getCljsTypeName(connectSequence);

state.analytics().logEvent("REPL", "ConnectInitiated", isAutoConnect ? "auto" : "manual");
state.analytics().logEvent("REPL", "ConnectInitiated", cljsTypeName).send();
Expand All @@ -489,7 +480,7 @@ export async function connect(connectSequence: ReplConnectSequence, isAutoConnec
await promptForNreplUrlAndConnect(port, connectSequence);
}
} else {
chan.appendLine('No nrepl port file found. (Calva does not start the nrepl for you, yet.)');
resultsOutput.appendToResultsDoc('; No nrepl port file found. (Calva does not start the nrepl for you, yet.)');
await promptForNreplUrlAndConnect(port, connectSequence);
}
} else {
Expand All @@ -498,26 +489,24 @@ export async function connect(connectSequence: ReplConnectSequence, isAutoConnec
return true;
}

function standaloneConnect(connectSequence: ReplConnectSequence, chan: vscode.OutputChannel) {
function standaloneConnect(connectSequence: ReplConnectSequence) {
if (connectSequence) {
const cljsTypeName = projectTypes.getCljsTypeName(connectSequence);
chan.appendLine(`Connecting ...`);
resultsOutput.appendToResultsDoc(`; Connecting ...`);
state.analytics().logEvent("REPL", "StandaloneConnect", `${connectSequence.name} + ${cljsTypeName}`).send();
connect(connectSequence, false, false).catch(() => { });
}
else {
chan.appendLine("Aborting connect, error determining connect sequence.");
resultsOutput.appendToResultsDoc("; Aborting connect, error determining connect sequence.");
}
}

export default {
connectNonProjectREPLCommand: async () => {
const chan = state.outputChannel();
const connectSequence = await askForConnectSequence(projectTypes.getAllProjectTypes(), 'connect-type', "ConnectInterrupted");
standaloneConnect(connectSequence, chan);
standaloneConnect(connectSequence);
},
connectCommand: async () => {
const chan = state.outputChannel();
// TODO: Figure out a better way to have an initialized project directory.
try {
await state.initProjectDir();
Expand All @@ -528,7 +517,7 @@ export default {
}
const cljTypes = await projectTypes.detectProjectTypes(),
connectSequence = await askForConnectSequence(cljTypes, 'connect-type', "ConnectInterrupted");
standaloneConnect(connectSequence, chan);
standaloneConnect(connectSequence);
},
disconnect: (options = null, callback = () => { }) => {
['clj', 'cljs'].forEach(sessionType => {
Expand Down Expand Up @@ -570,15 +559,14 @@ export default {
}
},
switchCljsBuild: async () => {
let cljSession = util.getSession('clj'),
chan = state.outputChannel();
let cljSession = util.getSession('clj');
const cljsTypeName: string = state.extensionContext.workspaceState.get('selectedCljsTypeName'),
cljTypeName: string = state.extensionContext.workspaceState.get('selectedCljTypeName');
state.analytics().logEvent("REPL", "switchCljsBuild", cljsTypeName).send();

let [session, build] = await makeCljsSessionClone(cljSession, translatedReplType, cljTypeName);
if (session) {
await setUpCljsRepl(session, chan, build);
await setUpCljsRepl(session, build);
}
status.update();
}
Expand Down
4 changes: 1 addition & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function activate(context: vscode.ExtensionContext) {


chan.appendLine("Calva activated.");

outputWindow.initResultsDoc();
status.update();

// COMMANDS
Expand Down Expand Up @@ -233,8 +233,6 @@ function activate(context: vscode.ExtensionContext) {
}
}

chan.appendLine("Start the REPL with the command *Start Project REPL and connect (aka Jack-in)*.")
chan.appendLine("Default keybinding for Jack-in: ctrl+alt+c ctrl+alt+j");
state.analytics().logPath("/activated").logEvent("LifeCycle", "Activated").send();

if (!cwExtension) {
Expand Down
Loading

0 comments on commit 021ad36

Please sign in to comment.