Skip to content

Commit

Permalink
- Make autocomplete suggestion loader asynchronous.
Browse files Browse the repository at this point in the history
- Add command execution, path navigation.
- Flesh out client-side message handler passing.
  • Loading branch information
unconed committed Sep 18, 2010
1 parent 304c777 commit cf15a49
Show file tree
Hide file tree
Showing 17 changed files with 323 additions and 107 deletions.
25 changes: 16 additions & 9 deletions HTML/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,25 @@ var tc = termkit.client = function () {
};

tc.prototype = {
invoke: function (method, args, returnCallback, viewCallback) {
// Invoke a method on the server.
invoke: function (method, args, returnCallback, handlers) {
handlers = handlers || {};
handlers.Return = returnCallback;

var sequence = this.nextId++;
this.handlers[sequence] = {
ret: returnCallback,
view: viewCallback,
};
console.log(method);
this.handlers[sequence] = handlers;

this.send(method, sequence, args);
},

// Pass a message to the server.
send: function (method, sequence, args) {
var json = JSON.stringify([ method, sequence, args ]);
console.log('sending '+json);
this.socket.send(json);
},

// Receive a message from the server.
message: function (data) {
// Parse incoming message.
var message = JSON.parse(data);
Expand All @@ -57,18 +61,21 @@ tc.prototype = {
sequence = message[1],
args = message[2];

console.log('received '+data);

// Verify arguments.
if (typeof message[1] == 'number') {
// Locate handler for method and execute.
var handler = this.handlers[sequence];
if (handler) {
if (method == 'return') {
handler.ret && handler.ret(args.data, args.code, args.status);
var prefix = method.split('.')[0];
if (prefix == 'return') {
handler.Return && handler.Return(args.data, args.code, args.status);
// Clean-up callbacks.
delete this.handlers[sequence];
}
else {
handler.view && handler.view(method, args);
handler[prefix] && handler[prefix](method, args);
}
}
}
Expand Down
23 changes: 21 additions & 2 deletions HTML/client/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,31 @@ var tc = termkit.client;
tc.shell = function (client, environment) {
var self = this;

this.environment = environment;
this.client = client;
this.environment = environment;

};

tc.shell.prototype = {

shellHandler: function (method, args) {
switch (method) {
case 'shell.environment':
for (i in args) {
this.environment[i] = args[i];
}
break;
}
},

run: function (tokens, exit, handlers) {
var self = this;
handlers['shell'] = function (m,a) { self.shellHandler(m, a); };

this.client.invoke('shell.run', {
tokens: tokens,
sessionId: this.environment.sessionId,
}, exit, handlers);
},
};

})();
Expand Down
43 changes: 28 additions & 15 deletions HTML/commandview/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,19 @@ var cv = termkit.commandView;
/**
* Represents a single command in the view.
*/
cv.command = function (context) {
cv.command = function (commandView, context) {
this.$element = this.$markup();
this.$sigil = this.$element.find('.sigil');

this.commandView = commandView;
this.context = context;
this.collapsed = true;
this.state = cv.command.STATE_WAITING;
this.state = 'waiting';

// Refresh markup.
this.updateElement();
};

cv.command.STATE_WAITING = 0;
cv.command.STATE_RUNNING = 1;
cv.command.STATE_SUCCESS = 2;
cv.command.STATE_WARNING = 3;
cv.command.STATE_ERROR = 4;

///////////////////////////////////////////////////////////////////////////////

cv.command.prototype = {
Expand All @@ -42,14 +37,14 @@ cv.command.prototype = {
$command.append(this.progressIndicator.$element);

this.progressIndicator.$element.hide();

return $command;
},

// State
get state() { return this._state; },
set state(state) {
this._state = state || cv.command.STATE_WAITING;
this._state = state || 'waiting';
this.updateElement();
},

Expand All @@ -64,13 +59,30 @@ cv.command.prototype = {
updateElement: function () {
this.$element.data('controller', this);
this.$sigil.html(this.collapsed ? '▶' : '▼');
this.progressIndicator.$element[(this.state == cv.command.STATE_RUNNING) ? 'show' : 'hide']();
this.progressIndicator.$element[(this.state == 'running') ? 'show' : 'hide']();
},

// Execute command.
// Execute tokenfield as command.
submitCommand: function (event, tokens) {
this.state = cv.command.STATE_RUNNING;
var self = this;
this.state = 'running';
this.collapsed = false;

// Convert tokens into strings.
var command = tokens.map(function (t) { return t.toCommand(); });
this.context.shell.run(command, function (data, code, status) {
// Set appropriate return state.
self.state = {
'ok': 'ok',
'warning': 'warning',
'error': 'error',
}[status] || 'ok';

// Open new command.
async(function () {
self.commandView.newCommand();
});
}, { });
},

// Use triggers to respond to a creation or change event.
Expand Down Expand Up @@ -155,8 +167,9 @@ cv.commandExecutable.triggerExecutable = function (offset, event, tokens) {
}
};

cv.commandExecutable.autocompleteExecutable = function (offset, event, tokens) {
return ['foo', 'bar', '.txt', this.context.user];
cv.commandExecutable.autocompleteExecutable = function (offset, event, tokens, callback) {
var suggestions = [];
callback(suggestions);
};

cv.commandExecutable.prototype = $.extend(new cv.command(), {});
Expand Down
8 changes: 5 additions & 3 deletions HTML/commandview/commandcontext.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ var cv = termkit.commandView;
/**
* Represents the system context for a command.
*/
cv.commandContext = function (environment) {
cv.commandContext = function (shell) {
this.$element = this.$markup();

this.$path = this.$element.find('.path');
this.$user = this.$element.find('.user');

this.path = environment.home;
this.user = environment.user;
this.shell = shell;

this.path = shell.environment.cwd;
this.user = shell.environment.user;
};

cv.commandContext.prototype = {
Expand Down
21 changes: 11 additions & 10 deletions HTML/commandview/commandview.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ var cv = termkit.commandView = function (shell) {
var self = this;

this.shell = shell;
this.environment = shell.environment;
this.context = new cv.commandContext(this.environment);

this.$element = this.$markup();

Expand All @@ -17,9 +15,9 @@ var cv = termkit.commandView = function (shell) {
this.$context = $(this.$element).find('.context');

this.activeIndex = 0;
this.beginIndex = 0;
this.endIndex = 0;
this.commandList = new cv.commandList();

this.newCommand();
};

cv.prototype = {
Expand All @@ -33,11 +31,12 @@ cv.prototype = {

// Refresh the given view by re-inserting all command elements.
updateElement: function () {
// Refresh commands.
var $commands = this.$commands.empty();
$.each(this.commandList.commands, function () {
$commands.append(this.$element);
});
if (this.endIndex < this.commandList.length) {
for (; this.endIndex < this.commandList.length; ++this.endIndex) {
var command = this.commandList.commands[this.endIndex];
this.$commands.append(command.$element);
}
}

// Refresh context bar.
var command = this.activeCommand();
Expand All @@ -51,9 +50,11 @@ cv.prototype = {
},

newCommand: function () {
this.commandList.add(new cv.command(this.context));
var command = new cv.command(this, new cv.commandContext(this.shell));
this.commandList.add(command);
this.activeIndex = this.commandList.length - 1;
this.updateElement();
command.tokenField.focus();
},

// Respond to mouse clicks.
Expand Down
18 changes: 17 additions & 1 deletion HTML/termkit.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ body {
.termkitTokenField {
border: 1px dotted #555;
line-height: 22px;
padding: 11px 10px 9px 35px;
padding: 10px 10px 10px 35px;

cursor: text;
}
Expand Down Expand Up @@ -221,7 +221,23 @@ body {
/************/

.termkitTokenField > span.token {
white-space: pre-wrap;
word-wrap: break-word;
max-width: 100%;
}

.termkitTokenField > span.token input {
max-width: 100%;
}

.termkitTokenField > span.token:not(:first-child)::after {
white-space: normal;
content: ' ';
}

.termkitTokenField > span.token:last-child::after {
white-space: pre;
content: ' ';
}

.termkitTokenField > span.token:after {
Expand Down
3 changes: 3 additions & 0 deletions HTML/termkit.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ $(document).ready(function () {
var shell = new termkit.client.shell(client, environment);
var view = new termkit.commandView(shell);
$('#terminal').append(view.$element);

view.newCommand();

console.log(environment);
});

Expand Down
46 changes: 25 additions & 21 deletions HTML/tokenfield/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,34 @@ tf.autocomplete.prototype = {
// Check if it's appropriate to display suggestions.
// TODO

var $e = this.$element.find('.lines');
$e.hide();

// Get list of suggestions.
this.items = this.handler && this.handler.call(this, tl.indexOf(token), event, tl.tokens) || [];
var self = this;
if (this.handler) {
this.handler.call(this, tl.indexOf(token), event, tl.tokens, function (items) {
self.items = items || [];

// Insert lines into box.
var prefix = this.prefix, $e = this.$element.find('.lines');
$e.empty();
$.each(this.items, function () {
$e.append($('<span>').addClass("line").html('<span class="prefix">' + escapeText(prefix) +'</span><span>'+ escapeText(this) +'</span>'));
});
// Insert lines into box.
var prefix = self.prefix;
$e.empty();
$.each(self.items, function () {
$e.append($('<span>').addClass("line").html('<span class="prefix">' + escapeText(prefix) +'</span><span>'+ escapeText(this) +'</span>'));
});
$e.show();

// Highlight active line, if any,
if (this.items.length) {
this.selected = (this.selected + this.items.length) % this.items.length;
var $line = $($e.find('.line')[this.selected]);

// Move caret element to active line.
var offsetY = $line.addClass('active').position().top;
//this.caret.$element.find('input').css('marginTop', offsetY);
this.$element.animate({ 'marginTop': -offsetY }, { duration: 50 });

$e.show();
}
else {
$e.hide();
// Highlight active line, if any,
if (self.items.length) {
self.selected = (self.selected + self.items.length) % self.items.length;
var $line = $($e.find('.line')[self.selected]);

// Move caret element to active line.
var offsetY = $line.addClass('active').position().top;
//this.caret.$element.find('input').css('marginTop', offsetY);
self.$element.animate({ 'marginTop': -offsetY }, { duration: 50 });
}
});
}
},

Expand Down
2 changes: 2 additions & 0 deletions HTML/tokenfield/caret.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ tf.caret.prototype = {
},

remove: function () {
console.log("remove ", this.token);
// Guard against recursive calls due to e.g. triggering onblur when detaching caret from DOM.
if (!this.token || !this.token.locked) return;

Expand Down Expand Up @@ -171,6 +172,7 @@ tf.caret.prototype = {
switch (event.keyCode) {
case 13: // Return
async.call(this, function () {
this.remove();
this.onSubmit(this.token, event);
});
break;
Expand Down
4 changes: 4 additions & 0 deletions HTML/tokenfield/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ tf.token.prototype = {
toString: function () {
return '['+ this.contents + '(' + this.type +')]';
},

toCommand: function () {
return this.contents;
},
};

///////////////////////////////////////////////////////////////////////////////
Expand Down
Loading

0 comments on commit cf15a49

Please sign in to comment.