diff --git a/src/cljConnection.ts b/src/cljConnection.ts index 30ccf7b..b0be265 100644 --- a/src/cljConnection.ts +++ b/src/cljConnection.ts @@ -8,6 +8,7 @@ import { nreplController } from './nreplController'; export interface CljConnectionInformation { host: string; port: number; + session?: string; } export interface REPLSession { type: 'ClojureScript' | 'Clojure'; @@ -17,6 +18,7 @@ export interface REPLSession { const CONNECTION_STATE_KEY: string = 'CLJ_CONNECTION'; const DEFAULT_LOCAL_IP: string = '127.0.0.1'; const CLJS_SESSION_KEY: string = 'CLJS_SESSION'; +const CL_SESSION_KEY: string = 'CL_SESSION'; const connectionIndicator: vscode.StatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); let cljContext: vscode.ExtensionContext; @@ -209,7 +211,8 @@ const sessionForFilename = (filename: string): Promise => { const sessionType = filename.endsWith('.cljs') ? "ClojureScript" : "Clojure"; if (sessionType == "Clojure") { // Assume that the default session is Clojure. This is always the case with cider. - return resolve({ type: sessionType, id: undefined }); + const connection = getConnection() + return resolve({ type: sessionType, id: !connection ? connection : connection.session }); } const session_id = cljContext.workspaceState.get(CLJS_SESSION_KEY); diff --git a/src/clojureEval.ts b/src/clojureEval.ts index 485c785..b2e1423 100644 --- a/src/clojureEval.ts +++ b/src/clojureEval.ts @@ -147,13 +147,14 @@ function evaluate(outputChannel: vscode.OutputChannel, showResults: boolean): vo const selection = editor.selection; let text = editor.document.getText(); if (!selection.isEmpty) { - const ns: string = cljParser.getNamespace(text); - text = `(ns ${ns})\n${editor.document.getText(selection)}`; + // const ns: string = cljParser.getNamespace(text); + // text = `(ns ${ns})\n${editor.document.getText(selection)}`; + text = editor.document.getText(selection); } cljConnection.sessionForFilename(editor.document.fileName).then(session => { let response; - if (!selection.isEmpty && session.type == 'ClojureScript') { + if (!selection.isEmpty) { // Piggieback's evalFile() ignores the text sent as part of the request // and just loads the whole file content from disk. So we use eval() // here, which as a drawback will give us a random temporary filename in @@ -204,6 +205,7 @@ function handleSuccess(outputChannel: vscode.OutputChannel, showResults: boolean if (!showResults) { vscode.window.showInformationMessage('Successfully compiled'); } else { + let connection = cljConnection.getConnection(); respObjs.forEach(respObj => { if (respObj.out) outputChannel.append(respObj.out); @@ -212,7 +214,10 @@ function handleSuccess(outputChannel: vscode.OutputChannel, showResults: boolean if (respObj.value) outputChannel.appendLine(`=> ${respObj.value}`); outputChannel.show(true); + + if(connection && !connection.session) { + connection.session = respObj.session; + } }); } - nreplClient.close(respObjs[0].session); } diff --git a/src/nreplClient.ts b/src/nreplClient.ts index fccc58b..e530fc3 100644 --- a/src/nreplClient.ts +++ b/src/nreplClient.ts @@ -4,14 +4,17 @@ import { Buffer } from 'buffer'; import * as bencodeUtil from './bencodeUtil'; import { cljConnection, CljConnectionInformation } from './cljConnection'; +import { resolve } from 'url'; interface nREPLCompleteMessage { + id: string, op: string; symbol: string; ns?: string } interface nREPLInfoMessage { + id: string, op: string; symbol: string; ns: string; @@ -25,6 +28,7 @@ type TestMessage = { } interface nREPLEvalMessage { + id: string, op: string; file: string; 'file-path'?: string; @@ -32,47 +36,51 @@ interface nREPLEvalMessage { } interface nREPLSingleEvalMessage { + id: string, op: string; code: string; session: string; } interface nREPLStacktraceMessage { + id: string, op: string; session: string; } interface nREPLCloneMessage { + id: string, op: string; session?: string; } interface nREPLCloseMessage { + id: string, op: string; session?: string; } const complete = (symbol: string, ns: string): Promise => { - const msg: nREPLCompleteMessage = { op: 'complete', symbol, ns }; + const msg: nREPLCompleteMessage = { id: create_UUID(), op: 'complete', symbol, ns }; return send(msg).then(respObjs => respObjs[0]); }; const info = (symbol: string, ns: string, session?: string): Promise => { - const msg: nREPLInfoMessage = { op: 'info', symbol, ns, session }; + const msg: nREPLInfoMessage = { id: create_UUID(), op: 'info', symbol, ns, session }; return send(msg).then(respObjs => respObjs[0]); }; -const evaluate = (code: string, session?: string): Promise => clone(session).then((session_id) => { - const msg: nREPLSingleEvalMessage = { op: 'eval', code: code, session: session_id }; +const evaluate = (code: string, session?: string): Promise => (!session ? clone(session) : Promise.resolve(session)).then((session_id) => { + const msg: nREPLSingleEvalMessage = { id: create_UUID(), op: 'eval', code: code, session: session_id }; return send(msg); }); -const evaluateFile = (code: string, filepath: string, session?: string): Promise => clone(session).then((session_id) => { - const msg: nREPLEvalMessage = { op: 'load-file', file: code, 'file-path': filepath, session: session_id }; +const evaluateFile = (code: string, filepath: string, session?: string): Promise => (!session ? clone(session) : Promise.resolve(session)).then((session_id) => { + const msg: nREPLEvalMessage = { id: create_UUID(), op: 'load-file', file: code, 'file-path': filepath, session: session_id }; return send(msg); }); -const stacktrace = (session: string): Promise => send({ op: 'stacktrace', session: session }); +const stacktrace = (session: string): Promise => send({ id: create_UUID(), op: 'stacktrace', session: session }); const runTests = function (namespace: string | undefined): Promise { const message: TestMessage = { @@ -84,10 +92,10 @@ const runTests = function (namespace: string | undefined): Promise { } -const clone = (session?: string): Promise => send({ op: 'clone', session: session }).then(respObjs => respObjs[0]['new-session']); +const clone = (session?: string): Promise => send({ id: create_UUID(), op: 'clone', session: session }).then(respObjs => respObjs[0]['new-session']); const test = (connectionInfo: CljConnectionInformation): Promise => { - return send({ op: 'clone' }, connectionInfo) + return send({ id: create_UUID(), op: 'clone' }, connectionInfo) .then(respObjs => respObjs[0]) .then(response => { if (!('new-session' in response)) @@ -98,10 +106,10 @@ const test = (connectionInfo: CljConnectionInformation): Promise => { }); }; -const close = (session?: string): Promise => send({ op: 'close', session: session }); +const close = (session?: string): Promise => send({ id: create_UUID(), op: 'close', session: session }); const listSessions = (): Promise<[string]> => { - return send({ op: 'ls-sessions' }).then(respObjs => { + return send({ id: create_UUID(), op: 'ls-sessions' }).then(respObjs => { const response = respObjs[0]; if (response.status[0] == "done") { return Promise.resolve(response.sessions); @@ -162,6 +170,17 @@ const isLastNreplObject = (nreplObjects: any[]): boolean => { return lastObj && lastObj.status && lastObj.status.indexOf('done') > -1; } +const create_UUID = () => { + var dt = new Date().getTime(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = (dt + Math.random()*16)%16 | 0; + dt = Math.floor(dt/16); + return (c=='x' ? r :(r&0x3|0x8)).toString(16); + }); + return uuid; +} + + export const nreplClient = { complete, info,