Skip to content

Commit

Permalink
Implemented a very basic vscode extension-structure. Closes BetterTha…
Browse files Browse the repository at this point in the history
  • Loading branch information
Stian Sivertsen committed Jan 5, 2017
1 parent b217962 commit 886d306
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"env": {
"browser": false,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"rules": {
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-unreachable": "warn",
"no-unused-vars": "warn",
"constructor-super": "warn",
"valid-typeof": "warn"
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# visual code
.vscode

# Logs
logs
*.log
Expand Down
7 changes: 7 additions & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.vscode/**
.vscode-test/**
test/**
.gitignore
jsconfig.json
vsc-extension-quickstart.md
.eslintrc.json
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Change Log
All notable changes to the "visualclojure" extension will be documented in this file.

## [Unreleased]
- Initial release
12 changes: 12 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"lib": [
"es6"
]
},
"exclude": [
"node_modules"
]
}
39 changes: 39 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "visualclojure",
"displayName": "visualclojure",
"description": "clj(s) support for visual studio code",
"version": "0.0.1",
"publisher": "stiansivertsen",
"engines": {
"vscode": "^1.5.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onLanguage:clojure"
],
"main": "./src/extension",
"contributes": {
"commands": [{
"command": "visualclojure.connectToREPL",
"title": "VisualClojure: Connect to an existing nREPL session"
}]
},
"scripts": {
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
"devDependencies": {
"typescript": "^2.0.3",
"vscode": "^1.0.0",
"mocha": "^2.3.3",
"eslint": "^3.6.0",
"@types/node": "^6.0.40",
"@types/mocha": "^2.2.32",
"bencoder": "^0.0.5",
"buffer": "^5.0.2",
"net": "^1.0.2",
"nrepl-client": "0.2.3"
}
}
Empty file added src/clojure/eval_file.js
Empty file.
82 changes: 82 additions & 0 deletions src/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const vscode = require('vscode');
const nreplClient = require('nrepl-client');
const vsclj = require('./state');

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
function activate(context) {
let statusbar_type = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
statusbar_type.text = vsclj.session_type;
statusbar_type.show();

let connectToREPL = vscode.commands.registerCommand('visualclojure.connectToREPL', function () {
vscode.window.showInputBox({
placeHolder: "Enter existing nREPL hostname:port here...",
prompt: "Add port to nREPL if localhost, otherwise 'hostname:port'",
value: "localhost:",
ignoreFocusOut: true
})
.then(function (nREPL) {
let result = nREPL.split(':');
let hostname = result[0];
let port = result[1];

vsclj.hostname = hostname;
vsclj.port = port;


let client = nreplClient.connect({
host: hostname,
port: port
}).once('connect', function () {
client.lsSessions(function (err, result) {
vsclj.connected = true;
vsclj.session_type = "ClojureScript Session";
vsclj.session_id = result[0].sessions[0];

console.log(vsclj);

statusbar_type.text = vsclj.session_type;

client.end();
})
});
},

function (err) {
console.error("Unable to connect to REPL!");
console.error(err);
}
);
});

context.subscriptions.push(connectToREPL);

vscode.workspace.onDidSaveTextDocument(function (file) {
console.log("SAVED!");
console.log(file);

if (vsclj.connected) {
console.log("USING SESSION => " + vsclj.session_id);

let client = nreplClient.connect({
host: vsclj.hostname,
port: vsclj.port
}).once('connect', function () {
var cljs_expr = '(. (js/Date.) toLocaleString)';
client.eval(cljs_expr, "", vsclj.session_id, function (err, result) {
console.log("EVAL!");
console.log(result);
client.end();
})
});
} else {
console.log("NOT CONNECTED TO NREPL! PLEASE CONNECT TO EVAL..");
}
});
}
exports.activate = activate;

// this method is called when your extension is deactivated
function deactivate() {}
exports.deactivate = deactivate;
34 changes: 34 additions & 0 deletions src/nrepl/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

import * as net from 'net';
import {Buffer} from 'buffer';
import * as Bencoder from 'bencoder';

function connect(state, hostname, port) {
if (state.connection === null) {
state.connection = net.createConnection({host: hostname,
port: port});
}
return state;
};

function send(connection, msg, callback) {
var nREPLResponse = new Buffer('');

var encodedMsg = Bencoder.encode(msg);
connection.write(encodedMsg);
connection.on('data', function (data) {
try {
nREPLResponse = Buffer.concat([nREPLResponse, data]);
var response = Bencoder.decode(nREPLResponse);
callback(response);
} catch (error) {
// waiting for the rest of the response
}
});
};

module.exports = {
connect : connect,
send : send
};
24 changes: 24 additions & 0 deletions src/nrepl/message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';
var operation = {
"EVALUATE" : "eval",
"LIST_SESSIONS" : "lsSessions"
}

function evalMsg(params) {
return {
"op" : operation.EVALUATE,
"code" : params.code,
"session" : params.session
};
};

function listSessions() {
return {
"op" : operation.LIST_SESSIONS
};
};

module.exports = {
"eval" : evalMsg,
"listSessions" : listSessions
};
15 changes: 15 additions & 0 deletions src/state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var session_type = {
CLJS : "ClojureScript Session",
CLJ : "Clojure Session",
NONE : "No Session"
}

module.exports = {
hostname : null,
port: null,
session_id : null,
session_type: session_type.NONE,
connected: false,
connection: null,
last_communication: null
}
24 changes: 24 additions & 0 deletions test/extension.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* global suite, test */

//
// Note: This example test is leveraging the Mocha test framework.
// Please refer to their documentation on https://mochajs.org/ for help.
//

// The module 'assert' provides assertion methods from node
var assert = require('assert');

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
var vscode = require('vscode');
var myExtension = require('../extension');

// Defines a Mocha test suite to group tests of similar kind together
suite("Extension Tests", function() {

// Defines a Mocha unit test
test("Something 1", function() {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});
22 changes: 22 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
//
// This file is providing the test runner to use when running extension tests.
// By default the test runner in use is Mocha based.
//
// You can provide your own test runner if you want to override it by exporting
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
// host can call to run the tests. The test runner is expected to use console.log
// to report the results back to the caller. When the tests are finished, return
// a possible error to the callback or null if none.

var testRunner = require('vscode/lib/testrunner');

// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.js (suite, test, etc.)
useColors: true // colored output from test results
});

module.exports = testRunner;

0 comments on commit 886d306

Please sign in to comment.