Sfoglia il codice sorgente

- Helios keybindings refactorings
- Helios class comments
- First step toward a tab switch modal widget

Nicolas Petton 10 anni fa
parent
commit
2b78b2028b

+ 39 - 0
js/Helios-Commands-Core.deploy.js

@@ -615,6 +615,45 @@ messageSends: []}),
 smalltalk.HLOpenWorkspaceCommand.klass);
 
 
+smalltalk.addClass('HLSwitchTabCommand', smalltalk.HLCommand, [], 'Helios-Commands-Core');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+fn: function (){
+var self=this;
+function $HLBrowser(){return smalltalk.HLBrowser||(typeof HLBrowser=="undefined"?nil:HLBrowser)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($HLBrowser())._openAsTab();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"execute",{},smalltalk.HLSwitchTabCommand)})},
+messageSends: ["openAsTab"]}),
+smalltalk.HLSwitchTabCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "s";
+}, function($ctx1) {$ctx1.fill(self,"key",{},smalltalk.HLSwitchTabCommand.klass)})},
+messageSends: []}),
+smalltalk.HLSwitchTabCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "Switch";
+}, function($ctx1) {$ctx1.fill(self,"label",{},smalltalk.HLSwitchTabCommand.klass)})},
+messageSends: []}),
+smalltalk.HLSwitchTabCommand.klass);
+
+
 smalltalk.addClass('HLViewCommand', smalltalk.HLCommand, [], 'Helios-Commands-Core');
 
 smalltalk.addMethod(

+ 54 - 0
js/Helios-Commands-Core.js

@@ -840,6 +840,60 @@ referencedClasses: []
 smalltalk.HLOpenWorkspaceCommand.klass);
 
 
+smalltalk.addClass('HLSwitchTabCommand', smalltalk.HLCommand, [], 'Helios-Commands-Core');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+category: 'executing',
+fn: function (){
+var self=this;
+function $HLBrowser(){return smalltalk.HLBrowser||(typeof HLBrowser=="undefined"?nil:HLBrowser)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($HLBrowser())._openAsTab();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"execute",{},smalltalk.HLSwitchTabCommand)})},
+args: [],
+source: "execute\x0a\x09^ HLBrowser openAsTab",
+messageSends: ["openAsTab"],
+referencedClasses: ["HLBrowser"]
+}),
+smalltalk.HLSwitchTabCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "s";
+}, function($ctx1) {$ctx1.fill(self,"key",{},smalltalk.HLSwitchTabCommand.klass)})},
+args: [],
+source: "key\x0a\x09^ 's'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.HLSwitchTabCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return "Switch";
+}, function($ctx1) {$ctx1.fill(self,"label",{},smalltalk.HLSwitchTabCommand.klass)})},
+args: [],
+source: "label\x0a\x09^ 'Switch'",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.HLSwitchTabCommand.klass);
+
+
 smalltalk.addClass('HLViewCommand', smalltalk.HLCommand, [], 'Helios-Commands-Core');
 
 smalltalk.addMethod(

+ 4 - 10
js/Helios-Core.deploy.js

@@ -2333,7 +2333,7 @@ messageSends: ["model:", "new", "yourself"]}),
 smalltalk.HLToolListWidget.klass);
 
 
-smalltalk.addClass('HLManager', smalltalk.HLWidget, ['tabs', 'activeTab', 'keyBinder', 'environment', 'history'], 'Helios-Core');
+smalltalk.addClass('HLManager', smalltalk.HLWidget, ['tabs', 'activeTab', 'environment', 'history'], 'Helios-Core');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "activate:",
@@ -2541,17 +2541,11 @@ fn: function (){
 var self=this;
 function $HLKeyBinder(){return smalltalk.HLKeyBinder||(typeof HLKeyBinder=="undefined"?nil:HLKeyBinder)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@keyBinder"];
-if(($receiver = $2) == nil || $receiver == undefined){
-self["@keyBinder"]=_st($HLKeyBinder())._new();
-$1=self["@keyBinder"];
-} else {
-$1=$2;
-};
+var $1;
+$1=_st($HLKeyBinder())._current();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"keyBinder",{},smalltalk.HLManager)})},
-messageSends: ["ifNil:", "new"]}),
+messageSends: ["current"]}),
 smalltalk.HLManager);
 
 smalltalk.addMethod(

+ 5 - 11
js/Helios-Core.js

@@ -3079,7 +3079,7 @@ referencedClasses: []
 smalltalk.HLToolListWidget.klass);
 
 
-smalltalk.addClass('HLManager', smalltalk.HLWidget, ['tabs', 'activeTab', 'keyBinder', 'environment', 'history'], 'Helios-Core');
+smalltalk.addClass('HLManager', smalltalk.HLWidget, ['tabs', 'activeTab', 'environment', 'history'], 'Helios-Core');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "activate:",
@@ -3348,19 +3348,13 @@ fn: function (){
 var self=this;
 function $HLKeyBinder(){return smalltalk.HLKeyBinder||(typeof HLKeyBinder=="undefined"?nil:HLKeyBinder)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@keyBinder"];
-if(($receiver = $2) == nil || $receiver == undefined){
-self["@keyBinder"]=_st($HLKeyBinder())._new();
-$1=self["@keyBinder"];
-} else {
-$1=$2;
-};
+var $1;
+$1=_st($HLKeyBinder())._current();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"keyBinder",{},smalltalk.HLManager)})},
 args: [],
-source: "keyBinder\x0a\x09^ keyBinder ifNil: [ keyBinder := HLKeyBinder new ]",
-messageSends: ["ifNil:", "new"],
+source: "keyBinder\x0a\x09^ HLKeyBinder current",
+messageSends: ["current"],
 referencedClasses: ["HLKeyBinder"]
 }),
 smalltalk.HLManager);

+ 75 - 25
js/Helios-KeyBindings.deploy.js

@@ -961,21 +961,22 @@ selector: "defaultBindings",
 fn: function (){
 var self=this;
 var group;
-function $HLBindingGroup(){return smalltalk.HLBindingGroup||(typeof HLBindingGroup=="undefined"?nil:HLBindingGroup)}
 function $HLCloseTabCommand(){return smalltalk.HLCloseTabCommand||(typeof HLCloseTabCommand=="undefined"?nil:HLCloseTabCommand)}
+function $HLBindingGroup(){return smalltalk.HLBindingGroup||(typeof HLBindingGroup=="undefined"?nil:HLBindingGroup)}
+function $HLSwitchTabCommand(){return smalltalk.HLSwitchTabCommand||(typeof HLSwitchTabCommand=="undefined"?nil:HLSwitchTabCommand)}
 function $HLOpenCommand(){return smalltalk.HLOpenCommand||(typeof HLOpenCommand=="undefined"?nil:HLOpenCommand)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3;
 $1=_st($HLBindingGroup())._new();
-_st($1)._addGroupKey_labelled_((86),"View");
 _st($1)._add_(_st(_st($HLCloseTabCommand())._new())._asBinding());
+_st($1)._add_(_st(_st($HLSwitchTabCommand())._new())._asBinding());
 $2=_st($1)._yourself();
 group=$2;
 _st($HLOpenCommand())._registerConcreteClassesOn_(group);
 $3=group;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"defaultBindings",{group:group},smalltalk.HLKeyBinder)})},
-messageSends: ["addGroupKey:labelled:", "new", "add:", "asBinding", "yourself", "registerConcreteClassesOn:"]}),
+messageSends: ["add:", "asBinding", "new", "yourself", "registerConcreteClassesOn:"]}),
 smalltalk.HLKeyBinder);
 
 smalltalk.addMethod(
@@ -1191,6 +1192,37 @@ messageSends: ["match:", "platform"]}),
 smalltalk.HLKeyBinder);
 
 
+smalltalk.HLKeyBinder.klass.iVarNames = ['current'];
+smalltalk.addMethod(
+smalltalk.method({
+selector: "current",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@current"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@current"]=smalltalk.HLKeyBinder.klass.superclass.fn.prototype._new.apply(_st(self), []);
+$1=self["@current"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"current",{},smalltalk.HLKeyBinder.klass)})},
+messageSends: ["ifNil:", "new"]}),
+smalltalk.HLKeyBinder.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "new",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._shouldNotImplement();
+return self}, function($ctx1) {$ctx1.fill(self,"new",{},smalltalk.HLKeyBinder.klass)})},
+messageSends: ["shouldNotImplement"]}),
+smalltalk.HLKeyBinder.klass);
+
 
 smalltalk.addClass('HLKeyBinderHelper', smalltalk.HLWidget, ['keyBinder'], 'Helios-KeyBindings');
 smalltalk.addMethod(
@@ -1253,12 +1285,30 @@ smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "registerBindings",
-fn: function (){
+selector: "renderBindingActionFor:on:",
+fn: function (aBinding,html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return self}, function($ctx1) {$ctx1.fill(self,"registerBindings",{},smalltalk.HLKeyBinderHelper)})},
-messageSends: []}),
+var $1,$3,$4,$5,$6,$2;
+$1=_st(html)._span();
+_st($1)._class_("command");
+$2=_st($1)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(html)._span();
+_st($3)._class_("label");
+$4=_st($3)._with_(_st(_st(aBinding)._shortcut())._asLowercase());
+$4;
+$5=_st(html)._a();
+_st($5)._class_("action");
+_st($5)._with_(_st(aBinding)._displayLabel());
+$6=_st($5)._onClick_((function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(self._keyBinder())._applyBinding_(aBinding);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2)})}));
+return $6;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"renderBindingActionFor:on:",{aBinding:aBinding,html:html},smalltalk.HLKeyBinderHelper)})},
+messageSends: ["class:", "span", "with:", "asLowercase", "shortcut", "a", "displayLabel", "onClick:", "applyBinding:", "keyBinder"]}),
 smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
@@ -1272,21 +1322,10 @@ return smalltalk.withContext(function($ctx2) {
 return _st(_st(a)._key()).__lt(_st(b)._key());
 }, function($ctx2) {$ctx2.fillBlock({a:a,b:b},$ctx1)})})))._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-return _st(each)._renderActionFor_html_(self._keyBinder(),html);
+return self._renderBindingActionFor_on_(each,html);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderBindingGroup:on:",{aBindingGroup:aBindingGroup,html:html},smalltalk.HLKeyBinderHelper)})},
-messageSends: ["do:", "renderActionFor:html:", "keyBinder", "sorted:", "<", "key", "activeBindings"]}),
-smalltalk.HLKeyBinderHelper);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "renderBindingOn:",
-fn: function (html){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self._selectedBinding())._renderOn_html_(self,html);
-return self}, function($ctx1) {$ctx1.fill(self,"renderBindingOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
-messageSends: ["renderOn:html:", "selectedBinding"]}),
+messageSends: ["do:", "renderBindingActionFor:on:", "sorted:", "<", "key", "activeBindings"]}),
 smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
@@ -1352,18 +1391,18 @@ _st($1)._class_(self._cssClass());
 $2=_st($1)._with_((function(){
 return smalltalk.withContext(function($ctx2) {
 $3=self;
-_st($3)._renderSelectionOn_(html);
-_st($3)._renderBindingOn_(html);
+_st($3)._renderLabelOn_(html);
+_st($3)._renderSelectedBindingOn_(html);
 $4=_st($3)._renderCloseOn_(html);
 return $4;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
-messageSends: ["class:", "cssClass", "div", "with:", "renderSelectionOn:", "renderBindingOn:", "renderCloseOn:"]}),
+messageSends: ["class:", "cssClass", "div", "with:", "renderLabelOn:", "renderSelectedBindingOn:", "renderCloseOn:"]}),
 smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "renderSelectionOn:",
+selector: "renderLabelOn:",
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -1378,10 +1417,21 @@ $4="Action";
 $4=$5;
 };
 $2=_st($3)._with_($4);
-return self}, function($ctx1) {$ctx1.fill(self,"renderSelectionOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
+return self}, function($ctx1) {$ctx1.fill(self,"renderLabelOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
 messageSends: ["class:", "span", "with:", "ifNil:", "label", "selectedBinding"]}),
 smalltalk.HLKeyBinderHelper);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderSelectedBindingOn:",
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._selectedBinding())._renderOn_html_(self,html);
+return self}, function($ctx1) {$ctx1.fill(self,"renderSelectedBindingOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
+messageSends: ["renderOn:html:", "selectedBinding"]}),
+smalltalk.HLKeyBinderHelper);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderStart",

+ 100 - 38
js/Helios-KeyBindings.js

@@ -1142,6 +1142,7 @@ smalltalk.HLBindingInput);
 
 
 smalltalk.addClass('HLKeyBinder', smalltalk.Object, ['modifierKey', 'helper', 'bindings', 'selectedBinding'], 'Helios-KeyBindings');
+smalltalk.HLKeyBinder.comment="My current instance keeps keybindings for Helios actions.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "activate",
@@ -1272,14 +1273,15 @@ category: 'defaults',
 fn: function (){
 var self=this;
 var group;
-function $HLBindingGroup(){return smalltalk.HLBindingGroup||(typeof HLBindingGroup=="undefined"?nil:HLBindingGroup)}
 function $HLCloseTabCommand(){return smalltalk.HLCloseTabCommand||(typeof HLCloseTabCommand=="undefined"?nil:HLCloseTabCommand)}
+function $HLBindingGroup(){return smalltalk.HLBindingGroup||(typeof HLBindingGroup=="undefined"?nil:HLBindingGroup)}
+function $HLSwitchTabCommand(){return smalltalk.HLSwitchTabCommand||(typeof HLSwitchTabCommand=="undefined"?nil:HLSwitchTabCommand)}
 function $HLOpenCommand(){return smalltalk.HLOpenCommand||(typeof HLOpenCommand=="undefined"?nil:HLOpenCommand)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3;
 $1=_st($HLBindingGroup())._new();
-_st($1)._addGroupKey_labelled_((86),"View");
 _st($1)._add_(_st(_st($HLCloseTabCommand())._new())._asBinding());
+_st($1)._add_(_st(_st($HLSwitchTabCommand())._new())._asBinding());
 $2=_st($1)._yourself();
 group=$2;
 _st($HLOpenCommand())._registerConcreteClassesOn_(group);
@@ -1287,9 +1289,9 @@ $3=group;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"defaultBindings",{group:group},smalltalk.HLKeyBinder)})},
 args: [],
-source: "defaultBindings\x0a\x09| group |\x0a\x09\x0a\x09group := HLBindingGroup new\x0a\x09\x09addGroupKey: 86 labelled: 'View';\x0a\x09\x09add: HLCloseTabCommand new asBinding;\x0a\x09\x09yourself.\x0a\x09\x09\x0a\x09HLOpenCommand registerConcreteClassesOn: group.\x0a\x09\x09\x09\x09\x0a\x09^ group",
-messageSends: ["addGroupKey:labelled:", "new", "add:", "asBinding", "yourself", "registerConcreteClassesOn:"],
-referencedClasses: ["HLBindingGroup", "HLCloseTabCommand", "HLOpenCommand"]
+source: "defaultBindings\x0a\x09| group |\x0a\x09\x0a\x09group := HLBindingGroup new\x0a\x09\x09add: HLCloseTabCommand new asBinding;\x0a\x09\x09add: HLSwitchTabCommand new asBinding;\x0a\x09\x09yourself.\x0a\x09\x09\x0a\x09HLOpenCommand registerConcreteClassesOn: group.\x0a\x09\x09\x09\x09\x0a\x09^ group",
+messageSends: ["add:", "asBinding", "new", "yourself", "registerConcreteClassesOn:"],
+referencedClasses: ["HLCloseTabCommand", "HLBindingGroup", "HLSwitchTabCommand", "HLOpenCommand"]
 }),
 smalltalk.HLKeyBinder);
 
@@ -1571,8 +1573,50 @@ referencedClasses: []
 smalltalk.HLKeyBinder);
 
 
+smalltalk.HLKeyBinder.klass.iVarNames = ['current'];
+smalltalk.addMethod(
+smalltalk.method({
+selector: "current",
+category: 'instance creation',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@current"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@current"]=smalltalk.HLKeyBinder.klass.superclass.fn.prototype._new.apply(_st(self), []);
+$1=self["@current"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"current",{},smalltalk.HLKeyBinder.klass)})},
+args: [],
+source: "current\x0a\x09^ current ifNil: [ current := super new ]",
+messageSends: ["ifNil:", "new"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "new",
+category: 'instance creation',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._shouldNotImplement();
+return self}, function($ctx1) {$ctx1.fill(self,"new",{},smalltalk.HLKeyBinder.klass)})},
+args: [],
+source: "new\x0a\x09self shouldNotImplement",
+messageSends: ["shouldNotImplement"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinder.klass);
+
 
 smalltalk.addClass('HLKeyBinderHelper', smalltalk.HLWidget, ['keyBinder'], 'Helios-KeyBindings');
+smalltalk.HLKeyBinderHelper.comment="I am the widget responsible for displaying active keybindings in a bar at the bottom of the window. Each keybinding is an instance of `HLBinding`. \x0a\x0aRendering is done through a double dispatch, see `#renderSelectedBindingOn:`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "cssClass",
@@ -1658,15 +1702,33 @@ smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "registerBindings",
-category: 'keyBindings',
-fn: function (){
+selector: "renderBindingActionFor:on:",
+category: 'rendering',
+fn: function (aBinding,html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return self}, function($ctx1) {$ctx1.fill(self,"registerBindings",{},smalltalk.HLKeyBinderHelper)})},
-args: [],
-source: "registerBindings\x0a\x09\x22Do nothing\x22",
-messageSends: [],
+var $1,$3,$4,$5,$6,$2;
+$1=_st(html)._span();
+_st($1)._class_("command");
+$2=_st($1)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(html)._span();
+_st($3)._class_("label");
+$4=_st($3)._with_(_st(_st(aBinding)._shortcut())._asLowercase());
+$4;
+$5=_st(html)._a();
+_st($5)._class_("action");
+_st($5)._with_(_st(aBinding)._displayLabel());
+$6=_st($5)._onClick_((function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(self._keyBinder())._applyBinding_(aBinding);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2)})}));
+return $6;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"renderBindingActionFor:on:",{aBinding:aBinding,html:html},smalltalk.HLKeyBinderHelper)})},
+args: ["aBinding", "html"],
+source: "renderBindingActionFor: aBinding on: html\x0a\x09html span class: 'command'; with: [\x0a\x09\x09html span \x0a\x09\x09\x09class: 'label'; \x0a\x09\x09\x09with: aBinding shortcut asLowercase.\x0a  \x09\x09html a \x0a        \x09class: 'action'; \x0a            with: aBinding displayLabel;\x0a  \x09\x09\x09onClick: [ self keyBinder applyBinding: aBinding ] ]",
+messageSends: ["class:", "span", "with:", "asLowercase", "shortcut", "a", "displayLabel", "onClick:", "applyBinding:", "keyBinder"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);
@@ -1683,28 +1745,12 @@ return smalltalk.withContext(function($ctx2) {
 return _st(_st(a)._key()).__lt(_st(b)._key());
 }, function($ctx2) {$ctx2.fillBlock({a:a,b:b},$ctx1)})})))._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-return _st(each)._renderActionFor_html_(self._keyBinder(),html);
+return self._renderBindingActionFor_on_(each,html);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderBindingGroup:on:",{aBindingGroup:aBindingGroup,html:html},smalltalk.HLKeyBinderHelper)})},
 args: ["aBindingGroup", "html"],
-source: "renderBindingGroup: aBindingGroup on: html\x0a\x09(aBindingGroup activeBindings \x0a    \x09sorted: [ :a :b | a key < b key ])\x0a        do: [ :each | each renderActionFor: self keyBinder html: html ]",
-messageSends: ["do:", "renderActionFor:html:", "keyBinder", "sorted:", "<", "key", "activeBindings"],
-referencedClasses: []
-}),
-smalltalk.HLKeyBinderHelper);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "renderBindingOn:",
-category: 'rendering',
-fn: function (html){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self._selectedBinding())._renderOn_html_(self,html);
-return self}, function($ctx1) {$ctx1.fill(self,"renderBindingOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
-args: ["html"],
-source: "renderBindingOn: html\x0a\x09self selectedBinding renderOn: self html: html",
-messageSends: ["renderOn:html:", "selectedBinding"],
+source: "renderBindingGroup: aBindingGroup on: html\x0a\x09(aBindingGroup activeBindings \x0a    \x09sorted: [ :a :b | a key < b key ])\x0a        do: [ :each | self renderBindingActionFor: each on: html ]",
+messageSends: ["do:", "renderBindingActionFor:on:", "sorted:", "<", "key", "activeBindings"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);
@@ -1783,22 +1829,22 @@ _st($1)._class_(self._cssClass());
 $2=_st($1)._with_((function(){
 return smalltalk.withContext(function($ctx2) {
 $3=self;
-_st($3)._renderSelectionOn_(html);
-_st($3)._renderBindingOn_(html);
+_st($3)._renderLabelOn_(html);
+_st($3)._renderSelectedBindingOn_(html);
 $4=_st($3)._renderCloseOn_(html);
 return $4;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html div class: self cssClass; with: [\x0a      \x09self \x0a        \x09renderSelectionOn:html;\x0a          \x09renderBindingOn: html;\x0a\x09\x09\x09renderCloseOn: html ]",
-messageSends: ["class:", "cssClass", "div", "with:", "renderSelectionOn:", "renderBindingOn:", "renderCloseOn:"],
+source: "renderContentOn: html\x0a\x09html div class: self cssClass; with: [\x0a      \x09self \x0a        \x09renderLabelOn:html;\x0a          \x09renderSelectedBindingOn: html;\x0a\x09\x09\x09renderCloseOn: html ]",
+messageSends: ["class:", "cssClass", "div", "with:", "renderLabelOn:", "renderSelectedBindingOn:", "renderCloseOn:"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "renderSelectionOn:",
+selector: "renderLabelOn:",
 category: 'rendering',
 fn: function (html){
 var self=this;
@@ -1814,14 +1860,30 @@ $4="Action";
 $4=$5;
 };
 $2=_st($3)._with_($4);
-return self}, function($ctx1) {$ctx1.fill(self,"renderSelectionOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
+return self}, function($ctx1) {$ctx1.fill(self,"renderLabelOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
 args: ["html"],
-source: "renderSelectionOn: html\x0a\x09\x09html span \x0a        \x09class: 'selected'; \x0a            with: (self selectedBinding label ifNil: [ 'Action' ])",
+source: "renderLabelOn: html\x0a\x09\x09html span \x0a        \x09class: 'selected'; \x0a            with: (self selectedBinding label ifNil: [ 'Action' ])",
 messageSends: ["class:", "span", "with:", "ifNil:", "label", "selectedBinding"],
 referencedClasses: []
 }),
 smalltalk.HLKeyBinderHelper);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderSelectedBindingOn:",
+category: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._selectedBinding())._renderOn_html_(self,html);
+return self}, function($ctx1) {$ctx1.fill(self,"renderSelectedBindingOn:",{html:html},smalltalk.HLKeyBinderHelper)})},
+args: ["html"],
+source: "renderSelectedBindingOn: html\x0a\x09self selectedBinding renderOn: self html: html\x0a\x09",
+messageSends: ["renderOn:html:", "selectedBinding"],
+referencedClasses: []
+}),
+smalltalk.HLKeyBinderHelper);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderStart",

+ 1 - 1
js/Helios-Workspace-Tests.js

@@ -15,7 +15,7 @@ self._assert_(_st(_st($HLCodeWidget())._pcKeyMap())._isKindOf_($HashedCollection
 self._assert_(_st(_st($HLCodeWidget())._macKeyMap())._isKindOf_($HashedCollection()));
 return self}, function($ctx1) {$ctx1.fill(self,"testKeyMap",{},smalltalk.HLCodeWidgetTest)})},
 args: [],
-source: "testKeyMap\x0a\x22Key maps are a collection of associations.\x22\x0aself assert: ( HLCodeWidget pcKeyMap isKindOf: HashedCollection ).\x0aself assert: ( HLCodeWidget macKeyMap isKindOf: HashedCollection ).",
+source: "testKeyMap\x0a\x09\x22Key maps are a collection of associations.\x22\x0a\x09self assert: (HLCodeWidget pcKeyMap isKindOf: HashedCollection).\x0a\x09self assert: (HLCodeWidget macKeyMap isKindOf: HashedCollection)",
 messageSends: ["assert:", "isKindOf:", "pcKeyMap", "macKeyMap"],
 referencedClasses: ["HashedCollection", "HLCodeWidget"]
 }),

+ 20 - 0
st/Helios-Commands-Core.st

@@ -273,6 +273,26 @@ label
 	^ 'Workspace'
 ! !
 
+HLCommand subclass: #HLSwitchTabCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-Core'!
+
+!HLSwitchTabCommand methodsFor: 'executing'!
+
+execute
+	^ HLBrowser openAsTab
+! !
+
+!HLSwitchTabCommand class methodsFor: 'accessing'!
+
+key
+	^ 's'
+!
+
+label
+	^ 'Switch'
+! !
+
 HLCommand subclass: #HLViewCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-Core'!

+ 2 - 2
st/Helios-Core.st

@@ -1090,7 +1090,7 @@ on: aModel
 ! !
 
 HLWidget subclass: #HLManager
-	instanceVariableNames: 'tabs activeTab keyBinder environment history'
+	instanceVariableNames: 'tabs activeTab environment history'
 	package: 'Helios-Core'!
 
 !HLManager methodsFor: 'accessing'!
@@ -1118,7 +1118,7 @@ history: aCollection
 !
 
 keyBinder
-	^ keyBinder ifNil: [ keyBinder := HLKeyBinder new ]
+	^ HLKeyBinder current
 !
 
 tabs

+ 38 - 15
st/Helios-KeyBindings.st

@@ -345,6 +345,8 @@ isFinal: aBoolean
 Object subclass: #HLKeyBinder
 	instanceVariableNames: 'modifierKey helper bindings selectedBinding'
 	package: 'Helios-KeyBindings'!
+!HLKeyBinder commentStamp!
+My current instance keeps keybindings for Helios actions.!
 
 !HLKeyBinder methodsFor: 'accessing'!
 
@@ -412,8 +414,8 @@ defaultBindings
 	| group |
 	
 	group := HLBindingGroup new
-		addGroupKey: 86 labelled: 'View';
 		add: HLCloseTabCommand new asBinding;
+		add: HLSwitchTabCommand new asBinding;
 		yourself.
 		
 	HLOpenCommand registerConcreteClassesOn: group.
@@ -485,9 +487,25 @@ systemIsMac
 	^ navigator platform match: 'Mac'
 ! !
 
+HLKeyBinder class instanceVariableNames: 'current'!
+
+!HLKeyBinder class methodsFor: 'instance creation'!
+
+current
+	^ current ifNil: [ current := super new ]
+!
+
+new
+	self shouldNotImplement
+! !
+
 HLWidget subclass: #HLKeyBinderHelper
 	instanceVariableNames: 'keyBinder'
 	package: 'Helios-KeyBindings'!
+!HLKeyBinderHelper commentStamp!
+I am the widget responsible for displaying active keybindings in a bar at the bottom of the window. Each keybinding is an instance of `HLBinding`. 
+
+Rendering is done through a double dispatch, see `#renderSelectedBindingOn:`.!
 
 !HLKeyBinderHelper methodsFor: 'accessing'!
 
@@ -527,22 +545,23 @@ showCog
 	'#cog-helper' asJQuery show
 ! !
 
-!HLKeyBinderHelper methodsFor: 'keyBindings'!
-
-registerBindings
-	"Do nothing"
-! !
-
 !HLKeyBinderHelper methodsFor: 'rendering'!
 
+renderBindingActionFor: aBinding on: html
+	html span class: 'command'; with: [
+		html span 
+			class: 'label'; 
+			with: aBinding shortcut asLowercase.
+  		html a 
+        	class: 'action'; 
+            with: aBinding displayLabel;
+  			onClick: [ self keyBinder applyBinding: aBinding ] ]
+!
+
 renderBindingGroup: aBindingGroup on: html
 	(aBindingGroup activeBindings 
     	sorted: [ :a :b | a key < b key ])
-        do: [ :each | each renderActionFor: self keyBinder html: html ]
-!
-
-renderBindingOn: html
-	self selectedBinding renderOn: self html: html
+        do: [ :each | self renderBindingActionFor: each on: html ]
 !
 
 renderCloseOn: html
@@ -566,17 +585,21 @@ renderCog
 renderContentOn: html
 	html div class: self cssClass; with: [
       	self 
-        	renderSelectionOn:html;
-          	renderBindingOn: html;
+        	renderLabelOn:html;
+          	renderSelectedBindingOn: html;
 			renderCloseOn: html ]
 !
 
-renderSelectionOn: html
+renderLabelOn: html
 		html span 
         	class: 'selected'; 
             with: (self selectedBinding label ifNil: [ 'Action' ])
 !
 
+renderSelectedBindingOn: html
+	self selectedBinding renderOn: self html: html
+!
+
 renderStart
 	'#helper' asJQuery remove.
 

+ 3 - 3
st/Helios-Workspace-Tests.st

@@ -6,8 +6,8 @@ TestCase subclass: #HLCodeWidgetTest
 !HLCodeWidgetTest methodsFor: 'tests'!
 
 testKeyMap
-"Key maps are a collection of associations."
-self assert: ( HLCodeWidget pcKeyMap isKindOf: HashedCollection ).
-self assert: ( HLCodeWidget macKeyMap isKindOf: HashedCollection ).
+	"Key maps are a collection of associations."
+	self assert: (HLCodeWidget pcKeyMap isKindOf: HashedCollection).
+	self assert: (HLCodeWidget macKeyMap isKindOf: HashedCollection)
 ! !