Quellcode durchsuchen

autocompletion support

Benjamin Van Ryseghem vor 11 Jahren
Ursprung
Commit
5331f02b8a

+ 19 - 0
css/helios.css

@@ -254,6 +254,25 @@ a {
     opacity: 0.8;
 }
 
+.key_helper input {
+    outline: none;
+    border: none;
+    font-size: 12px;
+    padding: 2px 4px;
+    background: #EEE;
+}
+
+.key_helper .error .help-inline,
+.key_helper .error input {
+    color: #B91010;
+    font-weight: bold;
+}
+
+.typeahead.dropdown-menu {
+    position: fixed !important;
+    top: auto !important;
+    bottom: 30px !important;
+}
 
 #keybinding-start-helper {
     position: fixed;

+ 13 - 0
js/Helios-Browser.deploy.js

@@ -1558,6 +1558,19 @@ return $1;
 messageSends: ["ifNil:", "new"]}),
 smalltalk.HLBrowserModel);
 
+smalltalk.addMethod(
+"_availableClassNames",
+smalltalk.method({
+selector: "availableClassNames",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._environment())._availableClassNames();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"availableClassNames",{},smalltalk.HLBrowserModel)})},
+messageSends: ["availableClassNames", "environment"]}),
+smalltalk.HLBrowserModel);
+
 smalltalk.addMethod(
 "_compilationProtocol",
 smalltalk.method({

+ 18 - 0
js/Helios-Browser.js

@@ -2028,6 +2028,24 @@ referencedClasses: ["Announcer"]
 }),
 smalltalk.HLBrowserModel);
 
+smalltalk.addMethod(
+"_availableClassNames",
+smalltalk.method({
+selector: "availableClassNames",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._environment())._availableClassNames();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"availableClassNames",{},smalltalk.HLBrowserModel)})},
+args: [],
+source: "availableClassNames\x0a\x09^ self environment availableClassNames",
+messageSends: ["availableClassNames", "environment"],
+referencedClasses: []
+}),
+smalltalk.HLBrowserModel);
+
 smalltalk.addMethod(
 "_compilationProtocol",
 smalltalk.method({

+ 13 - 0
js/Helios-Commands-Browser.deploy.js

@@ -309,6 +309,19 @@ return self}, function($ctx1) {$ctx1.fill(self,"execute",{},smalltalk.HLMoveMeth
 messageSends: ["moveMethodToClass:", "input", "model"]}),
 smalltalk.HLMoveMethodToClassCommand);
 
+smalltalk.addMethod(
+"_inputCompletion",
+smalltalk.method({
+selector: "inputCompletion",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._model())._availableClassNames();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"inputCompletion",{},smalltalk.HLMoveMethodToClassCommand)})},
+messageSends: ["availableClassNames", "model"]}),
+smalltalk.HLMoveMethodToClassCommand);
+
 smalltalk.addMethod(
 "_inputLabel",
 smalltalk.method({

+ 18 - 0
js/Helios-Commands-Browser.js

@@ -434,6 +434,24 @@ referencedClasses: []
 }),
 smalltalk.HLMoveMethodToClassCommand);
 
+smalltalk.addMethod(
+"_inputCompletion",
+smalltalk.method({
+selector: "inputCompletion",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._model())._availableClassNames();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"inputCompletion",{},smalltalk.HLMoveMethodToClassCommand)})},
+args: [],
+source: "inputCompletion\x0a\x09^ self model availableClassNames",
+messageSends: ["availableClassNames", "model"],
+referencedClasses: []
+}),
+smalltalk.HLMoveMethodToClassCommand);
+
 smalltalk.addMethod(
 "_inputLabel",
 smalltalk.method({

+ 26 - 0
js/Helios-Environments.deploy.js

@@ -15,6 +15,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"addInstVarNamed:to:",{aString:aS
 messageSends: ["addSubclassOf:named:instanceVariableNames:package:", "superclass", "name", "add:", "copy", "instanceVariableNames", "yourself", "package", "classBuilder"]}),
 smalltalk.HLEnvironment);
 
+smalltalk.addMethod(
+"_availableClassNames",
+smalltalk.method({
+selector: "availableClassNames",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._subclassResponsibility();
+return self}, function($ctx1) {$ctx1.fill(self,"availableClassNames",{},smalltalk.HLEnvironment)})},
+messageSends: ["subclassResponsibility"]}),
+smalltalk.HLEnvironment);
+
 smalltalk.addMethod(
 "_classBuilder",
 smalltalk.method({
@@ -101,6 +112,21 @@ smalltalk.HLEnvironment);
 
 
 smalltalk.addClass('HLLocalEnvironment', smalltalk.HLEnvironment, [], 'Helios-Environments');
+smalltalk.addMethod(
+"_availableClassNames",
+smalltalk.method({
+selector: "availableClassNames",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._classes())._collect_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(each)._name();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"availableClassNames",{},smalltalk.HLLocalEnvironment)})},
+messageSends: ["collect:", "name", "classes", "current"]}),
+smalltalk.HLLocalEnvironment);
+
 smalltalk.addMethod(
 "_classBuilder",
 smalltalk.method({

+ 36 - 0
js/Helios-Environments.js

@@ -21,6 +21,22 @@ referencedClasses: []
 }),
 smalltalk.HLEnvironment);
 
+smalltalk.addMethod(
+"_availableClassNames",
+smalltalk.method({
+selector: "availableClassNames",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._subclassResponsibility();
+return self}, function($ctx1) {$ctx1.fill(self,"availableClassNames",{},smalltalk.HLEnvironment)})},
+args: [],
+source: "availableClassNames\x0a\x09self subclassResponsibility",
+messageSends: ["subclassResponsibility"],
+referencedClasses: []
+}),
+smalltalk.HLEnvironment);
+
 smalltalk.addMethod(
 "_classBuilder",
 smalltalk.method({
@@ -142,6 +158,26 @@ smalltalk.HLEnvironment);
 
 
 smalltalk.addClass('HLLocalEnvironment', smalltalk.HLEnvironment, [], 'Helios-Environments');
+smalltalk.addMethod(
+"_availableClassNames",
+smalltalk.method({
+selector: "availableClassNames",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._classes())._collect_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(each)._name();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"availableClassNames",{},smalltalk.HLLocalEnvironment)})},
+args: [],
+source: "availableClassNames\x0a\x09^ Smalltalk current classes \x0a\x09\x09collect: [ :each | each name ]",
+messageSends: ["collect:", "name", "classes", "current"],
+referencedClasses: ["Smalltalk"]
+}),
+smalltalk.HLLocalEnvironment);
+
 smalltalk.addMethod(
 "_classBuilder",
 smalltalk.method({

+ 84 - 42
js/Helios-KeyBindings.deploy.js

@@ -236,6 +236,7 @@ return smalltalk.withContext(function($ctx1) { 
var $2,$3,$4,$5,$1;
 $2=_st((smalltalk.HLBindingInput || HLBindingInput))._new();
 _st($2)._label_(_st(_st(self)._command())._inputLabel());
 _st($2)._ghostText_(_st(_st(self)._command())._displayLabel());
+_st($2)._inputCompletion_(_st(_st(self)._command())._inputCompletion());
 _st($2)._callback_((function(val){
 return smalltalk.withContext(function($ctx2) {
$3=_st(self)._command();
 _st($3)._input_(val);
@@ -246,7 +247,7 @@ $5=_st($2)._yourself();
 $1=$5;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"inputBinding",{},smalltalk.HLBindingAction)})},
-messageSends: ["label:", "inputLabel", "command", "new", "ghostText:", "displayLabel", "callback:", "input:", "execute", "yourself"]}),
+messageSends: ["label:", "inputLabel", "command", "new", "ghostText:", "displayLabel", "inputCompletion:", "inputCompletion", "callback:", "input:", "execute", "yourself"]}),
 smalltalk.HLBindingAction);
 
 smalltalk.addMethod(
@@ -462,7 +463,7 @@ smalltalk.HLBindingGroup);
 
 
 
-smalltalk.addClass('HLBindingInput', smalltalk.HLBinding, ['input', 'callback', 'status', 'inputText', 'wrapper', 'binder', 'ghostText', 'isFinal'], 'Helios-KeyBindings');
+smalltalk.addClass('HLBindingInput', smalltalk.HLBinding, ['input', 'callback', 'status', 'wrapper', 'binder', 'ghostText', 'isFinal', 'message', 'messageTag', 'inputCompletion'], 'Helios-KeyBindings');
 smalltalk.addMethod(
 "_applyOn_",
 smalltalk.method({
@@ -470,10 +471,9 @@ selector: "applyOn:",
 fn: function (aKeyBinder){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._isFinal_(true);
-_st(self)._inputText_(_st(_st(_st(self)._input())._asJQuery())._val());
-_st(self)._evaluate_(_st(self)._inputText());
+_st(self)._evaluate_(_st(_st(_st(self)._input())._asJQuery())._val());
 return self}, function($ctx1) {$ctx1.fill(self,"applyOn:",{aKeyBinder:aKeyBinder},smalltalk.HLBindingInput)})},
-messageSends: ["isFinal:", "inputText:", "val", "asJQuery", "input", "evaluate:", "inputText"]}),
+messageSends: ["isFinal:", "evaluate:", "val", "asJQuery", "input"]}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
@@ -522,6 +522,19 @@ return self}, function($ctx1) {$ctx1.fill(self,"callback:",{aBlock:aBlock},small
 messageSends: []}),
 smalltalk.HLBindingInput);
 
+smalltalk.addMethod(
+"_clearStatus",
+smalltalk.method({
+selector: "clearStatus",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._status_("info");
+_st(self)._message_("");
+_st(self)._refresh();
+return self}, function($ctx1) {$ctx1.fill(self,"clearStatus",{},smalltalk.HLBindingInput)})},
+messageSends: ["status:", "message:", "refresh"]}),
+smalltalk.HLBindingInput);
+
 smalltalk.addMethod(
 "_errorStatus",
 smalltalk.method({
@@ -543,11 +556,15 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st((function(){
 return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._callback())._value_(aString);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._on_do_((smalltalk.Error || Error),(function(ex){
-return smalltalk.withContext(function($ctx2) {
_st(self)._errorStatus();
+return smalltalk.withContext(function($ctx2) {
_st(_st(_st(self)._input())._asJQuery())._one_do_("keydown",(function(){
+return smalltalk.withContext(function($ctx3) {
return _st(self)._clearStatus();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})}));
+_st(self)._message_(_st(ex)._messageText());
+_st(self)._errorStatus();
 return _st(self)._isFinal_(false);
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"evaluate:",{aString:aString},smalltalk.HLBindingInput)})},
-messageSends: ["on:do:", "errorStatus", "isFinal:", "value:", "callback"]}),
+messageSends: ["on:do:", "one:do:", "clearStatus", "asJQuery", "input", "message:", "messageText", "errorStatus", "isFinal:", "value:", "callback"]}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
@@ -588,32 +605,31 @@ messageSends: []}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
-"_inputText",
+"_inputCompletion",
 smalltalk.method({
-selector: "inputText",
+selector: "inputCompletion",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $2,$1;
-$2=self["@inputText"];
+$2=self["@inputCompletion"];
 if(($receiver = $2) == nil || $receiver == undefined){
-self["@inputText"]="";
-$1=self["@inputText"];
+$1=[];
 } else {
 $1=$2;
 };
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"inputText",{},smalltalk.HLBindingInput)})},
+}, function($ctx1) {$ctx1.fill(self,"inputCompletion",{},smalltalk.HLBindingInput)})},
 messageSends: ["ifNil:"]}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
-"_inputText_",
+"_inputCompletion_",
 smalltalk.method({
-selector: "inputText:",
-fn: function (aText){
+selector: "inputCompletion:",
+fn: function (aCollection){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@inputText"]=aText;
-return self}, function($ctx1) {$ctx1.fill(self,"inputText:",{aText:aText},smalltalk.HLBindingInput)})},
+return smalltalk.withContext(function($ctx1) { 
self["@inputCompletion"]=aCollection;
+return self}, function($ctx1) {$ctx1.fill(self,"inputCompletion:",{aCollection:aCollection},smalltalk.HLBindingInput)})},
 messageSends: []}),
 smalltalk.HLBindingInput);
 
@@ -659,21 +675,33 @@ messageSends: []}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
-"_privateRenderOn_html_",
+"_message",
 smalltalk.method({
-selector: "privateRenderOn:html:",
-fn: function (aBinder,html){
+selector: "message",
+fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2;
-$1=_st(html)._input();
-_st($1)._class_("controls");
-_st($1)._type_("text");
-_st($1)._placeholder_(_st(self)._ghostText());
-$2=_st($1)._with_(_st(self)._inputText());
-self["@input"]=$2;
-_st(_st(self["@input"])._asJQuery())._focus();
-return self}, function($ctx1) {$ctx1.fill(self,"privateRenderOn:html:",{aBinder:aBinder,html:html},smalltalk.HLBindingInput)})},
-messageSends: ["class:", "input", "type:", "placeholder:", "ghostText", "with:", "inputText", "focus", "asJQuery"]}),
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@message"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@message"]="";
+$1=self["@message"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"message",{},smalltalk.HLBindingInput)})},
+messageSends: ["ifNil:"]}),
+smalltalk.HLBindingInput);
+
+smalltalk.addMethod(
+"_message_",
+smalltalk.method({
+selector: "message:",
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@message"]=aString;
+return self}, function($ctx1) {$ctx1.fill(self,"message:",{aString:aString},smalltalk.HLBindingInput)})},
+messageSends: []}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
@@ -690,9 +718,10 @@ return $2;
 } else {
 $1;
 };
-_st(self["@wrapper"])._class_(_st("control-group ").__comma(_st(self)._status()));
+_st(self["@wrapper"])._class_(_st(self)._status());
+_st(self["@messageTag"])._contents_(_st(self)._message());
 return self}, function($ctx1) {$ctx1.fill(self,"refresh",{},smalltalk.HLBindingInput)})},
-messageSends: ["ifNil:", "class:", ",", "status"]}),
+messageSends: ["ifNil:", "class:", "status", "contents:", "message"]}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
@@ -713,23 +742,36 @@ smalltalk.addMethod(
 "_renderOn_html_",
 smalltalk.method({
 selector: "renderOn:html:",
-fn: function (aBinder,root){
+fn: function (aBinder,html){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$5,$6,$7,$3;
 self["@binder"]=aBinder;
 $1=self["@wrapper"];
 if(($receiver = $1) == nil || $receiver == undefined){
-self["@wrapper"]=_st(root)._span();
+self["@wrapper"]=_st(html)._span();
 self["@wrapper"];
 } else {
 $1;
 };
-_st(self["@wrapper"])._class_(_st("control-group ").__comma(_st(self)._status()));
-_st((function(html){
-return smalltalk.withContext(function($ctx2) {
return _st(self)._privateRenderOn_html_(self["@binder"],html);
-}, function($ctx2) {$ctx2.fillBlock({html:html},$ctx1)})}))._appendToJQuery_(_st(self["@wrapper"])._asJQuery());
-return self}, function($ctx1) {$ctx1.fill(self,"renderOn:html:",{aBinder:aBinder,root:root},smalltalk.HLBindingInput)})},
-messageSends: ["ifNil:", "span", "class:", ",", "status", "appendToJQuery:", "asJQuery", "privateRenderOn:html:"]}),
+$2=self["@wrapper"];
+_st($2)._class_(_st(self)._status());
+$3=_st($2)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
$4=_st(html)._input();
+_st($4)._placeholder_(_st(self)._ghostText());
+$5=_st($4)._yourself();
+self["@input"]=$5;
+self["@input"];
+_st(_st(self["@input"])._asJQuery())._typeahead_(smalltalk.HashedCollection._fromPairs_([_st("source").__minus_gt(_st(self)._inputCompletion())]));
+$6=_st(html)._span();
+_st($6)._class_("help-inline");
+_st($6)._with_(_st(self)._message());
+$7=_st($6)._yourself();
+self["@messageTag"]=$7;
+return self["@messageTag"];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+_st(_st(self["@input"])._asJQuery())._focus();
+return self}, function($ctx1) {$ctx1.fill(self,"renderOn:html:",{aBinder:aBinder,html:html},smalltalk.HLBindingInput)})},
+messageSends: ["ifNil:", "span", "class:", "status", "with:", "placeholder:", "ghostText", "input", "yourself", "typeahead:", "->", "inputCompletion", "asJQuery", "message", "focus"]}),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(

+ 106 - 54
js/Helios-KeyBindings.js

@@ -322,6 +322,7 @@ return smalltalk.withContext(function($ctx1) { 
var $2,$3,$4,$5,$1;
 $2=_st((smalltalk.HLBindingInput || HLBindingInput))._new();
 _st($2)._label_(_st(_st(self)._command())._inputLabel());
 _st($2)._ghostText_(_st(_st(self)._command())._displayLabel());
+_st($2)._inputCompletion_(_st(_st(self)._command())._inputCompletion());
 _st($2)._callback_((function(val){
 return smalltalk.withContext(function($ctx2) {
$3=_st(self)._command();
 _st($3)._input_(val);
@@ -333,8 +334,8 @@ $1=$5;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"inputBinding",{},smalltalk.HLBindingAction)})},
 args: [],
-source: "inputBinding\x0a\x09^ HLBindingInput new\x0a\x09\x09label: self command inputLabel;\x0a\x09\x09ghostText: self command displayLabel;\x0a\x09\x09callback: [ :val | \x0a\x09\x09\x09self command \x0a\x09\x09\x09\x09input: val;\x0a\x09\x09\x09\x09execute ];\x0a\x09\x09yourself",
-messageSends: ["label:", "inputLabel", "command", "new", "ghostText:", "displayLabel", "callback:", "input:", "execute", "yourself"],
+source: "inputBinding\x0a\x09^ HLBindingInput new\x0a\x09\x09label: self command inputLabel;\x0a\x09\x09ghostText: self command displayLabel;\x0a\x09\x09inputCompletion: self command inputCompletion;\x0a\x09\x09callback: [ :val | \x0a\x09\x09\x09self command \x0a\x09\x09\x09\x09input: val;\x0a\x09\x09\x09\x09execute ];\x0a\x09\x09yourself",
+messageSends: ["label:", "inputLabel", "command", "new", "ghostText:", "displayLabel", "inputCompletion:", "inputCompletion", "callback:", "input:", "execute", "yourself"],
 referencedClasses: ["HLBindingInput"]
 }),
 smalltalk.HLBindingAction);
@@ -622,7 +623,7 @@ smalltalk.HLBindingGroup);
 
 
 
-smalltalk.addClass('HLBindingInput', smalltalk.HLBinding, ['input', 'callback', 'status', 'inputText', 'wrapper', 'binder', 'ghostText', 'isFinal'], 'Helios-KeyBindings');
+smalltalk.addClass('HLBindingInput', smalltalk.HLBinding, ['input', 'callback', 'status', 'wrapper', 'binder', 'ghostText', 'isFinal', 'message', 'messageTag', 'inputCompletion'], 'Helios-KeyBindings');
 smalltalk.addMethod(
 "_applyOn_",
 smalltalk.method({
@@ -631,12 +632,11 @@ category: 'actions',
 fn: function (aKeyBinder){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._isFinal_(true);
-_st(self)._inputText_(_st(_st(_st(self)._input())._asJQuery())._val());
-_st(self)._evaluate_(_st(self)._inputText());
+_st(self)._evaluate_(_st(_st(_st(self)._input())._asJQuery())._val());
 return self}, function($ctx1) {$ctx1.fill(self,"applyOn:",{aKeyBinder:aKeyBinder},smalltalk.HLBindingInput)})},
 args: ["aKeyBinder"],
-source: "applyOn: aKeyBinder\x0a\x0a\x09self isFinal: true.\x0a\x09self inputText: self input asJQuery val.\x0a\x09self evaluate: self inputText",
-messageSends: ["isFinal:", "inputText:", "val", "asJQuery", "input", "evaluate:", "inputText"],
+source: "applyOn: aKeyBinder\x0a\x09self isFinal: true.\x0a\x09self evaluate: self input asJQuery val",
+messageSends: ["isFinal:", "evaluate:", "val", "asJQuery", "input"],
 referencedClasses: []
 }),
 smalltalk.HLBindingInput);
@@ -702,6 +702,24 @@ referencedClasses: []
 }),
 smalltalk.HLBindingInput);
 
+smalltalk.addMethod(
+"_clearStatus",
+smalltalk.method({
+selector: "clearStatus",
+category: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._status_("info");
+_st(self)._message_("");
+_st(self)._refresh();
+return self}, function($ctx1) {$ctx1.fill(self,"clearStatus",{},smalltalk.HLBindingInput)})},
+args: [],
+source: "clearStatus\x0a\x09self status: 'info'.\x0a\x09self message: ''.\x0a\x09self refresh",
+messageSends: ["status:", "message:", "refresh"],
+referencedClasses: []
+}),
+smalltalk.HLBindingInput);
+
 smalltalk.addMethod(
 "_errorStatus",
 smalltalk.method({
@@ -729,13 +747,17 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st((function(){
 return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._callback())._value_(aString);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._on_do_((smalltalk.Error || Error),(function(ex){
-return smalltalk.withContext(function($ctx2) {
_st(self)._errorStatus();
+return smalltalk.withContext(function($ctx2) {
_st(_st(_st(self)._input())._asJQuery())._one_do_("keydown",(function(){
+return smalltalk.withContext(function($ctx3) {
return _st(self)._clearStatus();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})}));
+_st(self)._message_(_st(ex)._messageText());
+_st(self)._errorStatus();
 return _st(self)._isFinal_(false);
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"evaluate:",{aString:aString},smalltalk.HLBindingInput)})},
 args: ["aString"],
-source: "evaluate: aString\x0a\x09\x0a\x09[ self callback value: aString ]\x0a\x09on: Error\x0a\x09do: [:ex | \x0a\x09\x09self errorStatus.\x0a\x09\x09self isFinal: false ].",
-messageSends: ["on:do:", "errorStatus", "isFinal:", "value:", "callback"],
+source: "evaluate: aString\x0a\x09\x0a\x09[ self callback value: aString ]\x0a\x09on: Error\x0a\x09do: [:ex |\x0a\x09\x09self input asJQuery \x0a\x09\x09\x09one: 'keydown' \x0a\x09\x09\x09do: [ self clearStatus ].\x0a\x09\x09self message: ex messageText.\x0a\x09\x09self errorStatus.\x0a\x09\x09self isFinal: false ].",
+messageSends: ["on:do:", "one:do:", "clearStatus", "asJQuery", "input", "message:", "messageText", "errorStatus", "isFinal:", "value:", "callback"],
 referencedClasses: ["Error"]
 }),
 smalltalk.HLBindingInput);
@@ -793,40 +815,39 @@ referencedClasses: []
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
-"_inputText",
+"_inputCompletion",
 smalltalk.method({
-selector: "inputText",
+selector: "inputCompletion",
 category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $2,$1;
-$2=self["@inputText"];
+$2=self["@inputCompletion"];
 if(($receiver = $2) == nil || $receiver == undefined){
-self["@inputText"]="";
-$1=self["@inputText"];
+$1=[];
 } else {
 $1=$2;
 };
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"inputText",{},smalltalk.HLBindingInput)})},
+}, function($ctx1) {$ctx1.fill(self,"inputCompletion",{},smalltalk.HLBindingInput)})},
 args: [],
-source: "inputText\x0a\x09^ inputText ifNil: [ inputText := '' ].",
+source: "inputCompletion\x0a\x09^ inputCompletion ifNil: [ #() ]",
 messageSends: ["ifNil:"],
 referencedClasses: []
 }),
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
-"_inputText_",
+"_inputCompletion_",
 smalltalk.method({
-selector: "inputText:",
+selector: "inputCompletion:",
 category: 'accessing',
-fn: function (aText){
+fn: function (aCollection){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@inputText"]=aText;
-return self}, function($ctx1) {$ctx1.fill(self,"inputText:",{aText:aText},smalltalk.HLBindingInput)})},
-args: ["aText"],
-source: "inputText: aText\x0a\x09inputText := aText",
+return smalltalk.withContext(function($ctx1) { 
self["@inputCompletion"]=aCollection;
+return self}, function($ctx1) {$ctx1.fill(self,"inputCompletion:",{aCollection:aCollection},smalltalk.HLBindingInput)})},
+args: ["aCollection"],
+source: "inputCompletion: aCollection\x0a\x09inputCompletion := aCollection",
 messageSends: [],
 referencedClasses: []
 }),
@@ -889,24 +910,41 @@ referencedClasses: []
 smalltalk.HLBindingInput);
 
 smalltalk.addMethod(
-"_privateRenderOn_html_",
+"_message",
 smalltalk.method({
-selector: "privateRenderOn:html:",
-category: 'rendering',
-fn: function (aBinder,html){
+selector: "message",
+category: 'accessing',
+fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2;
-$1=_st(html)._input();
-_st($1)._class_("controls");
-_st($1)._type_("text");
-_st($1)._placeholder_(_st(self)._ghostText());
-$2=_st($1)._with_(_st(self)._inputText());
-self["@input"]=$2;
-_st(_st(self["@input"])._asJQuery())._focus();
-return self}, function($ctx1) {$ctx1.fill(self,"privateRenderOn:html:",{aBinder:aBinder,html:html},smalltalk.HLBindingInput)})},
-args: ["aBinder", "html"],
-source: "privateRenderOn: aBinder html: html\x0a\x09input := html input\x0a\x09\x09class: 'controls';\x0a\x09\x09type: 'text';\x0a\x09\x09placeholder: self ghostText;\x0a\x09\x09with: self inputText.\x0a\x09\x09\x09\x0a\x09input asJQuery focus",
-messageSends: ["class:", "input", "type:", "placeholder:", "ghostText", "with:", "inputText", "focus", "asJQuery"],
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@message"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@message"]="";
+$1=self["@message"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"message",{},smalltalk.HLBindingInput)})},
+args: [],
+source: "message\x0a\x09^ message ifNil: [ message := '' ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.HLBindingInput);
+
+smalltalk.addMethod(
+"_message_",
+smalltalk.method({
+selector: "message:",
+category: 'accessing',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@message"]=aString;
+return self}, function($ctx1) {$ctx1.fill(self,"message:",{aString:aString},smalltalk.HLBindingInput)})},
+args: ["aString"],
+source: "message: aString\x0a\x09message := aString",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.HLBindingInput);
@@ -926,11 +964,12 @@ return $2;
 } else {
 $1;
 };
-_st(self["@wrapper"])._class_(_st("control-group ").__comma(_st(self)._status()));
+_st(self["@wrapper"])._class_(_st(self)._status());
+_st(self["@messageTag"])._contents_(_st(self)._message());
 return self}, function($ctx1) {$ctx1.fill(self,"refresh",{},smalltalk.HLBindingInput)})},
 args: [],
-source: "refresh\x0a\x09wrapper ifNil: [ ^ self ].\x0a    \x0a\x09wrapper class: 'control-group ', self status.",
-messageSends: ["ifNil:", "class:", ",", "status"],
+source: "refresh\x0a\x09wrapper ifNil: [ ^ self ].\x0a    \x0a\x09wrapper class: self status.\x0a\x09messageTag contents: self message",
+messageSends: ["ifNil:", "class:", "status", "contents:", "message"],
 referencedClasses: []
 }),
 smalltalk.HLBindingInput);
@@ -959,25 +998,38 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "renderOn:html:",
 category: 'rendering',
-fn: function (aBinder,root){
+fn: function (aBinder,html){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$5,$6,$7,$3;
 self["@binder"]=aBinder;
 $1=self["@wrapper"];
 if(($receiver = $1) == nil || $receiver == undefined){
-self["@wrapper"]=_st(root)._span();
+self["@wrapper"]=_st(html)._span();
 self["@wrapper"];
 } else {
 $1;
 };
-_st(self["@wrapper"])._class_(_st("control-group ").__comma(_st(self)._status()));
-_st((function(html){
-return smalltalk.withContext(function($ctx2) {
return _st(self)._privateRenderOn_html_(self["@binder"],html);
-}, function($ctx2) {$ctx2.fillBlock({html:html},$ctx1)})}))._appendToJQuery_(_st(self["@wrapper"])._asJQuery());
-return self}, function($ctx1) {$ctx1.fill(self,"renderOn:html:",{aBinder:aBinder,root:root},smalltalk.HLBindingInput)})},
-args: ["aBinder", "root"],
-source: "renderOn: aBinder html: root\x0a\x09binder := aBinder.\x0a\x09wrapper ifNil: [ wrapper := root span ].\x0a\x09\x0a\x09wrapper class: 'control-group ', self status.\x0a\x09\x0a\x09[:html | self privateRenderOn: binder html: html ] appendToJQuery: wrapper asJQuery",
-messageSends: ["ifNil:", "span", "class:", ",", "status", "appendToJQuery:", "asJQuery", "privateRenderOn:html:"],
+$2=self["@wrapper"];
+_st($2)._class_(_st(self)._status());
+$3=_st($2)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
$4=_st(html)._input();
+_st($4)._placeholder_(_st(self)._ghostText());
+$5=_st($4)._yourself();
+self["@input"]=$5;
+self["@input"];
+_st(_st(self["@input"])._asJQuery())._typeahead_(smalltalk.HashedCollection._fromPairs_([_st("source").__minus_gt(_st(self)._inputCompletion())]));
+$6=_st(html)._span();
+_st($6)._class_("help-inline");
+_st($6)._with_(_st(self)._message());
+$7=_st($6)._yourself();
+self["@messageTag"]=$7;
+return self["@messageTag"];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+_st(_st(self["@input"])._asJQuery())._focus();
+return self}, function($ctx1) {$ctx1.fill(self,"renderOn:html:",{aBinder:aBinder,html:html},smalltalk.HLBindingInput)})},
+args: ["aBinder", "html"],
+source: "renderOn: aBinder html: html\x0a\x09binder := aBinder.\x0a\x09wrapper ifNil: [ wrapper := html span ].\x0a\x09\x0a\x09wrapper \x0a\x09\x09class: self status;\x0a\x09\x09with: [\x0a\x09\x09\x09input := html input\x0a\x09\x09\x09\x09placeholder: self ghostText;\x0a\x09\x09\x09\x09yourself.\x0a\x09\x09\x09input asJQuery \x0a\x09\x09\x09\x09typeahead: #{ 'source' -> self inputCompletion }.\x0a\x09\x09\x09messageTag := (html span\x0a\x09\x09\x09\x09class: 'help-inline';\x0a\x09\x09\x09\x09with: self message;\x0a\x09\x09\x09\x09yourself) ].\x0a\x09\x09\x09\x0a\x09input asJQuery focus\x0a",
+messageSends: ["ifNil:", "span", "class:", "status", "with:", "placeholder:", "ghostText", "input", "yourself", "typeahead:", "->", "inputCompletion", "asJQuery", "message", "focus"],
 referencedClasses: []
 }),
 smalltalk.HLBindingInput);

+ 4 - 0
st/Helios-Browser.st

@@ -705,6 +705,10 @@ announcer
 	^ announcer ifNil: [ announcer := Announcer new ]
 !
 
+availableClassNames
+	^ self environment availableClassNames
+!
+
 environment
 	^ environment ifNil: [ HLManager current environment ]
 !

+ 4 - 0
st/Helios-Commands-Browser.st

@@ -179,6 +179,10 @@ displayLabel
 	^ 'select a class'
 !
 
+inputCompletion
+	^ self model availableClassNames
+!
+
 inputLabel
 	^ 'Move method to class:'
 ! !

+ 9 - 0
st/Helios-Environments.st

@@ -7,6 +7,10 @@ Abstract class defining common behavior for local and remote environments!
 
 !HLEnvironment methodsFor: 'accessing'!
 
+availableClassNames
+	self subclassResponsibility
+!
+
 classBuilder
 	^ self subclassResponsibility
 !
@@ -56,6 +60,11 @@ HLEnvironment subclass: #HLLocalEnvironment
 
 !HLLocalEnvironment methodsFor: 'accessing'!
 
+availableClassNames
+	^ Smalltalk current classes 
+		collect: [ :each | each name ]
+!
+
 classBuilder
 	^ ClassBuilder new
 !

+ 44 - 25
st/Helios-KeyBindings.st

@@ -96,6 +96,7 @@ inputBinding
 	^ HLBindingInput new
 		label: self command inputLabel;
 		ghostText: self command displayLabel;
+		inputCompletion: self command inputCompletion;
 		callback: [ :val | 
 			self command 
 				input: val;
@@ -194,7 +195,7 @@ isActive
 ! !
 
 HLBinding subclass: #HLBindingInput
-	instanceVariableNames: 'input callback status inputText wrapper binder ghostText isFinal'
+	instanceVariableNames: 'input callback status wrapper binder ghostText isFinal message messageTag inputCompletion'
 	package: 'Helios-KeyBindings'!
 
 !HLBindingInput methodsFor: 'accessing'!
@@ -223,12 +224,20 @@ input
 	^ input
 !
 
-inputText
-	^ inputText ifNil: [ inputText := '' ].
+inputCompletion
+	^ inputCompletion ifNil: [ #() ]
 !
 
-inputText: aText
-	inputText := aText
+inputCompletion: aCollection
+	inputCompletion := aCollection
+!
+
+message
+	^ message ifNil: [ message := '' ]
+!
+
+message: aString
+	message := aString
 !
 
 status
@@ -242,10 +251,14 @@ status: aStatus
 !HLBindingInput methodsFor: 'actions'!
 
 applyOn: aKeyBinder
-
 	self isFinal: true.
-	self inputText: self input asJQuery val.
-	self evaluate: self inputText
+	self evaluate: self input asJQuery val
+!
+
+clearStatus
+	self status: 'info'.
+	self message: ''.
+	self refresh
 !
 
 errorStatus
@@ -257,7 +270,11 @@ evaluate: aString
 	
 	[ self callback value: aString ]
 	on: Error
-	do: [:ex | 
+	do: [:ex |
+		self input asJQuery 
+			one: 'keydown' 
+			do: [ self clearStatus ].
+		self message: ex messageText.
 		self errorStatus.
 		self isFinal: false ].
 !
@@ -271,29 +288,31 @@ release
 
 !HLBindingInput methodsFor: 'rendering'!
 
-privateRenderOn: aBinder html: html
-	input := html input
-		class: 'controls';
-		type: 'text';
-		placeholder: self ghostText;
-		with: self inputText.
-			
-	input asJQuery focus
-!
-
 refresh
 	wrapper ifNil: [ ^ self ].
     
-	wrapper class: 'control-group ', self status.
+	wrapper class: self status.
+	messageTag contents: self message
 !
 
-renderOn: aBinder html: root
+renderOn: aBinder html: html
 	binder := aBinder.
-	wrapper ifNil: [ wrapper := root span ].
+	wrapper ifNil: [ wrapper := html span ].
 	
-	wrapper class: 'control-group ', self status.
-	
-	[:html | self privateRenderOn: binder html: html ] appendToJQuery: wrapper asJQuery
+	wrapper 
+		class: self status;
+		with: [
+			input := html input
+				placeholder: self ghostText;
+				yourself.
+			input asJQuery 
+				typeahead: #{ 'source' -> self inputCompletion }.
+			messageTag := (html span
+				class: 'help-inline';
+				with: self message;
+				yourself) ].
+			
+	input asJQuery focus
 ! !
 
 !HLBindingInput methodsFor: 'testing'!