From 971183df9dcceb051d3a4ed40dbc82a82d4dd99a Mon Sep 17 00:00:00 2001 From: Steven Wittens Date: Thu, 5 May 2011 01:47:47 -0700 Subject: [PATCH] Fix autocompletion event handling around up/down arrows. Fix filesystem autocompleter --- HTML/client/shell.js | 2 +- HTML/termkit.css | 3 ++- HTML/termkit.js | 2 +- HTML/tokenfield/autocomplete.js | 12 ++++++++- HTML/tokenfield/caret.js | 7 +++--- HTML/tokenfield/token.js | 6 +++-- HTML/tokenfield/tokenfield.js | 3 +++ HTML/typography.css | 3 ++- License.txt | 2 +- Node/shell/autocomplete.js | 21 +++++++++++----- Node/shell/builtin.js | 6 +++-- Node/shell/meta.js | 2 +- Node/shell/worker.js | 5 +++- termkit.txt | 8 +++--- todo.txt | 43 ++++++++++++--------------------- 15 files changed, 74 insertions(+), 51 deletions(-) diff --git a/HTML/client/shell.js b/HTML/client/shell.js index a4ea693..53648fe 100644 --- a/HTML/client/shell.js +++ b/HTML/client/shell.js @@ -24,7 +24,7 @@ tc.shell = function (client, environment, success) { that.query('shell.environment', { }, function (message) { that.environment = message.args; - success(); + success(that); }); }); diff --git a/HTML/termkit.css b/HTML/termkit.css index 5dcab4e..bcfc56b 100644 --- a/HTML/termkit.css +++ b/HTML/termkit.css @@ -140,6 +140,7 @@ body { left: 15px; top: 12px; color: #ccc; + font-size: 12px; } .termkitCommand > span.sigil-ok { @@ -272,7 +273,7 @@ body { z-index: 2; display: block; white-space: nowrap; - height: 21px; + height: 23px; z-index: 5; } diff --git a/HTML/termkit.js b/HTML/termkit.js index 468adfb..fb56a46 100644 --- a/HTML/termkit.js +++ b/HTML/termkit.js @@ -8,7 +8,7 @@ $(document).ready(function () { var client = new termkit.client(); client.onConnect = function () { - var shell = new termkit.client.shell(client, {}, function () { + var shell = new termkit.client.shell(client, {}, function (shell) { var view = new termkit.commandView(shell); $('#terminal').append(view.$element); view.newCommand(); diff --git a/HTML/tokenfield/autocomplete.js b/HTML/tokenfield/autocomplete.js index f684286..2a582c8 100644 --- a/HTML/tokenfield/autocomplete.js +++ b/HTML/tokenfield/autocomplete.js @@ -14,6 +14,7 @@ tf.autocomplete = function (caret) { this.selected = 0; this.token = null; this.last = null; + this.animateTarget = 0; }; tf.autocomplete.prototype = { @@ -52,6 +53,7 @@ tf.autocomplete.prototype = { this.prefix = ''; this.selected = 0; this.token = null; + this.animateTarget = 0; // Reset caret position. //this.caret.$element.find('input').css('marginTop', 0); @@ -90,7 +92,14 @@ tf.autocomplete.prototype = { // Move caret element to active line. var offsetY = $line.addClass('active').position().top; //this.caret.$element.find('input').css('marginTop', offsetY); - that.$element.animate({ 'marginTop': -offsetY }, { duration: 30, queue: false }); + that.$element.stop().css({ + marginTop: that.animateTarget, + }) + .animate({ 'marginTop': -offsetY }, { + duration: 30, + queue: false, + }); + that.animateTarget = -offsetY; } else { $e.empty().hide(); @@ -121,6 +130,7 @@ tf.autocomplete.prototype = { onComplete: function (event) { if (this.token && this.selected < this.items.length) { + event.charCode = 10; // LF \n this.caret.setContents(this.items[this.selected] +' ', event); this.remove(); } diff --git a/HTML/tokenfield/caret.js b/HTML/tokenfield/caret.js index 69a4b58..607b8f1 100644 --- a/HTML/tokenfield/caret.js +++ b/HTML/tokenfield/caret.js @@ -132,7 +132,6 @@ tf.caret.prototype = { this.prefix = ''; this.$input.val(string); this.suffix = ''; - this.updateContents(event); }, @@ -145,6 +144,8 @@ tf.caret.prototype = { var old = this.token; var updated = this.prefix + this.$input.val() + this.suffix; + console.log('caret.updateContents', updated, this.selection, event); + // Check for changes and apply them. if (this.token.contents != updated) { this.autocomplete.remove(); @@ -154,8 +155,8 @@ tf.caret.prototype = { // (asynchronous to give the DOM time to finish event handling). async.call(this, function () { // Merge stored key/char codes in, effectively merging keydown/keypress info. - event.keyCode = this.keyCode; - event.charCode = this.charCode; + event.keyCode = event.keyCode || this.keyCode; + event.charCode = event.charCode || this.charCode; this.onChange(this.token, event); // TODO: replace with real autocomplete diff --git a/HTML/tokenfield/token.js b/HTML/tokenfield/token.js index b36b3f2..c0fd989 100644 --- a/HTML/tokenfield/token.js +++ b/HTML/tokenfield/token.js @@ -60,10 +60,9 @@ tf.token.prototype = { transmute: function (token) { if (this.contents == token.contents) { this.constructor = token.constructor; - this.checkSelf = token.checkSelf; - this.checkTriggers = token.checkTriggers; this.type = token.type; this.allowEmpty = token.allowEmpty; + this.__proto__ = token.prototype; return true; } }, @@ -72,6 +71,9 @@ tf.token.prototype = { // @return Array of replacement tokens for this token (optional). checkTriggers: function (selection, event) { var token = this, t = tf.token.triggers; + + console.log('checkTriggers', event, token, selection.anchor.token); + // Apply type var update, triggers = [].concat(t[this.type] || [], t['*'] || []); $.each(triggers, function () { diff --git a/HTML/tokenfield/tokenfield.js b/HTML/tokenfield/tokenfield.js index d593ea1..8d4fe37 100644 --- a/HTML/tokenfield/tokenfield.js +++ b/HTML/tokenfield/tokenfield.js @@ -102,6 +102,8 @@ tf.prototype = { // Refresh the given token in response to input. updateToken: function (token, event) { + console.log('tokenField.updateToken', token, event); + // Apply own rules. var update = token.checkSelf(this.selection, event); if (!update) { @@ -111,6 +113,7 @@ tf.prototype = { // Insert replacement tokens if given. if (update) { + console.log(' .updateToken update', update); // Allow both single replacement token as well as array of tokens. if (update.length === undefined) update = [update]; diff --git a/HTML/typography.css b/HTML/typography.css index ac96392..cc1bd28 100644 --- a/HTML/typography.css +++ b/HTML/typography.css @@ -9,8 +9,9 @@ body { } .termkitCommandView pre { - font-family: "BitStream Vera Sans"; + font-family: "BitStream Vera Sans Mono"; font-size: inherit; + font-size: 87.5%; } .termkitOutputView .widgetFile .name { diff --git a/License.txt b/License.txt index 05e0f54..228d327 100644 --- a/License.txt +++ b/License.txt @@ -1,4 +1,4 @@ -Copyright (c) 2009-2010, Steven Wittens +Copyright (c) 2009-2011, Steven Wittens All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Node/shell/autocomplete.js b/Node/shell/autocomplete.js index b04c0cc..8321246 100644 --- a/Node/shell/autocomplete.js +++ b/Node/shell/autocomplete.js @@ -42,6 +42,7 @@ exports.autocomplete.prototype = { var matches = []; for (i in builtin.shellCommands) { if (prefix == '' || i.indexOf(prefix) === 0) { + // TODO: Add space suffix / label matches.push(i); } } @@ -51,7 +52,12 @@ exports.autocomplete.prototype = { filesystem: function (path, prefix, options, callback) { var sticky = ''; + path = path || process.cwd(); + + if (/[^\/]$/(path)) { + path += '/'; + } prefix = prefix || ''; if (prefix[0] == '/') { @@ -59,11 +65,13 @@ exports.autocomplete.prototype = { sticky = '/'; path = '/'; } - else if (prefix.indexOf('/') != -1) { - var split = prefix.split(/\//); - path += '/' + split[0]; - prefix = split[1]; - sticky = split[0] + '/'; + + if (prefix.indexOf('/') != -1) { + var split = prefix.split(/\//g); + prefix = split.pop(); + head = split.join('/') + '/'; + path += head; + sticky += head; } if (typeof options == 'function') { @@ -80,11 +88,12 @@ exports.autocomplete.prototype = { matches.sort(); callback(matches); }); - + fs.readdir(path, track(function (err, files) { if (!err) { for (i in files) (function (file) { if (prefix == '' || file.indexOf(prefix) === 0) { + // TODO: stat file, and add appropriate suffix matches.push(sticky + file); } })(files[i]); diff --git a/Node/shell/builtin.js b/Node/shell/builtin.js index a2c85bf..dc452c8 100644 --- a/Node/shell/builtin.js +++ b/Node/shell/builtin.js @@ -51,11 +51,13 @@ exports.shellCommands = { out.print("Error reading file (" + file + ")"); return; } + + var slice = buffer.slice(0, bytesRead); if (position == 0) { var headers = new meta.headers(); headers.set({ - 'Content-Type': meta.sniff(file, buffer), + 'Content-Type': meta.sniff(file, slice), 'Content-Length': stats.size, 'Content-Disposition': [ 'attachment', { 'filename': file } ], }); @@ -63,7 +65,7 @@ exports.shellCommands = { pipes.dataOut.write(headers.generate()); } - pipes.dataOut.write(buffer.slice(0, bytesRead)); + pipes.dataOut.write(slice); position += bytesRead; if (position < stats.size) { diff --git a/Node/shell/meta.js b/Node/shell/meta.js index 3f88971..5d66561 100644 --- a/Node/shell/meta.js +++ b/Node/shell/meta.js @@ -403,7 +403,7 @@ exports.sniff = function (file, data) { return mime.types[extension]; } - if (/[^\u0001-\u00FD]/('' + data)) { + if (/[^\u0001-\uFFFF]/('' + data)) { return 'application/octet-stream'; } diff --git a/Node/shell/worker.js b/Node/shell/worker.js index 64c647f..c52e898 100644 --- a/Node/shell/worker.js +++ b/Node/shell/worker.js @@ -4,5 +4,8 @@ require.paths.unshift('shell'); var processor = require('processor'); +// Change to home directory. +process.chdir(process.env.HOME); + // Set up processor. -var p = new processor.processor(process.openStdin(), process.stdout); \ No newline at end of file +var p = new processor.processor(process.openStdin(), process.stdout); diff --git a/termkit.txt b/termkit.txt index 8045803..c831855 100644 --- a/termkit.txt +++ b/termkit.txt @@ -59,7 +59,8 @@ Good desktop citizen: [X] Viewstream integration [X] 5-pipe command execution [ ] unix command execution - [ ] filesystem autocomplete + [.] filesystem autocomplete + [ ] http get/post data piping [ ] command decoration [ ] interactive execution [ ] inline man-pages tips @@ -67,6 +68,7 @@ Good desktop citizen: [ ] interactive quicklook [X] OS X icon loading [X] inline image display + [ ] regexp hinter 0.4: Network & Modularity [ ] SSH tunneling @@ -395,11 +397,11 @@ seq: set, callback method: view.* - > shell-specific interaction rules are client-side. + > shell-specific interaction rules are server-side. > rich widget lib for display, extensible > widgets are streamed to client like termkit-ML. objects are smartly typed and have callback commands defined for them. callbacks can be stateful or stateless. though stateful is only intended to be used for interactive commands. - tableview / listcontainer -> generic, scales form simple list to tabled headers w/ simple syntax + tableview / listcontainer -> generic, scales from simple list to tabled headers w/ simple syntax object references for files and other things. are multi-typed and annotated on server-side. +++ -- diff --git a/todo.txt b/todo.txt index 6a0fb85..1dee319 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,9 @@ Tasks: -[ ] filesystem autocomplete +[:] filesystem autocomplete [.] Viewstream integration +[ ] run unix [ ] run pipeline test - [X] run built-in - [ ] run unix -[X] output formatter +[ ] cat/echo Piping + progress bar [ ] 5-pipe command execution [ ] unix command execution [ ] command decoration @@ -13,17 +12,12 @@ Tasks: [ ] version control [ ] interactive quicklook -[ ] File autocompletion -[ ] cat/echo Piping + progress bar -[ ] refactor/standardize view bridge onto standard DOM -[ ] file < input piping, use node-mime to detect type? -[ ] Improve typography of directory listing Prototype: 1) UI prototypes -[alpha] Token field +[:] Token field [X] plain text [X] encapsed string [X] token transmutation @@ -45,14 +39,7 @@ Prototype: [ ] caret.remove() shouldn't need to touch tokenList when pruning empties -> let triggers do it [ ] | and >> token support - [?] write external bindings for tokenfield - => tokenfield abstracts, interface for matching should be only multiregexp + callback - . on change -> process tokens, apply multiregexps - . register multiregexp - . execute command - [?] rewrite $element / $markup pattern to create new $markup on demand when doing insert/remove from DOM - -[X] inline autocomplete +[:] inline autocomplete [X] panel overlayed on token [X] alignment [X] keyboard controls up/down @@ -60,7 +47,7 @@ Prototype: [X] escape to close popup [ ] autocomplete icons, markup, widgets, etc -[ ] command view +[:] command view [X] list of collapsible sections [X] host token field [X] context bar by command @@ -79,10 +66,11 @@ Prototype: [X] triggers system, unify with token field triggers a bit? [X] autocomplete a string / command [X] autocomplete empties - [ ] autocomplete commands - [ ] autocomplete filesystem - [ ] autocomplete dir / file distinction - [ ] badge tokens with one/many/command icons + [X] autocomplete commands + [X] autocomplete filesystem ++ [ ] autocomplete label / contents / icon ++ [ ] autocomplete dir / file distinction ++ [ ] badge tokens with one/many/command icons 3) Smart output with selectable things [X] research FastCGI socket protocol @@ -96,12 +84,13 @@ Prototype: [X] list of files [X] file icons [X] implement view DOM v2 with path targeting - [ ] auto-layout mechanism w/ padded max-height on view + [X] auto-layout mechanism w/ padded max-height on view + [ ] intercontrol focus / caret, set up global manager + [ ] tab, switch between widgets. + [ ] working widget callbacks [ ] auto-layout column width (preferred size from widgets + widget variant/style) [ ] make file icons cacheable long-term in webkit cache [ ] stable multi-column layout - [ ] intercontrol focus / caret, set up global manager - [ ] tab, switch between widgets. [ ] smart tab-tabling layout for plain-text 4) NodeKit daemon @@ -118,7 +107,7 @@ Prototype: [X] simplify message format to raw json [X] viewstream integration [ ] arrange pipes for command/view for unix processes - [X] output formatter ++ [X] output formatter [X] full mime header parser/generator [ ] handle encodings [ ] smart binary output