1
0
Ver Fonte

Merge branch 'master' into moka

Nicolas Petton há 10 anos atrás
pai
commit
e0daaac5d3
100 ficheiros alterados com 3612 adições e 969 exclusões
  1. 0 3
      .gitignore
  2. 28 28
      Gruntfile.js
  3. 2 2
      RELEASING.md
  4. 1 2
      cli/index.html
  5. 7 24
      cli/src/AmberCli.js
  6. 2 6
      cli/src/AmberCli.st
  7. 23 48
      cli/support/amber-cli.js
  8. 2 2
      cli/support/amberc-cli.js
  9. 4 3
      cli/support/amberc.js
  10. 2 4
      cli/support/release-worker.sh
  11. 2 2
      cli/support/setversion.sh
  12. 47 10
      css/helios.css
  13. 56 11
      css/helios.less
  14. 3 3
      grunt/tasks/grunt-amberc.js
  15. 0 0
      src/Benchfib.js
  16. 0 0
      src/Benchfib.st
  17. 170 0
      src/Compiler-AST.js
  18. 55 0
      src/Compiler-AST.st
  19. 0 24
      src/Compiler-Core.js
  20. 0 5
      src/Compiler-Core.st
  21. 0 0
      src/Compiler-Exceptions.js
  22. 0 0
      src/Compiler-Exceptions.st
  23. 0 0
      src/Compiler-IR.js
  24. 0 0
      src/Compiler-IR.st
  25. 0 0
      src/Compiler-Inlining.js
  26. 0 0
      src/Compiler-Inlining.st
  27. 0 0
      src/Compiler-Interpreter.js
  28. 0 0
      src/Compiler-Interpreter.st
  29. 0 0
      src/Compiler-Semantic.js
  30. 0 0
      src/Compiler-Semantic.st
  31. 49 0
      src/Compiler-Tests.js
  32. 25 0
      src/Compiler-Tests.st
  33. 1 1
      src/Examples.js
  34. 0 0
      src/Examples.st
  35. 3 12
      src/Helios-Announcements.js
  36. 4 18
      src/Helios-Announcements.st
  37. 120 27
      src/Helios-Browser.js
  38. 31 5
      src/Helios-Browser.st
  39. 49 0
      src/Helios-Commands-Browser.js
  40. 20 0
      src/Helios-Commands-Browser.st
  41. 52 0
      src/Helios-Commands-Core.js
  42. 20 0
      src/Helios-Commands-Core.st
  43. 66 7
      src/Helios-Commands-Tools.js
  44. 22 3
      src/Helios-Commands-Tools.st
  45. 558 164
      src/Helios-Core.js
  46. 266 85
      src/Helios-Core.st
  47. 186 37
      src/Helios-Debugger.js
  48. 81 34
      src/Helios-Debugger.st
  49. 0 0
      src/Helios-Exceptions.js
  50. 0 0
      src/Helios-Exceptions.st
  51. 168 4
      src/Helios-Helpers.js
  52. 70 8
      src/Helios-Helpers.st
  53. 128 129
      src/Helios-Inspector.js
  54. 43 36
      src/Helios-Inspector.st
  55. 20 11
      src/Helios-KeyBindings.js
  56. 9 8
      src/Helios-KeyBindings.st
  57. 1 1
      src/Helios-Layout.js
  58. 0 0
      src/Helios-Layout.st
  59. 0 0
      src/Helios-References.js
  60. 0 0
      src/Helios-References.st
  61. 67 0
      src/Helios-SUnit.js
  62. 25 0
      src/Helios-SUnit.st
  63. 2 2
      src/Helios-Transcript.js
  64. 2 2
      src/Helios-Transcript.st
  65. 0 0
      src/Helios-Workspace-Tests.js
  66. 0 0
      src/Helios-Workspace-Tests.st
  67. 182 63
      src/Helios-Workspace.js
  68. 66 17
      src/Helios-Workspace.st
  69. 1 1
      src/IDE.js
  70. 0 0
      src/IDE.st
  71. 142 10
      src/Kernel-Announcements.js
  72. 42 1
      src/Kernel-Announcements.st
  73. 17 0
      src/Kernel-Classes.js
  74. 6 0
      src/Kernel-Classes.st
  75. 1 1
      src/Kernel-Collections.js
  76. 0 0
      src/Kernel-Collections.st
  77. 4 0
      src/Kernel-Exceptions.js
  78. 6 0
      src/Kernel-Exceptions.st
  79. 93 42
      src/Kernel-ImportExport.js
  80. 43 10
      src/Kernel-ImportExport.st
  81. 83 8
      src/Kernel-Infrastructure.js
  82. 35 4
      src/Kernel-Infrastructure.st
  83. 17 0
      src/Kernel-Methods.js
  84. 6 0
      src/Kernel-Methods.st
  85. 152 2
      src/Kernel-Objects.js
  86. 36 0
      src/Kernel-Objects.st
  87. 118 2
      src/Kernel-Tests.js
  88. 34 1
      src/Kernel-Tests.st
  89. 0 0
      src/Kernel-Transcript.js
  90. 0 0
      src/Kernel-Transcript.st
  91. 0 0
      src/SUnit-Tests.js
  92. 0 0
      src/SUnit-Tests.st
  93. 0 0
      src/SUnit.js
  94. 0 0
      src/SUnit.st
  95. 0 0
      src/Spaces.js
  96. 0 0
      src/Spaces.st
  97. 19 19
      src/Web.js
  98. 11 11
      src/Web.st
  99. 5 5
      support/amber.js
  100. 1 1
      support/deploy.js

+ 0 - 3
.gitignore

@@ -4,9 +4,6 @@ server/FileServer*.js
 # Ignoring Mac Finder files
 .DS_Store
 
-# Ignoring compiled files in st
-st/*.js
-
 # Ignoring run.js in test/
 test/amber_test_runner.js
 test/run.js

+ 28 - 28
Gruntfile.js

@@ -30,40 +30,40 @@ module.exports = function(grunt) {
         closure_jar: ''
       },
       all: {
-        output_dir : 'js',
-        src: ['st/Kernel-Objects.st', 'st/Kernel-Classes.st', 'st/Kernel-Methods.st', 'st/Kernel-Collections.st',
-              'st/Kernel-Infrastructure.st', 'st/Kernel-Exceptions.st', 'st/Kernel-Transcript.st', 'st/Kernel-Announcements.st',
-              'st/Kernel-ImportExport.st', 'st/Compiler-Exceptions.st', 'st/Compiler-Core.st', 'st/Compiler-AST.st',
-              'st/Compiler-IR.st', 'st/Compiler-Inlining.st', 'st/Compiler-Semantic.st', 'st/Compiler-Interpreter.st',
-              'st/Canvas.st', 'st/SUnit.st', 'st/IDE.st',
-              'st/Kernel-Tests.st', 'st/Compiler-Tests.st', 'st/SUnit-Tests.st',
-              'st/Helios-Core.st', 'st/Helios-Exceptions.st', 'st/Helios-Announcements.st',
-              'st/Helios-KeyBindings.st', 'st/Helios-Layout.st',
-              'st/Helios-Commands-Core.st', 'st/Helios-Commands-Tools.st', 'st/Helios-Commands-Browser.st',
-              'st/Helios-References.st', 'st/Helios-Inspector.st', 'st/Helios-Browser.st',
-              'st/Helios-Transcript.st', 'st/Helios-Workspace.st', 'st/Helios-Debugger.st',
-              'st/Helios-Workspace-Tests.st',
-              'st/Benchfib.st', 'st/Examples.st', 'st/Spaces.st'
+        output_dir : 'src',
+        src: ['src/Kernel-Objects.st', 'src/Kernel-Classes.st', 'src/Kernel-Methods.st', 'src/Kernel-Collections.st',
+              'src/Kernel-Infrastructure.st', 'src/Kernel-Exceptions.st', 'src/Kernel-Transcript.st', 'src/Kernel-Announcements.st',
+              'src/Kernel-ImportExport.st', 'src/Compiler-Exceptions.st', 'src/Compiler-Core.st', 'src/Compiler-AST.st',
+              'src/Compiler-IR.st', 'src/Compiler-Inlining.st', 'src/Compiler-Semantic.st', 'src/Compiler-Interpreter.st',
+              'src/Web.st', 'src/SUnit.st', 'src/IDE.st',
+              'src/Kernel-Tests.st', 'src/Compiler-Tests.st', 'src/SUnit-Tests.st',
+              'src/Helios-Core.st', 'src/Helios-Exceptions.st', 'src/Helios-Announcements.st',
+              'src/Helios-KeyBindings.st', 'src/Helios-Layout.st',
+              'src/Helios-Commands-Core.st', 'src/Helios-Commands-Tools.st', 'src/Helios-Commands-Browser.st',
+              'src/Helios-References.st', 'src/Helios-Inspector.st', 'src/Helios-Browser.st',
+              'src/Helios-Transcript.st', 'src/Helios-Workspace.st', 'src/Helios-Debugger.st',
+              'src/Helios-Workspace-Tests.st',
+              'src/Benchfib.st', 'src/Examples.st', 'src/Spaces.st'
               ],
         jsGlobals: ['navigator']
       },
       amber_kernel: {
-        output_dir : 'js',
-        src: ['st/Kernel-Objects.st', 'st/Kernel-Classes.st', 'st/Kernel-Methods.st', 'st/Kernel-Collections.st',
-              'st/Kernel-Infrastructure.st', 'st/Kernel-Exceptions.st', 'st/Kernel-Transcript.st', 'st/Kernel-Announcements.st']
+        output_dir : 'src',
+        src: ['src/Kernel-Objects.st', 'src/Kernel-Classes.st', 'src/Kernel-Methods.st', 'src/Kernel-Collections.st',
+              'src/Kernel-Infrastructure.st', 'src/Kernel-Exceptions.st', 'src/Kernel-Transcript.st', 'src/Kernel-Announcements.st']
       },
-      amber_canvas: {
-        output_dir : 'js',
-        src: ['st/Canvas.st', 'st/SUnit.st']
+      amber_web: {
+        output_dir : 'src',
+        src: ['src/Web.st', 'src/SUnit.st']
       },
       amber_IDE: {
-        output_dir : 'js',
-        src: ['st/IDE.st'],
-        libraries: ['Canvas']
+        output_dir : 'src',
+        src: ['src/IDE.st'],
+        libraries: ['Web']
       },
       amber_tests: {
-        output_dir : 'js',
-        src: ['st/Kernel-Tests.st', 'st/Compiler-Tests.st', 'st/SUnit-Tests.st'],
+        output_dir : 'src',
+        src: ['src/Kernel-Tests.st', 'src/Compiler-Tests.st', 'src/SUnit-Tests.st'],
         libraries: ['SUnit']
       },
       amber_test_runner: {
@@ -77,8 +77,8 @@ module.exports = function(grunt) {
         output_name: 'test/amber_test_runner'
       },
       amber_cli: {
-        output_dir: 'cli/js',
-        src: ['cli/st/AmberCli.st'],
+        output_dir: 'cli/src',
+        src: ['cli/src/AmberCli.st'],
         libraries: [
             'Compiler-Exceptions', 'Compiler-Core', 'Compiler-AST',
             'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser'
@@ -90,7 +90,7 @@ module.exports = function(grunt) {
     },
 
     jshint: {
-      amber: ['js/*.js'],
+      amber: ['src/*.js'],
       server: ['server/*.js'],
       repl: ['repl/*.js'],
       tests: ['test/*.js'],

+ 2 - 2
RELEASING.md

@@ -5,8 +5,8 @@ The following steps are required to make a release of Amber:
 
 1. check that all tests are green
 2. check that the examples are up-to-date
-3. check that `API-CHANGES.txt` is up-to-date
-4. check the `CHANGELOG` file and update the release notes
+3. check that `API-CHANGES.txt` is up-to-date; remove the 'work in progress' from version
+4. check the `CHANGELOG` file and update the release notes, check the milestone index in issues link
 5. log in to npm with write access for the Amber package
 6. execute `cli/support/release.sh`
 7. answer the question about the version number used for the release

+ 1 - 2
cli/index.html

@@ -14,8 +14,7 @@
     <script type='text/javascript'>
     require.config({
         paths: {
-            'amber_cli': 'js',
-            'amber_cli/_source': 'st'
+            'amber_cli': 'src'
         }
     });
     require(

+ 7 - 24
cli/js/AmberCli.js → cli/src/AmberCli.js

@@ -253,9 +253,8 @@ protocol: 'initialization',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$5,$4,$2,$6;
+var $1;
 $1=_st(self["@fs"])._existsSync_(self._withBasePath_("index.html"));
-$ctx1.sendIdx["existsSync:"]=1;
 if(! smalltalk.assert($1)){
 _st(console)._warn_("Warning: project directory does not contain index.html.");
 $ctx1.sendIdx["warn:"]=1;
@@ -264,27 +263,11 @@ $ctx1.sendIdx["warn:"]=2;
 _st(console)._warn_("    You can also specify a page to be served by default,");
 $ctx1.sendIdx["warn:"]=3;
 _st(console)._warn_("    for all paths that do not map to a file, with --fallback-page.");
-$ctx1.sendIdx["warn:"]=4;
-};
-$3=self["@fs"];
-$5=self._basePath();
-$ctx1.sendIdx["basePath"]=1;
-$4=_st($5).__comma("st");
-$ctx1.sendIdx[","]=1;
-$2=_st($3)._existsSync_($4);
-$ctx1.sendIdx["existsSync:"]=2;
-if(! smalltalk.assert($2)){
-_st(console)._warn_("Warning: project directory is missing an \x22st\x22 directory");
-$ctx1.sendIdx["warn:"]=5;
-};
-$6=_st(self["@fs"])._existsSync_(_st(self._basePath()).__comma("js"));
-if(! smalltalk.assert($6)){
-_st(console)._warn_("Warning: project directory is missing a \x22js\x22 directory");
 };
 return self}, function($ctx1) {$ctx1.fill(self,"checkDirectoryLayout",{},globals.FileServer)})},
 args: [],
-source: "checkDirectoryLayout\x0a\x09(fs existsSync:\x09(self withBasePath: 'index.html')) ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory does not contain index.html.'.\x0a\x09\x09console warn: '    You can specify the directory containing index.html with --base-path.'.\x0a\x09\x09console warn: '    You can also specify a page to be served by default,'.\x0a\x09\x09console warn: '    for all paths that do not map to a file, with --fallback-page.'].\x0a\x09(fs existsSync: self basePath, 'st') ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory is missing an \x22st\x22 directory'].\x0a\x09(fs existsSync: self basePath, 'js') ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory is missing a \x22js\x22 directory'].",
-messageSends: ["ifFalse:", "existsSync:", "withBasePath:", "warn:", ",", "basePath"],
+source: "checkDirectoryLayout\x0a\x09(fs existsSync:\x09(self withBasePath: 'index.html')) ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory does not contain index.html.'.\x0a\x09\x09console warn: '    You can specify the directory containing index.html with --base-path.'.\x0a\x09\x09console warn: '    You can also specify a page to be served by default,'.\x0a\x09\x09console warn: '    for all paths that do not map to a file, with --fallback-page.'].",
+messageSends: ["ifFalse:", "existsSync:", "withBasePath:", "warn:"],
 referencedClasses: []
 }),
 globals.FileServer);
@@ -394,7 +377,7 @@ $3="Error creating WriteStream for file ".__comma(file);
 $ctx2.sendIdx[","]=2;
 _st($2)._warn_($3);
 $ctx2.sendIdx["warn:"]=1;
-_st(console)._warn_("    Did you forget to create the necessary js/ or st/ directory in your project?");
+_st(console)._warn_("    Did you forget to create the necessary directory in your project (often /src)?");
 $ctx2.sendIdx["warn:"]=2;
 _st(console)._warn_("    The exact error is: ".__comma(error));
 return self._respondNotCreatedTo_(aResponse);
@@ -420,7 +403,7 @@ return _st(stream)._end();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"handlePUTRequest:respondTo:",{aRequest:aRequest,aResponse:aResponse,file:file,stream:stream},globals.FileServer)})},
 args: ["aRequest", "aResponse"],
-source: "handlePUTRequest: aRequest respondTo: aResponse\x0a\x09| file stream |\x0a\x09(self isAuthenticated: aRequest)\x0a\x09\x09ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].\x0a\x0a\x09file := '.', aRequest url.\x0a\x09stream := fs createWriteStream: file.\x0a\x0a\x09stream on: 'error' do: [:error |\x0a\x09\x09console warn: 'Error creating WriteStream for file ', file.\x0a\x09\x09console warn: '    Did you forget to create the necessary js/ or st/ directory in your project?'.\x0a\x09\x09console warn: '    The exact error is: ', error.\x0a\x09\x09self respondNotCreatedTo: aResponse].\x0a\x0a\x09stream on: 'close' do: [\x0a\x09\x09self respondCreatedTo: aResponse].\x0a\x0a\x09aRequest setEncoding: 'utf8'.\x0a\x09aRequest on: 'data' do: [:data |\x0a\x09\x09stream write: data].\x0a\x0a\x09aRequest on: 'end' do: [\x0a\x09\x09stream writable ifTrue: [stream end]]",
+source: "handlePUTRequest: aRequest respondTo: aResponse\x0a\x09| file stream |\x0a\x09(self isAuthenticated: aRequest)\x0a\x09\x09ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].\x0a\x0a\x09file := '.', aRequest url.\x0a\x09stream := fs createWriteStream: file.\x0a\x0a\x09stream on: 'error' do: [:error |\x0a\x09\x09console warn: 'Error creating WriteStream for file ', file.\x0a\x09\x09console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.\x0a\x09\x09console warn: '    The exact error is: ', error.\x0a\x09\x09self respondNotCreatedTo: aResponse].\x0a\x0a\x09stream on: 'close' do: [\x0a\x09\x09self respondCreatedTo: aResponse].\x0a\x0a\x09aRequest setEncoding: 'utf8'.\x0a\x09aRequest on: 'data' do: [:data |\x0a\x09\x09stream write: data].\x0a\x0a\x09aRequest on: 'end' do: [\x0a\x09\x09stream writable ifTrue: [stream end]]",
 messageSends: ["ifFalse:", "isAuthenticated:", "respondAuthenticationRequiredTo:", ",", "url", "createWriteStream:", "on:do:", "warn:", "respondNotCreatedTo:", "respondCreatedTo:", "setEncoding:", "write:", "ifTrue:", "writable", "end"],
 referencedClasses: []
 }),
@@ -798,11 +781,11 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 _st(aResponse)._writeHead_options_((400),globals.HashedCollection._newFromPairs_(["Content-Type","text/plain"]));
-_st(aResponse)._write_("File could not be created. Did you forget to create the st/js directories on the server?");
+_st(aResponse)._write_("File could not be created. Did you forget to create the src directory on the server?");
 $1=_st(aResponse)._end();
 return self}, function($ctx1) {$ctx1.fill(self,"respondNotCreatedTo:",{aResponse:aResponse},globals.FileServer)})},
 args: ["aResponse"],
-source: "respondNotCreatedTo: aResponse\x0a\x09aResponse\x0a\x09\x09writeHead: 400 options: #{'Content-Type' -> 'text/plain'};\x0a\x09\x09write: 'File could not be created. Did you forget to create the st/js directories on the server?';\x0a\x09\x09end.",
+source: "respondNotCreatedTo: aResponse\x0a\x09aResponse\x0a\x09\x09writeHead: 400 options: #{'Content-Type' -> 'text/plain'};\x0a\x09\x09write: 'File could not be created. Did you forget to create the src directory on the server?';\x0a\x09\x09end.",
 messageSends: ["writeHead:options:", "write:", "end"],
 referencedClasses: []
 }),

+ 2 - 6
cli/st/AmberCli.st → cli/src/AmberCli.st

@@ -174,10 +174,6 @@ checkDirectoryLayout
 		console warn: '    You can specify the directory containing index.html with --base-path.'.
 		console warn: '    You can also specify a page to be served by default,'.
 		console warn: '    for all paths that do not map to a file, with --fallback-page.'].
-	(fs existsSync: self basePath, 'st') ifFalse: [
-		console warn: 'Warning: project directory is missing an "st" directory'].
-	(fs existsSync: self basePath, 'js') ifFalse: [
-		console warn: 'Warning: project directory is missing a "js" directory'].
 !
 
 initialize
@@ -279,7 +275,7 @@ handlePUTRequest: aRequest respondTo: aResponse
 
 	stream on: 'error' do: [:error |
 		console warn: 'Error creating WriteStream for file ', file.
-		console warn: '    Did you forget to create the necessary js/ or st/ directory in your project?'.
+		console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.
 		console warn: '    The exact error is: ', error.
 		self respondNotCreatedTo: aResponse].
 
@@ -352,7 +348,7 @@ respondInternalErrorTo: aResponse
 respondNotCreatedTo: aResponse
 	aResponse
 		writeHead: 400 options: #{'Content-Type' -> 'text/plain'};
-		write: 'File could not be created. Did you forget to create the st/js directories on the server?';
+		write: 'File could not be created. Did you forget to create the src directory on the server?';
 		end.
 !
 

+ 23 - 48
cli/support/amber-cli.js

@@ -1447,7 +1447,7 @@ smalltalk.addPackage('Kernel-Objects');
 smalltalk.packages["Kernel-Objects"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 smalltalk.addClass('ProtoObject', globals.nil, [], 'Kernel-Objects');
-globals.ProtoObject.comment="I implement the basic behavior required for any object in Amber.\x0a\x0aIn most cases, subclassing `ProtoObject` is wrong and `Object` should be used instead. However subclassing `ProtoObject` can be useful in some special cases like proxy implementations. ";
+globals.ProtoObject.comment="I implement the basic behavior required for any object in Amber.\x0a\x0aIn most cases, subclassing `ProtoObject` is wrong and `Object` should be used instead. However subclassing `ProtoObject` can be useful in some special cases like proxy implementations.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "=",
@@ -15248,7 +15248,7 @@ globals.String.klass);
 
 
 smalltalk.addClass('Set', globals.Collection, ['defaultBucket', 'slowBucketStores', 'fastBuckets', 'size'], 'Kernel-Collections');
-globals.Set.comment="I represent an unordered set of objects without duplicates.\x0a\x0a## Implementation notes\x0a\x0aI put elements into different stores based on their type.\x0aThe goal is to store some elements into native JS object property names to be fast.\x0a\x0aIf an unboxed element has typeof 'string', 'boolean' or 'number', or an element is nil, null or undefined,\x0aI store it as a property name in an empty (== Object.create(null)) JS object, different for each type\x0a(for simplicity, nil/null/undefined is treated as one and included with the two booleans).\x0a\x0aIf element happen to be an object, I try to store them in `ArrayBucketStore`. I have two of them by default,\x0aone hashed using the Smalltalk class name, the other one using the JS constructor name. It is possible to have more or less\x0ainstances of `ArrayBucketStores`, see `#initializeSlowBucketStores`.\x0a\x0aAs a last resort, if none of the `ArrayBucketStore` instances can find a suitable bucket, the `defaultBucket` is used,\x0awhich is an `Array`.\x0a";
+globals.Set.comment="I represent an unordered set of objects without duplicates.\x0a\x0a## Implementation notes\x0a\x0aI put elements into different stores based on their type.\x0aThe goal is to store some elements into native JS object property names to be fast.\x0a\x0aIf an unboxed element has typeof 'string', 'boolean' or 'number', or an element is nil, null or undefined,\x0aI store it as a property name in an empty (== Object.create(null)) JS object, different for each type\x0a(for simplicity, nil/null/undefined is treated as one and included with the two booleans).\x0a\x0aIf element happen to be an object, I try to store them in `ArrayBucketStore`. I have two of them by default,\x0aone hashed using the Smalltalk class name, the other one using the JS constructor name. It is possible to have more or less\x0ainstances of `ArrayBucketStores`, see `#initializeSlowBucketStores`.\x0a\x0aAs a last resort, if none of the `ArrayBucketStore` instances can find a suitable bucket, the `defaultBucket` is used,\x0awhich is an `Array`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "=",
@@ -17732,7 +17732,7 @@ return smalltalk.withContext(function($ctx1) {
 return self["@jsObject"] === aJSObject;
 return self}, function($ctx1) {$ctx1.fill(self,"compareJSObjectWith:",{aJSObject:aJSObject},globals.JSObjectProxy)})},
 args: ["aJSObject"],
-source: " compareJSObjectWith: aJSObject\x0a \x09<return self[\x22@jsObject\x22] === aJSObject>",
+source: "compareJSObjectWith: aJSObject\x0a \x09<return self[\x22@jsObject\x22] === aJSObject>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -19137,7 +19137,7 @@ globals.Setting.klass);
 
 
 smalltalk.addClass('SmalltalkImage', globals.Object, [], 'Kernel-Infrastructure');
-globals.SmalltalkImage.comment="I represent the Smalltalk system, wrapping\x0aoperations of variable `smalltalk` declared in `js/boot.js`.\x0a\x0a## API\x0a\x0aI have only one instance, accessed with global variable `Smalltalk`.\x0a\x0aThe `smalltalk` object holds all class and packages defined in the system.\x0a\x0a## Classes\x0a\x0aClasses can be accessed using the following methods:\x0a\x0a- `#classes` answers the full list of Smalltalk classes in the system\x0a- `#at:` answers a specific class or `nil`\x0a\x0a## Packages\x0a\x0aPackages can be accessed using the following methods:\x0a\x0a- `#packages` answers the full list of packages\x0a- `#packageAt:` answers a specific package or `nil`\x0a\x0a## Parsing\x0a\x0aThe `#parse:` method is used to parse Amber source code.\x0aIt requires the `Compiler` package and the `js/parser.js` parser file in order to work.";
+globals.SmalltalkImage.comment="I represent the Smalltalk system, wrapping\x0aoperations of variable `smalltalk` declared in `support/boot.js`.\x0a\x0a## API\x0a\x0aI have only one instance, accessed with global variable `Smalltalk`.\x0a\x0aThe `smalltalk` object holds all class and packages defined in the system.\x0a\x0a## Classes\x0a\x0aClasses can be accessed using the following methods:\x0a\x0a- `#classes` answers the full list of Smalltalk classes in the system\x0a- `#at:` answers a specific class or `nil`\x0a\x0a## Packages\x0a\x0aPackages can be accessed using the following methods:\x0a\x0a- `#packages` answers the full list of packages\x0a- `#packageAt:` answers a specific package or `nil`\x0a\x0a## Parsing\x0a\x0aThe `#parse:` method is used to parse Amber source code.\x0aIt requires the `Compiler` package and the `support/parser.js` parser file in order to work.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "addGlobalJsVariable:",
@@ -34551,28 +34551,20 @@ selector: "visitDynamicDictionaryNode:",
 protocol: 'visiting',
 fn: function (aNode){
 var self=this;
-var associations,hashedCollection;
+var keyValueList;
 function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
-associations=_st($OrderedCollection())._new();
-$ctx1.sendIdx["new"]=1;
-hashedCollection=_st($HashedCollection())._new();
+keyValueList=_st($OrderedCollection())._new();
 _st(_st(aNode)._nodes())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-return _st(associations)._add_(self._pop());
-$ctx2.sendIdx["add:"]=1;
+return _st(keyValueList)._add_(self._pop());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
-$ctx1.sendIdx["do:"]=1;
-_st(_st(associations)._reversed())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(hashedCollection)._add_(each);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
-self._push_(hashedCollection);
-return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode,associations:associations,hashedCollection:hashedCollection},globals.ASTInterpreter)})},
+self._push_(_st($HashedCollection())._newFromPairs_(_st(keyValueList)._reversed()));
+return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode,keyValueList:keyValueList},globals.ASTInterpreter)})},
 args: ["aNode"],
-source: "visitDynamicDictionaryNode: aNode\x0a\x09| associations hashedCollection |\x0a\x09\x0a\x09associations := OrderedCollection new.\x0a\x09hashedCollection := HashedCollection new.\x0a\x09\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09associations add: self pop ].\x0a\x09\x0a\x09associations reversed do: [ :each |\x0a\x09\x09hashedCollection add: each ].\x0a\x09\x0a\x09self push: hashedCollection",
-messageSends: ["new", "do:", "nodes", "add:", "pop", "reversed", "push:"],
+source: "visitDynamicDictionaryNode: aNode\x0a\x09| keyValueList |\x0a\x09\x0a\x09keyValueList := OrderedCollection new.\x0a\x09\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09keyValueList add: self pop ].\x0a\x09\x0a\x09self push: (HashedCollection newFromPairs: keyValueList reversed)",
+messageSends: ["new", "do:", "nodes", "add:", "pop", "push:", "newFromPairs:", "reversed"],
 referencedClasses: ["OrderedCollection", "HashedCollection"]
 }),
 globals.ASTInterpreter);
@@ -38878,7 +38870,7 @@ smalltalk.addPackage('AmberCli');
 smalltalk.packages["AmberCli"].transport = {"type":"amd","amdNamespace":"amber_cli"};
 
 smalltalk.addClass('AmberCli', globals.Object, [], 'AmberCli');
-globals.AmberCli.comment="I am the Amber CLI (CommandLine Interface) tool which runs on Node.js.\x0d\x0a\x0d\x0aMy responsibility is to start different Amber programs like the FileServer or the Repl.\x0d\x0aWhich program to start is determined by the first commandline parameters passed to the AmberCli executable.\x0d\x0aUse `help` to get a list of all available options.\x0d\x0aAny further commandline parameters are passed to the specific program.\x0d\x0a\x0d\x0a## Commands\x0d\x0a\x0d\x0aNew commands can be added by creating a class side method in the `commands` protocol which takes one parameter.\x0d\x0aThis parameter is an array of all commandline options + values passed on to the program.\x0d\x0aAny `camelCaseCommand` is transformed into a commandline parameter of the form `camel-case-command` and vice versa.";
+globals.AmberCli.comment="I am the Amber CLI (CommandLine Interface) tool which runs on Node.js.\x0a\x0aMy responsibility is to start different Amber programs like the FileServer or the Repl.\x0aWhich program to start is determined by the first commandline parameters passed to the AmberCli executable.\x0aUse `help` to get a list of all available options.\x0aAny further commandline parameters are passed to the specific program.\x0a\x0a## Commands\x0a\x0aNew commands can be added by creating a class side method in the `commands` protocol which takes one parameter.\x0aThis parameter is an array of all commandline options + values passed on to the program.\x0aAny `camelCaseCommand` is transformed into a commandline parameter of the form `camel-case-command` and vice versa.";
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -39064,7 +39056,7 @@ globals.AmberCli.klass);
 
 
 smalltalk.addClass('FileServer', globals.Object, ['path', 'http', 'fs', 'url', 'host', 'port', 'basePath', 'util', 'username', 'password', 'fallbackPage'], 'AmberCli');
-globals.FileServer.comment="I am the Amber Smalltalk FileServer.\x0d\x0aMy runtime requirement is a functional Node.js executable.\x0d\x0a\x0d\x0aTo start a FileServer instance on port `4000` use the following code:\x0d\x0a\x0d\x0a    FileServer new start\x0d\x0a\x0d\x0aA parameterized instance can be created with the following code:\x0d\x0a\x0d\x0a    FileServer createServerWithArguments: options\x0d\x0a\x0d\x0aHere, `options` is an array of commandline style strings each followed by a value e.g. `#('--port', '6000', '--host', '0.0.0.0')`.\x0d\x0aA list of all available parameters can be printed to the commandline by passing `--help` as parameter.\x0d\x0aSee the `Options` section for further details on how options are mapped to instance methods.\x0d\x0a\x0d\x0aAfter startup FileServer checks if the directory layout required by Amber is present and logs a warning on absence.\x0d\x0a\x0d\x0a\x0d\x0a## Options\x0d\x0a\x0d\x0aEach option is of the form `--some-option-string` which is transformed into a selector of the format `someOptionString:`.\x0d\x0aThe trailing `--` gets removed, each `-[a-z]` gets transformed into the according uppercase letter, and a `:` is appended to create a selector which takes a single argument.\x0d\x0aAfterwards, the selector gets executed on the `FileServer` instance with the value following in the options array as parameter.\x0d\x0a\x0d\x0a## Adding new commandline parameters\x0d\x0a\x0d\x0aAdding new commandline parameters to `FileServer` is as easy as adding a new single parameter method to the `accessing` protocol.";
+globals.FileServer.comment="I am the Amber Smalltalk FileServer.\x0aMy runtime requirement is a functional Node.js executable.\x0a\x0aTo start a FileServer instance on port `4000` use the following code:\x0a\x0a    FileServer new start\x0a\x0aA parameterized instance can be created with the following code:\x0a\x0a    FileServer createServerWithArguments: options\x0a\x0aHere, `options` is an array of commandline style strings each followed by a value e.g. `#('--port', '6000', '--host', '0.0.0.0')`.\x0aA list of all available parameters can be printed to the commandline by passing `--help` as parameter.\x0aSee the `Options` section for further details on how options are mapped to instance methods.\x0a\x0aAfter startup FileServer checks if the directory layout required by Amber is present and logs a warning on absence.\x0a\x0a\x0a## Options\x0a\x0aEach option is of the form `--some-option-string` which is transformed into a selector of the format `someOptionString:`.\x0aThe trailing `--` gets removed, each `-[a-z]` gets transformed into the according uppercase letter, and a `:` is appended to create a selector which takes a single argument.\x0aAfterwards, the selector gets executed on the `FileServer` instance with the value following in the options array as parameter.\x0a\x0a## Adding new commandline parameters\x0a\x0aAdding new commandline parameters to `FileServer` is as easy as adding a new single parameter method to the `accessing` protocol.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "base64Decode:",
@@ -39128,9 +39120,8 @@ protocol: 'initialization',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$5,$4,$2,$6;
+var $1;
 $1=_st(self["@fs"])._existsSync_(self._withBasePath_("index.html"));
-$ctx1.sendIdx["existsSync:"]=1;
 if(! smalltalk.assert($1)){
 _st(console)._warn_("Warning: project directory does not contain index.html.");
 $ctx1.sendIdx["warn:"]=1;
@@ -39139,27 +39130,11 @@ $ctx1.sendIdx["warn:"]=2;
 _st(console)._warn_("    You can also specify a page to be served by default,");
 $ctx1.sendIdx["warn:"]=3;
 _st(console)._warn_("    for all paths that do not map to a file, with --fallback-page.");
-$ctx1.sendIdx["warn:"]=4;
-};
-$3=self["@fs"];
-$5=self._basePath();
-$ctx1.sendIdx["basePath"]=1;
-$4=_st($5).__comma("st");
-$ctx1.sendIdx[","]=1;
-$2=_st($3)._existsSync_($4);
-$ctx1.sendIdx["existsSync:"]=2;
-if(! smalltalk.assert($2)){
-_st(console)._warn_("Warning: project directory is missing an \x22st\x22 directory");
-$ctx1.sendIdx["warn:"]=5;
-};
-$6=_st(self["@fs"])._existsSync_(_st(self._basePath()).__comma("js"));
-if(! smalltalk.assert($6)){
-_st(console)._warn_("Warning: project directory is missing a \x22js\x22 directory");
 };
 return self}, function($ctx1) {$ctx1.fill(self,"checkDirectoryLayout",{},globals.FileServer)})},
 args: [],
-source: "checkDirectoryLayout\x0a\x09(fs existsSync:\x09(self withBasePath: 'index.html')) ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory does not contain index.html.'.\x0a\x09\x09console warn: '    You can specify the directory containing index.html with --base-path.'.\x0a\x09\x09console warn: '    You can also specify a page to be served by default,'.\x0a\x09\x09console warn: '    for all paths that do not map to a file, with --fallback-page.'].\x0a\x09(fs existsSync: self basePath, 'st') ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory is missing an \x22st\x22 directory'].\x0a\x09(fs existsSync: self basePath, 'js') ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory is missing a \x22js\x22 directory'].",
-messageSends: ["ifFalse:", "existsSync:", "withBasePath:", "warn:", ",", "basePath"],
+source: "checkDirectoryLayout\x0a\x09(fs existsSync:\x09(self withBasePath: 'index.html')) ifFalse: [\x0a\x09\x09console warn: 'Warning: project directory does not contain index.html.'.\x0a\x09\x09console warn: '    You can specify the directory containing index.html with --base-path.'.\x0a\x09\x09console warn: '    You can also specify a page to be served by default,'.\x0a\x09\x09console warn: '    for all paths that do not map to a file, with --fallback-page.'].",
+messageSends: ["ifFalse:", "existsSync:", "withBasePath:", "warn:"],
 referencedClasses: []
 }),
 globals.FileServer);
@@ -39269,7 +39244,7 @@ $3="Error creating WriteStream for file ".__comma(file);
 $ctx2.sendIdx[","]=2;
 _st($2)._warn_($3);
 $ctx2.sendIdx["warn:"]=1;
-_st(console)._warn_("    Did you forget to create the necessary js/ or st/ directory in your project?");
+_st(console)._warn_("    Did you forget to create the necessary directory in your project (often /src)?");
 $ctx2.sendIdx["warn:"]=2;
 _st(console)._warn_("    The exact error is: ".__comma(error));
 return self._respondNotCreatedTo_(aResponse);
@@ -39295,7 +39270,7 @@ return _st(stream)._end();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"handlePUTRequest:respondTo:",{aRequest:aRequest,aResponse:aResponse,file:file,stream:stream},globals.FileServer)})},
 args: ["aRequest", "aResponse"],
-source: "handlePUTRequest: aRequest respondTo: aResponse\x0a\x09| file stream |\x0a\x09(self isAuthenticated: aRequest)\x0a\x09\x09ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].\x0a\x0a\x09file := '.', aRequest url.\x0a\x09stream := fs createWriteStream: file.\x0a\x0a\x09stream on: 'error' do: [:error |\x0a\x09\x09console warn: 'Error creating WriteStream for file ', file.\x0a\x09\x09console warn: '    Did you forget to create the necessary js/ or st/ directory in your project?'.\x0a\x09\x09console warn: '    The exact error is: ', error.\x0a\x09\x09self respondNotCreatedTo: aResponse].\x0a\x0a\x09stream on: 'close' do: [\x0a\x09\x09self respondCreatedTo: aResponse].\x0a\x0a\x09aRequest setEncoding: 'utf8'.\x0a\x09aRequest on: 'data' do: [:data |\x0a\x09\x09stream write: data].\x0a\x0a\x09aRequest on: 'end' do: [\x0a\x09\x09stream writable ifTrue: [stream end]]",
+source: "handlePUTRequest: aRequest respondTo: aResponse\x0a\x09| file stream |\x0a\x09(self isAuthenticated: aRequest)\x0a\x09\x09ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].\x0a\x0a\x09file := '.', aRequest url.\x0a\x09stream := fs createWriteStream: file.\x0a\x0a\x09stream on: 'error' do: [:error |\x0a\x09\x09console warn: 'Error creating WriteStream for file ', file.\x0a\x09\x09console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.\x0a\x09\x09console warn: '    The exact error is: ', error.\x0a\x09\x09self respondNotCreatedTo: aResponse].\x0a\x0a\x09stream on: 'close' do: [\x0a\x09\x09self respondCreatedTo: aResponse].\x0a\x0a\x09aRequest setEncoding: 'utf8'.\x0a\x09aRequest on: 'data' do: [:data |\x0a\x09\x09stream write: data].\x0a\x0a\x09aRequest on: 'end' do: [\x0a\x09\x09stream writable ifTrue: [stream end]]",
 messageSends: ["ifFalse:", "isAuthenticated:", "respondAuthenticationRequiredTo:", ",", "url", "createWriteStream:", "on:do:", "warn:", "respondNotCreatedTo:", "respondCreatedTo:", "setEncoding:", "write:", "ifTrue:", "writable", "end"],
 referencedClasses: []
 }),
@@ -39673,11 +39648,11 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 _st(aResponse)._writeHead_options_((400),globals.HashedCollection._newFromPairs_(["Content-Type","text/plain"]));
-_st(aResponse)._write_("File could not be created. Did you forget to create the st/js directories on the server?");
+_st(aResponse)._write_("File could not be created. Did you forget to create the src directory on the server?");
 $1=_st(aResponse)._end();
 return self}, function($ctx1) {$ctx1.fill(self,"respondNotCreatedTo:",{aResponse:aResponse},globals.FileServer)})},
 args: ["aResponse"],
-source: "respondNotCreatedTo: aResponse\x0a\x09aResponse\x0a\x09\x09writeHead: 400 options: #{'Content-Type' -> 'text/plain'};\x0a\x09\x09write: 'File could not be created. Did you forget to create the st/js directories on the server?';\x0a\x09\x09end.",
+source: "respondNotCreatedTo: aResponse\x0a\x09aResponse\x0a\x09\x09writeHead: 400 options: #{'Content-Type' -> 'text/plain'};\x0a\x09\x09write: 'File could not be created. Did you forget to create the src directory on the server?';\x0a\x09\x09end.",
 messageSends: ["writeHead:options:", "write:", "end"],
 referencedClasses: []
 }),
@@ -40212,7 +40187,7 @@ globals.FileServer.klass);
 
 
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
-globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0d\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0d\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0d\x0a\x0d\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
+globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "addVariableNamed:to:",
@@ -40913,8 +40888,8 @@ globals.Repl.klass);
 
 });
 
-define("amber_vm/_init", ["amber_vm/smalltalk", "amber_vm/globals", "amber_vm/smalltalk","amber_vm/globals","amber_vm/nil","amber_core/Kernel-Objects","amber_core/Kernel-Classes","amber_core/Kernel-Methods","amber_core/Kernel-Collections","amber_core/Kernel-Infrastructure","amber_core/Kernel-Exceptions","amber_core/Kernel-Transcript","amber_core/Kernel-Announcements","amber_core/Compiler-Exceptions","amber_core/Compiler-Core","amber_core/Compiler-AST","amber_core/Compiler-IR","amber_core/Compiler-Inlining","amber_core/Compiler-Semantic","amber_core/Compiler-Interpreter","amber_vm/parser","amber_cli/AmberCli"], function (smalltalk, globals) {
-smalltalk.initialize();
+define("amber_vm/_init", ["amber_vm/smalltalk", "amber_vm/globals", "amber_vm/smalltalk","amber_vm/globals","amber_vm/nil","amber_core/Kernel-Objects","amber_core/Kernel-Classes","amber_core/Kernel-Methods","amber_core/Kernel-Collections","amber_core/Kernel-Infrastructure","amber_core/Kernel-Exceptions","amber_core/Kernel-Transcript","amber_core/Kernel-Announcements","amber_core/Compiler-Exceptions","amber_core/Compiler-Core","amber_core/Compiler-AST","amber_core/Compiler-IR","amber_core/Compiler-Inlining","amber_core/Compiler-Semantic","amber_core/Compiler-Interpreter","amber_vm/parser","amber_cli/AmberCli"], function (vm, globals) {
+vm.initialize();
 globals.AmberCli._main();
 });
 requirejs("amber_vm/_init");

+ 2 - 2
cli/support/amberc-cli.js

@@ -112,11 +112,11 @@ function print_usage() {
 		'',
 		'   *.js',
 		'     Files are linked (concatenated) in listed order.',
-		'     If not found we look in $AMBER/js/',
+		'     If not found we look in $AMBER/src/',
 		'',
 		'   *.st',
 		'     Files are compiled into .js files before concatenation.',
-		'     If not found we look in $AMBER/st/.',
+		'     If not found we look in $AMBER/src/',
 		'',
 		'     NOTE: Each .st file is currently considered to be a fileout of a single class',
 		'     category of the same name as the file!',

+ 4 - 3
cli/support/amberc.js

@@ -118,7 +118,7 @@ AmberCompiler.prototype.main = function(configuration, finished_callback) {
 	}
 
 	if (undefined !== configuration.jsLibraryDirs) {
-		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'js'));
+		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'src'));
 		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'support'));
 	}
 
@@ -178,7 +178,7 @@ function check_configuration(configuration) {
  * Check if the file given as parameter exists in any of the following directories:
  *  1. current local directory
  *  2. configuration.jsLibraryDirs
- *  3. $AMBER/js/
+ *  3. $AMBER/src/
  *  3. $AMBER/support/
  *
  * @param filename name of a file without '.js' prefix
@@ -468,7 +468,8 @@ function compose_js_files(configuration) {
 	return new Promise(function(resolve, reject) {
 		var programFile = configuration.program;
 		if (undefined === programFile) {
-			reject(configuration);
+			resolve(configuration);
+            return;
 		}
 		if (undefined !== configuration.output_dir) {
 			programFile = path.join(configuration.output_dir, programFile);

+ 2 - 4
cli/support/release-worker.sh

@@ -16,8 +16,7 @@ if [ "$VER" = "0" ]; then :; else
 	sed -e 's@/amber.git.*"@/amber.git#'"$VER"'"@' package.json.bak >package.json
 	rm package.json.bak
 	git add package.json
-	bin/amberc -m AmberCli -n amber_cli -l Compiler-Exceptions,Compiler-Core,Compiler-AST,Compiler-IR,Compiler-Inlining,Compiler-Semantic,Compiler-Interpreter,parser cli/st/AmberCli.st cli/support/amber-cli
-	rm cli/st/*.js
+	bin/amberc -m AmberCli -n amber_cli -l Compiler-Exceptions,Compiler-Core,Compiler-AST,Compiler-IR,Compiler-Inlining,Compiler-Semantic,Compiler-Interpreter,parser cli/src/AmberCli.st cli/support/amber-cli
 	git add cli/support/amber-cli.js
 	git commit -a -m "Release version $VER"
 	git tag -a "$VER" -m "Release version $VER"
@@ -33,8 +32,7 @@ cp package.json package.json.bak
 sed -e 's@/amber.git.*"@/amber.git"@' package.json.bak >package.json
 rm package.json.bak
 git add package.json
-bin/amberc -m AmberCli -n amber_cli -l Compiler-Exceptions,Compiler-Core,Compiler-AST,Compiler-IR,Compiler-Inlining,Compiler-Semantic,Compiler-Interpreter,parser cli/st/AmberCli.st cli/support/amber-cli
-rm cli/st/*.js
+bin/amberc -m AmberCli -n amber_cli -l Compiler-Exceptions,Compiler-Core,Compiler-AST,Compiler-IR,Compiler-Inlining,Compiler-Semantic,Compiler-Interpreter,parser cli/src/AmberCli.st cli/support/amber-cli
 git add cli/support/amber-cli.js
 git commit -a -m "Working on $VERF"
 git push --tags

+ 2 - 2
cli/support/setversion.sh

@@ -4,7 +4,7 @@ VERSION=$1
 cd `dirname "$0"`/../..
 AMBER_BASE=`pwd`
 
-cd $AMBER_BASE/st
+cd $AMBER_BASE/src
 # replace version number
 cp Kernel-Infrastructure.st Kernel-Infrastructure.st.bak
 sed -e "/^version\$/,/^\! \!\$/ s/\^ '[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\(-pre\)\{0,1\}'\$/^ '$VERSION'/" Kernel-Infrastructure.st.bak >Kernel-Infrastructure.st
@@ -12,7 +12,7 @@ rm Kernel-Infrastructure.st.bak
 
 # compile Kernel-Infrastructure
 cd $AMBER_BASE
-bin/amberc -D js -l Kernel-Objects,Kernel-Collections st/Kernel-Infrastructure.st
+bin/amberc -D src -l Kernel-Objects,Kernel-Collections src/Kernel-Infrastructure.st
 # set version in all json files (bower, npm)
 for F in *.json; do
   cp $F $F.bak

+ 47 - 10
css/helios.css

@@ -15,8 +15,11 @@ html[xmlns] .clearfix {
 * html .clearfix {
   height: 1%;
 }
+body.navigation .CodeMirror pre {
+  cursor: pointer !important;
+}
 .cm-s-helios.CodeMirror {
-  font-family: Menlo, Monaco, Consolas, Inconsolata, "Lucida Console", Courier, monospace;
+  font-family: Consolas, "Liberation Mono", Courier, monospace;
   line-height: 16px;
   font-size: 13px;
 }
@@ -533,6 +536,7 @@ body[id="helios"] .key_helper .command strong {
 body[id="helios"] .key_helper #binding-helper-main {
   display: block;
   padding: 5px;
+  background: #eee;
 }
 body[id="helios"] .key_helper .label {
   padding: 1px 4px;
@@ -622,16 +626,13 @@ body[id="helios"] #helper {
 }
 body[id="helios"] #overlay {
   z-index: 2000;
-  background: rgba(112, 66, 20, 0.1);
+  background: transparent;
   position: fixed;
   top: 0;
   left: 0;
   right: 0;
   bottom: 0;
 }
-body[id="helios"] #overlay.light {
-  background: rgba(50, 50, 50, 0.1);
-}
 body[id="helios"] .confirmation,
 body[id="helios"] .dialog {
   z-index: 2001;
@@ -647,10 +648,14 @@ body[id="helios"] .dialog {
   left: 50%;
   margin-left: -135px;
   box-shadow: 0 0 6px #333;
-  transition: top .5s;
-  -webkit-transition: top .5s;
-  -moz-transition: top .5s;
-  -o-transition: top .5s;
+  transition: top .2s;
+  -webkit-transition: top .2s;
+  -moz-transition: top .2s;
+  -o-transition: top .2s;
+}
+body[id="helios"] .confirmation .head,
+body[id="helios"] .dialog .head {
+  display: block;
 }
 body[id="helios"] .confirmation .hl_widget .form-actions,
 body[id="helios"] .dialog .hl_widget .form-actions {
@@ -686,6 +691,11 @@ body[id="helios"] .dialog textarea {
   display: block;
   width: 235px;
 }
+body[id="helios"] .confirmation input[type="text"],
+body[id="helios"] .dialog input[type="text"] {
+  margin: 5px 0;
+  width: 390px;
+}
 body[id="helios"] .confirmation .progress,
 body[id="helios"] .dialog .progress {
   height: 5px;
@@ -724,6 +734,10 @@ body[id="helios"] .button {
   margin: 0;
   margin-left: 10px;
   background: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, 0.04) 50.5%, rgba(0, 0, 0, 0.04) 100%) #ffffff;
+  background: -moz-linear-gradient(bottom, rgba(0, 0, 0, 0.09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, 0.04) 50.5%, rgba(0, 0, 0, 0.04) 100%) #ffffff;
+  background: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, 0.04) 50.5%, rgba(0, 0, 0, 0.04) 100%) #ffffff;
+  background: -ms-linear-gradient(bottom, rgba(0, 0, 0, 0.09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, 0.04) 50.5%, rgba(0, 0, 0, 0.04) 100%) #ffffff;
+  background: linear-gradient(bottom, rgba(0, 0, 0, 0.09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, 0.04) 50.5%, rgba(0, 0, 0, 0.04) 100%) #ffffff;
   font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
 }
 body[id="helios"] .button.default {
@@ -732,6 +746,9 @@ body[id="helios"] .button.default {
   border-bottom: 1px solid #4B4B58;
   background: -webkit-linear-gradient(bottom, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.3) 50.5%, rgba(255, 255, 255, 0.45) 95%, rgba(255, 255, 255, 0.8) 100%) #b1bdd5;
   background: -moz-linear-gradient(bottom, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.3) 50.5%, rgba(255, 255, 255, 0.45) 95%, rgba(255, 255, 255, 0.8) 100%) #b1bdd5;
+  background: -o-linear-gradient(bottom, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.3) 50.5%, rgba(255, 255, 255, 0.45) 95%, rgba(255, 255, 255, 0.8) 100%) #b1bdd5;
+  background: -ms-linear-gradient(bottom, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.3) 50.5%, rgba(255, 255, 255, 0.45) 95%, rgba(255, 255, 255, 0.8) 100%) #b1bdd5;
+  background: linear-gradient(bottom, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.3) 50.5%, rgba(255, 255, 255, 0.45) 95%, rgba(255, 255, 255, 0.8) 100%) #b1bdd5;
   -moz-box-shadow: 0 0 3px rgba(69, 113, 184, 0.8);
   -webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
   box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
@@ -762,11 +779,14 @@ body[id="helios"] .doc code {
   padding: 1px 4px;
 }
 body[id="helios"] .doc .head {
-  background: #08C;
+  background: #666;
   padding: 10px;
   font-size: 22px;
   color: white;
 }
+body[id="helios"] .focused .doc .head {
+  background: #08c;
+}
 body[id="helios"] .doc .button {
   float: right;
 }
@@ -803,3 +823,20 @@ body[id="helios"] .transcript textarea {
   padding: 0;
   border: 0;
 }
+body[id="helios"] .hl_debugger .tool_container {
+  top: 53px;
+}
+body[id="helios"] .hl_debugger .head {
+  position: absolute;
+  top: 23px;
+  width: 100%;
+  background: #0088cc url(/images/debugger.png) 10px center no-repeat;
+  border-bottom: 1px solid white;
+}
+body[id="helios"] .hl_debugger .head h2 {
+  font-size: 14px;
+  line-height: 30px;
+  padding: 0 30px;
+  margin: 0;
+  color: white;
+}

+ 56 - 11
css/helios.less

@@ -19,9 +19,13 @@ html[xmlns] .clearfix {
 	height: 1%;
 }
 
+body.navigation .CodeMirror pre {
+	cursor: pointer !important;
+}
+
 .cm-s-helios {
 	&.CodeMirror {
-		font-family: Menlo, Monaco, Consolas, Inconsolata, "Lucida Console", Courier, monospace;
+		font-family: Consolas, "Liberation Mono", Courier, monospace;
 		line-height: 16px;
 		font-size: 13px;
 	}
@@ -613,6 +617,7 @@ body[id="helios"] {
 		#binding-helper-main {
 			display: block;
 			padding: 5px;
+			background: #eee;
 		}
 
 		.label {
@@ -721,16 +726,12 @@ body[id="helios"] {
 
 	#overlay {
 		z-index: 2000;
-		background: rgba(112, 66, 20, 0.1);
+		background: transparent;
 		position: fixed;
 		top: 0;
 		left: 0;
 		right: 0;
 		bottom: 0;
-
-		&.light {
-			background: rgba(50, 50, 50, 0.1);
-		}
 	}
 
 	.confirmation, .dialog {
@@ -747,10 +748,14 @@ body[id="helios"] {
 		left: 50%;
 		margin-left: -135px;
 		box-shadow: 0 0 6px #333;
-		transition: top .5s;
-		-webkit-transition: top .5s;
-		-moz-transition: top .5s;
-		-o-transition: top .5s;
+		transition: top .2s;
+		-webkit-transition: top .2s;
+		-moz-transition: top .2s;
+		-o-transition: top .2s;
+
+		.head {
+			display: block;
+		}
 
 		.hl_widget {
 
@@ -789,6 +794,11 @@ body[id="helios"] {
 			width: 235px;
 		}
 
+		input[type="text"] {
+			margin: 5px 0;
+			width: 390px;
+		}
+
 		.progress {
 			height: 5px;
 
@@ -828,6 +838,10 @@ body[id="helios"] {
 		margin: 0;
 		margin-left: 10px;
 		background: -webkit-linear-gradient(bottom, rgba(0, 0, 0, .09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, .04) 50.5%, rgba(0, 0, 0, .04) 100%) #fff;
+		background: -moz-linear-gradient(bottom, rgba(0, 0, 0, .09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, .04) 50.5%, rgba(0, 0, 0, .04) 100%) #fff;
+		background: -o-linear-gradient(bottom, rgba(0, 0, 0, .09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, .04) 50.5%, rgba(0, 0, 0, .04) 100%) #fff;
+		background: -ms-linear-gradient(bottom, rgba(0, 0, 0, .09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, .04) 50.5%, rgba(0, 0, 0, .04) 100%) #fff;
+		background: linear-gradient(bottom, rgba(0, 0, 0, .09) 0%, rgba(0, 0, 0, 0.02) 50%, rgba(0, 0, 0, .04) 50.5%, rgba(0, 0, 0, .04) 100%) #fff;
 		font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
 	}
 
@@ -837,6 +851,9 @@ body[id="helios"] {
 		border-bottom: 1px solid #4B4B58;
 		background: -webkit-linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
 		background: -moz-linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
+		background: -o-linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
+		background: -ms-linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
+		background: linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
 		-moz-box-shadow: 0 0 3px rgba(69, 113, 184, 0.8);
 		-webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
 		box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
@@ -871,12 +888,16 @@ body[id="helios"] {
 		padding: 1px 4px;
 	}
 	.doc .head {
-		background: #08C;
+		background: #666;
 		padding: 10px;
 		font-size: 22px;
 		color: white;
 	}
 
+	.focused .doc .head {
+		background: #08c;
+	}
+
 	.doc .button {
 		float: right;
 	}
@@ -918,4 +939,28 @@ body[id="helios"] {
 		padding: 0;
 		border: 0;
 	}
+
+	.hl_debugger {
+		
+		.tool_container {
+			top: 53px;
+		}
+
+		.head {
+			position: absolute;
+			top: 23px;
+			width: 100%;
+			background: #08c url(/images/debugger.png) 10px center no-repeat;
+			border-bottom: 1px solid white;
+
+			h2 {
+				font-size: 14px;
+				line-height: 30px;
+				padding: 0 30px;
+				margin: 0;
+				color: white;
+			}
+		}
+	}
+
 }

+ 3 - 3
grunt/tasks/grunt-amberc.js

@@ -26,9 +26,9 @@ module.exports = function(grunt) {
            library_dirs: ['dir1', '/usr/local/js'], // optional
            verbose: true
          },
-         src: ['projects/HelloWorld/st/HelloWorld.st'], // REQUIRED
-         output_dir: 'projects/HelloWorld/js',  // optional
-         libraries: 'Canvas',                   // optional
+         src: ['projects/HelloWorld/src/HelloWorld.st'], // REQUIRED
+         output_dir: 'projects/HelloWorld/src',  // optional
+         libraries: 'Web',                       // optional
          jsGlobals: ['global1', 'global2'],     // optional
          main_class: 'HelloWorld',              // optional
          output_name: 'helloWorld',             // optional

+ 0 - 0
js/Benchfib.js → src/Benchfib.js


+ 0 - 0
js/Benchfib.st → src/Benchfib.st


+ 170 - 0
js/Compiler-AST.js → src/Compiler-AST.js

@@ -39,6 +39,53 @@ referencedClasses: []
 }),
 globals.Node);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "allNodes",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var allNodes;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=self._nodes();
+$ctx1.sendIdx["nodes"]=1;
+allNodes=_st($1)._asSet();
+_st(self._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(allNodes)._addAll_(_st(each)._allNodes());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+$2=allNodes;
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"allNodes",{allNodes:allNodes},globals.Node)})},
+args: [],
+source: "allNodes\x0a\x09| allNodes |\x0a\x09\x0a\x09allNodes := self nodes asSet.\x0a\x09self nodes do: [ :each | \x0a\x09\x09allNodes addAll: each allNodes ].\x0a\x09\x0a\x09^ allNodes",
+messageSends: ["asSet", "nodes", "do:", "addAll:", "allNodes"],
+referencedClasses: []
+}),
+globals.Node);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "inPosition:",
+protocol: 'testing',
+fn: function (aPoint){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self._positionStart()).__lt_eq(aPoint))._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._positionEnd()).__gt_eq(aPoint);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"inPosition:",{aPoint:aPoint},globals.Node)})},
+args: ["aPoint"],
+source: "inPosition: aPoint\x0a\x09^ (self positionStart <= aPoint and: [\x0a\x09\x09self positionEnd >= aPoint ])",
+messageSends: ["and:", "<=", "positionStart", ">=", "positionEnd"],
+referencedClasses: []
+}),
+globals.Node);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isAssignmentNode",
@@ -147,6 +194,21 @@ referencedClasses: []
 }),
 globals.Node);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isNavigationNode",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return false;
+},
+args: [],
+source: "isNavigationNode\x0a\x09\x22Answer true if the node can be navigated to\x22\x0a\x09\x0a\x09^ false",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Node);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isNode",
@@ -287,6 +349,48 @@ referencedClasses: []
 }),
 globals.Node);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "navigationNodeAt:ifAbsent:",
+protocol: 'accessing',
+fn: function (aPoint,aBlock){
+var self=this;
+var children;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$4,$3,$2;
+var $early={};
+try {
+children=_st(self._allNodes())._select_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(each)._isNavigationNode())._and_((function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(each)._inPosition_(aPoint);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+_st(children)._ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(aBlock)._value();
+throw $early=[$1];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+$2=_st(_st(_st(children)._asArray())._sort_((function(a,b){
+return smalltalk.withContext(function($ctx2) {
+$4=_st(a)._positionStart();
+$ctx2.sendIdx["positionStart"]=1;
+$3=_st($4)._dist_(aPoint);
+$ctx2.sendIdx["dist:"]=1;
+return _st($3).__lt_eq(_st(_st(b)._positionStart())._dist_(aPoint));
+}, function($ctx2) {$ctx2.fillBlock({a:a,b:b},$ctx1,4)})})))._first();
+return $2;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"navigationNodeAt:ifAbsent:",{aPoint:aPoint,aBlock:aBlock,children:children},globals.Node)})},
+args: ["aPoint", "aBlock"],
+source: "navigationNodeAt: aPoint ifAbsent: aBlock\x0a\x09\x22Answer the navigation node in the receiver's tree at aPoint \x0a\x09or nil if no navigation node was found.\x0a\x09\x0a\x09See `node >> isNaviationNode`\x22\x0a\x09\x0a\x09| children |\x0a\x09\x0a\x09children := self allNodes select: [ :each | \x0a\x09\x09each isNavigationNode and: [ each inPosition: aPoint ] ].\x0a\x09\x0a\x09children ifEmpty: [ ^ aBlock value ].\x0a\x09\x0a\x09^ (children asArray sort: [ :a :b | \x0a\x09\x09(a positionStart dist: aPoint) <= \x0a\x09\x09(b positionStart dist: aPoint) ]) first",
+messageSends: ["select:", "allNodes", "and:", "isNavigationNode", "inPosition:", "ifEmpty:", "value", "first", "sort:", "asArray", "<=", "dist:", "positionStart"],
+referencedClasses: []
+}),
+globals.Node);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "nextChild",
@@ -1742,6 +1846,21 @@ referencedClasses: []
 }),
 globals.SendNode);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isNavigationNode",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+},
+args: [],
+source: "isNavigationNode\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+globals.SendNode);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isSendNode",
@@ -1757,6 +1876,24 @@ referencedClasses: []
 }),
 globals.SendNode);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "navigationLink",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._selector();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"navigationLink",{},globals.SendNode)})},
+args: [],
+source: "navigationLink\x0a\x09^ self selector",
+messageSends: ["selector"],
+referencedClasses: []
+}),
+globals.SendNode);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "nodes",
@@ -2410,6 +2547,21 @@ referencedClasses: []
 }),
 globals.VariableNode);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isNavigationNode",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+},
+args: [],
+source: "isNavigationNode\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+globals.VariableNode);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isVariableNode",
@@ -2425,6 +2577,24 @@ referencedClasses: []
 }),
 globals.VariableNode);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "navigationLink",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"navigationLink",{},globals.VariableNode)})},
+args: [],
+source: "navigationLink\x0a\x09^ self value",
+messageSends: ["value"],
+referencedClasses: []
+}),
+globals.VariableNode);
+
 
 smalltalk.addMethod(
 smalltalk.method({

+ 55 - 0
js/Compiler-AST.st → src/Compiler-AST.st

@@ -16,10 +16,38 @@ addNode: aNode
 	aNode parent: self
 !
 
+allNodes
+	| allNodes |
+	
+	allNodes := self nodes asSet.
+	self nodes do: [ :each | 
+		allNodes addAll: each allNodes ].
+	
+	^ allNodes
+!
+
 method
 	^ self parent ifNotNil: [ :node | node method ]
 !
 
+navigationNodeAt: aPoint ifAbsent: aBlock
+	"Answer the navigation node in the receiver's tree at aPoint 
+	or nil if no navigation node was found.
+	
+	See `node >> isNaviationNode`"
+	
+	| children |
+	
+	children := self allNodes select: [ :each | 
+		each isNavigationNode and: [ each inPosition: aPoint ] ].
+	
+	children ifEmpty: [ ^ aBlock value ].
+	
+	^ (children asArray sort: [ :a :b | 
+		(a positionStart dist: aPoint) <= 
+		(b positionStart dist: aPoint) ]) first
+!
+
 nextChild
 	"Answer the next node after aNode.
 	Recurse into the possible children of the receiver to answer the next node to be evaluated"
@@ -122,6 +150,11 @@ postCopy
 
 !Node methodsFor: 'testing'!
 
+inPosition: aPoint
+	^ (self positionStart <= aPoint and: [
+		self positionEnd >= aPoint ])
+!
+
 isAssignmentNode
 	^ false
 !
@@ -150,6 +183,12 @@ isLastChild
 	^ self parent nodes last = self
 !
 
+isNavigationNode
+	"Answer true if the node can be navigated to"
+	
+	^ false
+!
+
 isNode
 	^ true
 !
@@ -530,6 +569,10 @@ index: anInteger
 	index := anInteger
 !
 
+navigationLink
+	^ self selector
+!
+
 nodes
 	self receiver ifNil: [ ^ self arguments copy ].
 	
@@ -582,6 +625,10 @@ isCascadeSendNode
 	^ self parent isCascadeNode
 !
 
+isNavigationNode
+	^ true
+!
+
 isSendNode
 	^ true
 !
@@ -740,6 +787,10 @@ binding
 
 binding: aScopeVar
 	binding := aScopeVar
+!
+
+navigationLink
+	^ self value
 ! !
 
 !VariableNode methodsFor: 'testing'!
@@ -752,6 +803,10 @@ isImmutable
 	^ self binding isImmutable
 !
 
+isNavigationNode
+	^ true
+!
+
 isVariableNode
 	^ true
 ! !

+ 0 - 24
js/Compiler-Core.js → src/Compiler-Core.js

@@ -687,30 +687,6 @@ globals.Compiler.klass);
 
 smalltalk.addClass('DoIt', globals.Object, [], 'Compiler-Core');
 globals.DoIt.comment="`DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "foo",
-protocol: 'tests',
-fn: function (){
-var self=this;
-function $Array(){return globals.Array||(typeof Array=="undefined"?nil:Array)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=_st($Array())._new();
-_st($2)._add_((3));
-$ctx1.sendIdx["add:"]=1;
-_st($2)._add_((4));
-$3=_st($2)._yourself();
-$1=$3;
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"foo",{},globals.DoIt)})},
-args: [],
-source: "foo ^ Array new add: 3; add: 4; yourself",
-messageSends: ["add:", "new", "yourself"],
-referencedClasses: ["Array"]
-}),
-globals.DoIt);
-
 
 
 smalltalk.addClass('NodeVisitor', globals.Object, [], 'Compiler-Core');

+ 0 - 5
js/Compiler-Core.st → src/Compiler-Core.st

@@ -223,11 +223,6 @@ Object subclass: #DoIt
 !DoIt commentStamp!
 `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
 
-!DoIt methodsFor: 'tests'!
-
-foo ^ Array new add: 3; add: 4; yourself
-! !
-
 Object subclass: #NodeVisitor
 	instanceVariableNames: ''
 	package: 'Compiler-Core'!

+ 0 - 0
js/Compiler-Exceptions.js → src/Compiler-Exceptions.js


+ 0 - 0
js/Compiler-Exceptions.st → src/Compiler-Exceptions.st


+ 0 - 0
js/Compiler-IR.js → src/Compiler-IR.js


+ 0 - 0
js/Compiler-IR.st → src/Compiler-IR.st


+ 0 - 0
js/Compiler-Inlining.js → src/Compiler-Inlining.js


+ 0 - 0
js/Compiler-Inlining.st → src/Compiler-Inlining.st


+ 0 - 0
js/Compiler-Interpreter.js → src/Compiler-Interpreter.js


+ 0 - 0
js/Compiler-Interpreter.st → src/Compiler-Interpreter.st


+ 0 - 0
js/Compiler-Semantic.js → src/Compiler-Semantic.js


+ 0 - 0
js/Compiler-Semantic.st → src/Compiler-Semantic.st


+ 49 - 0
js/Compiler-Tests.js → src/Compiler-Tests.js

@@ -269,6 +269,55 @@ globals.ASTPCNodeVisitorTest);
 
 
 
+smalltalk.addClass('ASTPositionTest', globals.ASTParsingTest, [], 'Compiler-Tests');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testNodeAtPosition",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var node;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$4,$2,$1,$7,$8,$6,$5;
+node=self._parse_("yourself\x0a\x09^ self");
+$ctx1.sendIdx["parse:"]=1;
+$3=node;
+$4=(2).__at((4));
+$ctx1.sendIdx["@"]=1;
+$2=_st($3)._navigationNodeAt_ifAbsent_($4,(function(){
+return nil;
+}));
+$ctx1.sendIdx["navigationNodeAt:ifAbsent:"]=1;
+$1=_st($2)._source();
+self._assert_equals_($1,"self");
+$ctx1.sendIdx["assert:equals:"]=1;
+node=self._parse_("foo\x0a\x09true ifTrue: [ 1 ]");
+$ctx1.sendIdx["parse:"]=2;
+$7=node;
+$8=(2).__at((7));
+$ctx1.sendIdx["@"]=2;
+$6=_st($7)._navigationNodeAt_ifAbsent_($8,(function(){
+return nil;
+}));
+$ctx1.sendIdx["navigationNodeAt:ifAbsent:"]=2;
+$5=_st($6)._selector();
+$ctx1.sendIdx["selector"]=1;
+self._assert_equals_($5,"ifTrue:");
+$ctx1.sendIdx["assert:equals:"]=2;
+node=self._parse_("foo\x0a\x09self foo; bar; baz");
+self._assert_equals_(_st(_st(node)._navigationNodeAt_ifAbsent_((2).__at((8)),(function(){
+return nil;
+})))._selector(),"foo");
+return self}, function($ctx1) {$ctx1.fill(self,"testNodeAtPosition",{node:node},globals.ASTPositionTest)})},
+args: [],
+source: "testNodeAtPosition\x0a\x09| node |\x0a\x09\x0a\x09node := self parse: 'yourself\x0a\x09^ self'.\x0a\x09\x0a\x09self assert: (node navigationNodeAt: 2@4 ifAbsent: [ nil ]) source equals: 'self'.\x0a\x09\x0a\x09node := self parse: 'foo\x0a\x09true ifTrue: [ 1 ]'.\x0a\x09\x0a\x09self assert: (node navigationNodeAt: 2@7 ifAbsent: [ nil ]) selector equals: 'ifTrue:'.\x0a\x09\x0a\x09node := self parse: 'foo\x0a\x09self foo; bar; baz'.\x0a\x09\x0a\x09self assert: (node navigationNodeAt: 2@8 ifAbsent: [ nil ]) selector equals: 'foo'",
+messageSends: ["parse:", "assert:equals:", "source", "navigationNodeAt:ifAbsent:", "@", "selector"],
+referencedClasses: []
+}),
+globals.ASTPositionTest);
+
+
+
 smalltalk.addClass('CodeGeneratorTest', globals.ASTParsingTest, ['receiver'], 'Compiler-Tests');
 smalltalk.addMethod(
 smalltalk.method({

+ 25 - 0
js/Compiler-Tests.st → src/Compiler-Tests.st

@@ -102,6 +102,31 @@ testPC
 		currentNode) isJSStatementNode
 ! !
 
+ASTParsingTest subclass: #ASTPositionTest
+	instanceVariableNames: ''
+	package: 'Compiler-Tests'!
+
+!ASTPositionTest methodsFor: 'tests'!
+
+testNodeAtPosition
+	| node |
+	
+	node := self parse: 'yourself
+	^ self'.
+	
+	self assert: (node navigationNodeAt: 2@4 ifAbsent: [ nil ]) source equals: 'self'.
+	
+	node := self parse: 'foo
+	true ifTrue: [ 1 ]'.
+	
+	self assert: (node navigationNodeAt: 2@7 ifAbsent: [ nil ]) selector equals: 'ifTrue:'.
+	
+	node := self parse: 'foo
+	self foo; bar; baz'.
+	
+	self assert: (node navigationNodeAt: 2@8 ifAbsent: [ nil ]) selector equals: 'foo'
+! !
+
 ASTParsingTest subclass: #CodeGeneratorTest
 	instanceVariableNames: 'receiver'
 	package: 'Compiler-Tests'!

+ 1 - 1
js/Examples.js → src/Examples.js

@@ -1,4 +1,4 @@
-define("amber_core/Examples", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Canvas"], function(smalltalk,nil,_st, globals){
+define("amber_core/Examples", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Web"], function(smalltalk,nil,_st, globals){
 smalltalk.addPackage('Examples');
 smalltalk.packages["Examples"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 0 - 0
js/Examples.st → src/Examples.st


+ 3 - 12
js/Helios-Announcements.js → src/Helios-Announcements.js

@@ -118,18 +118,6 @@ smalltalk.addClass('HLDoItExecuted', globals.HLCodeHandled, [], 'Helios-Announce
 globals.HLDoItExecuted.comment="I am emitted by a `HLCodeWidget` after a DoIt has been executed.";
 
 
-smalltalk.addClass('HLDoItRequested', globals.HLCodeHandled, [], 'Helios-Announcements');
-globals.HLDoItRequested.comment="I am emitted by a `HLCodeWidget` before a DoIt is executed.";
-
-
-smalltalk.addClass('HLInspectItRequested', globals.HLCodeHandled, [], 'Helios-Announcements');
-globals.HLInspectItRequested.comment="I am emitted by a `HLCodeWidget` before an object is inspected.";
-
-
-smalltalk.addClass('HLPrintItRequested', globals.HLCodeHandled, [], 'Helios-Announcements');
-globals.HLPrintItRequested.comment="I am emitted by a `HLCodeWidget` before an object is printed.";
-
-
 smalltalk.addClass('HLDebuggerAnnouncement', globals.HLAnnouncement, ['context'], 'Helios-Announcements');
 globals.HLDebuggerAnnouncement.comment="I am the root class of debugger announcements, and hold onto the debugged `context`.";
 smalltalk.addMethod(
@@ -360,6 +348,9 @@ smalltalk.addClass('HLFocusRequested', globals.HLAnnouncement, [], 'Helios-Annou
 smalltalk.addClass('HLClassesFocusRequested', globals.HLFocusRequested, [], 'Helios-Announcements');
 
 
+smalltalk.addClass('HLDocumentationFocusRequested', globals.HLFocusRequested, [], 'Helios-Announcements');
+
+
 smalltalk.addClass('HLMethodsFocusRequested', globals.HLFocusRequested, [], 'Helios-Announcements');
 
 

+ 4 - 18
js/Helios-Announcements.st → src/Helios-Announcements.st

@@ -62,24 +62,6 @@ HLCodeHandled subclass: #HLDoItExecuted
 !HLDoItExecuted commentStamp!
 I am emitted by a `HLCodeWidget` after a DoIt has been executed.!
 
-HLCodeHandled subclass: #HLDoItRequested
-	instanceVariableNames: ''
-	package: 'Helios-Announcements'!
-!HLDoItRequested commentStamp!
-I am emitted by a `HLCodeWidget` before a DoIt is executed.!
-
-HLCodeHandled subclass: #HLInspectItRequested
-	instanceVariableNames: ''
-	package: 'Helios-Announcements'!
-!HLInspectItRequested commentStamp!
-I am emitted by a `HLCodeWidget` before an object is inspected.!
-
-HLCodeHandled subclass: #HLPrintItRequested
-	instanceVariableNames: ''
-	package: 'Helios-Announcements'!
-!HLPrintItRequested commentStamp!
-I am emitted by a `HLCodeWidget` before an object is printed.!
-
 HLAnnouncement subclass: #HLDebuggerAnnouncement
 	instanceVariableNames: 'context'
 	package: 'Helios-Announcements'!
@@ -188,6 +170,10 @@ HLFocusRequested subclass: #HLClassesFocusRequested
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!
 
+HLFocusRequested subclass: #HLDocumentationFocusRequested
+	instanceVariableNames: ''
+	package: 'Helios-Announcements'!
+
 HLFocusRequested subclass: #HLMethodsFocusRequested
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!

+ 120 - 27
js/Helios-Browser.js → src/Helios-Browser.js

@@ -707,6 +707,23 @@ referencedClasses: ["HLClassesFocusRequested"]
 }),
 globals.HLBrowserModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "focusOnDocumentation",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLDocumentationFocusRequested(){return globals.HLDocumentationFocusRequested||(typeof HLDocumentationFocusRequested=="undefined"?nil:HLDocumentationFocusRequested)}
+return smalltalk.withContext(function($ctx1) { 
+_st(self._announcer())._announce_(_st($HLDocumentationFocusRequested())._new());
+return self}, function($ctx1) {$ctx1.fill(self,"focusOnDocumentation",{},globals.HLBrowserModel)})},
+args: [],
+source: "focusOnDocumentation\x0a\x09self announcer announce: HLDocumentationFocusRequested new",
+messageSends: ["announce:", "announcer", "new"],
+referencedClasses: ["HLDocumentationFocusRequested"]
+}),
+globals.HLBrowserModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "focusOnMethods",
@@ -1848,7 +1865,7 @@ return self._renderItemLabel_level_on_(aClass,anInteger,html);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
 $5=_st($4)._onClick_((function(){
 return smalltalk.withContext(function($ctx3) {
-return self._activateListItem_(_st(li)._asJQuery());
+return self._reactivateListItem_(_st(li)._asJQuery());
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
 return $5;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
@@ -1859,8 +1876,8 @@ return self._renderItem_level_on_(each,_st(anInteger).__plus((1)),html);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,4)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderItem:level:on:",{aClass:aClass,anInteger:anInteger,html:html,li:li},globals.HLClassesListWidget)})},
 args: ["aClass", "anInteger", "html"],
-source: "renderItem: aClass level: anInteger on: html\x0a\x09| li |\x0a    \x0a\x09li := html li.\x0a\x09li asJQuery data: 'item' put: aClass.\x0a    li\x0a\x09\x09class: (self listCssClassForItem: aClass);\x0a\x09\x09with: [ \x0a        \x09html a\x0a            \x09with: [ \x0a            \x09\x09(html tag: 'i') class: (self cssClassForItem: aClass).\x0a  \x09\x09\x09\x09\x09self renderItemLabel: aClass level: anInteger on: html ];\x0a\x09\x09\x09\x09onClick: [\x0a                  \x09self activateListItem: li asJQuery ] ].\x0a                    \x0a    (self getChildrenOf: aClass) do: [ :each |\x0a    \x09self renderItem: each level: anInteger + 1 on: html ]",
-messageSends: ["li", "data:put:", "asJQuery", "class:", "listCssClassForItem:", "with:", "a", "tag:", "cssClassForItem:", "renderItemLabel:level:on:", "onClick:", "activateListItem:", "do:", "getChildrenOf:", "renderItem:level:on:", "+"],
+source: "renderItem: aClass level: anInteger on: html\x0a\x09| li |\x0a    \x0a\x09li := html li.\x0a\x09li asJQuery data: 'item' put: aClass.\x0a    li\x0a\x09\x09class: (self listCssClassForItem: aClass);\x0a\x09\x09with: [ \x0a        \x09html a\x0a            \x09with: [ \x0a            \x09\x09(html tag: 'i') class: (self cssClassForItem: aClass).\x0a  \x09\x09\x09\x09\x09self renderItemLabel: aClass level: anInteger on: html ];\x0a\x09\x09\x09\x09onClick: [\x0a                  \x09self reactivateListItem: li asJQuery ] ].\x0a                    \x0a    (self getChildrenOf: aClass) do: [ :each |\x0a    \x09self renderItem: each level: anInteger + 1 on: html ]",
+messageSends: ["li", "data:put:", "asJQuery", "class:", "listCssClassForItem:", "with:", "a", "tag:", "cssClassForItem:", "renderItemLabel:level:on:", "onClick:", "reactivateListItem:", "do:", "getChildrenOf:", "renderItem:level:on:", "+"],
 referencedClasses: []
 }),
 globals.HLClassesListWidget);
@@ -1945,6 +1962,22 @@ referencedClasses: []
 }),
 globals.HLClassesListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "reselectItem:",
+protocol: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._forceSelectedClass_(anItem);
+return self}, function($ctx1) {$ctx1.fill(self,"reselectItem:",{anItem:anItem},globals.HLClassesListWidget)})},
+args: ["anItem"],
+source: "reselectItem: anItem\x0a\x09self model forceSelectedClass: anItem",
+messageSends: ["forceSelectedClass:", "model"],
+referencedClasses: []
+}),
+globals.HLClassesListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectItem:",
@@ -2256,17 +2289,20 @@ fn: function (){
 var self=this;
 function $HLClassSelected(){return globals.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 function $HLEditComment(){return globals.HLEditComment||(typeof HLEditComment=="undefined"?nil:HLEditComment)}
+function $HLDocumentationFocusRequested(){return globals.HLDocumentationFocusRequested||(typeof HLDocumentationFocusRequested=="undefined"?nil:HLDocumentationFocusRequested)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 $1=_st(self._model())._announcer();
 _st($1)._on_send_to_($HLClassSelected(),"onClassSelected:",self);
 $ctx1.sendIdx["on:send:to:"]=1;
-$2=_st($1)._on_send_to_($HLEditComment(),"onEditDocumentation",self);
+_st($1)._on_send_to_($HLEditComment(),"onEditDocumentation",self);
+$ctx1.sendIdx["on:send:to:"]=2;
+$2=_st($1)._on_send_to_($HLDocumentationFocusRequested(),"onDocumentationFocusRequested",self);
 return self}, function($ctx1) {$ctx1.fill(self,"observeModel",{},globals.HLDocumentationWidget)})},
 args: [],
-source: "observeModel\x0a\x09self model announcer \x0a\x09\x09on: HLClassSelected\x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLEditComment\x0a\x09\x09send: #onEditDocumentation\x0a\x09\x09to: self",
+source: "observeModel\x0a\x09self model announcer \x0a\x09\x09on: HLClassSelected\x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLEditComment\x0a\x09\x09send: #onEditDocumentation\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLDocumentationFocusRequested\x0a\x09\x09send: #onDocumentationFocusRequested\x0a\x09\x09to: self",
 messageSends: ["on:send:to:", "announcer", "model"],
-referencedClasses: ["HLClassSelected", "HLEditComment"]
+referencedClasses: ["HLClassSelected", "HLEditComment", "HLDocumentationFocusRequested"]
 }),
 globals.HLDocumentationWidget);
 
@@ -2294,15 +2330,24 @@ protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(_st(anAnnouncement)._theClass()).__eq(_st(_st(self._model())._selectedClass())._theNonMetaClass());
-if(smalltalk.assert($1)){
+var $2,$1,$3;
+$2=self._model();
+$ctx1.sendIdx["model"]=1;
+$1=_st($2)._selectedClass();
+$ctx1.sendIdx["selectedClass"]=1;
+if(($receiver = $1) == nil || $receiver == null){
+return self;
+} else {
+$1;
+};
+$3=_st(_st(anAnnouncement)._theClass()).__eq(_st(_st(self._model())._selectedClass())._theNonMetaClass());
+if(smalltalk.assert($3)){
 self._refresh();
 };
 return self}, function($ctx1) {$ctx1.fill(self,"onClassCommentChanged:",{anAnnouncement:anAnnouncement},globals.HLDocumentationWidget)})},
 args: ["anAnnouncement"],
-source: "onClassCommentChanged: anAnnouncement\x0a\x09anAnnouncement theClass = self model selectedClass theNonMetaClass\x0a\x09\x09ifTrue: [ self refresh ]",
-messageSends: ["ifTrue:", "=", "theClass", "theNonMetaClass", "selectedClass", "model", "refresh"],
+source: "onClassCommentChanged: anAnnouncement\x0a\x09self model selectedClass ifNil: [ ^ self ].\x0a\x09\x0a\x09anAnnouncement theClass = self model selectedClass theNonMetaClass\x0a\x09\x09ifTrue: [ self refresh ]",
+messageSends: ["ifNil:", "selectedClass", "model", "ifTrue:", "=", "theClass", "theNonMetaClass", "refresh"],
 referencedClasses: []
 }),
 globals.HLDocumentationWidget);
@@ -2323,6 +2368,22 @@ referencedClasses: []
 }),
 globals.HLDocumentationWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onDocumentationFocusRequested",
+protocol: 'reactions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._focus();
+return self}, function($ctx1) {$ctx1.fill(self,"onDocumentationFocusRequested",{},globals.HLDocumentationWidget)})},
+args: [],
+source: "onDocumentationFocusRequested\x0a\x09self focus",
+messageSends: ["focus"],
+referencedClasses: []
+}),
+globals.HLDocumentationWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "onEditDocumentation",
@@ -3133,6 +3194,22 @@ referencedClasses: []
 }),
 globals.HLMethodsListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "reselectItem:",
+protocol: 'actions',
+fn: function (aSelector){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._forceSelectedMethod_(self._methodForSelector_(aSelector));
+return self}, function($ctx1) {$ctx1.fill(self,"reselectItem:",{aSelector:aSelector},globals.HLMethodsListWidget)})},
+args: ["aSelector"],
+source: "reselectItem: aSelector\x0a\x09self model forceSelectedMethod: (self methodForSelector: aSelector)",
+messageSends: ["forceSelectedMethod:", "model", "methodForSelector:"],
+referencedClasses: []
+}),
+globals.HLMethodsListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectItem:",
@@ -3261,22 +3338,6 @@ globals.HLMethodsListWidget.klass);
 
 smalltalk.addClass('HLPackagesListWidget', globals.HLToolListWidget, [], 'Helios-Browser');
 globals.HLPackagesListWidget.comment="I render a list of the system packages.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "commitPackage",
-protocol: 'actions',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self._model())._commitPackage();
-return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLPackagesListWidget)})},
-args: [],
-source: "commitPackage\x0a\x09self model commitPackage",
-messageSends: ["commitPackage", "model"],
-referencedClasses: []
-}),
-globals.HLPackagesListWidget);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "cssClassForItem:",
@@ -3515,6 +3576,22 @@ referencedClasses: []
 }),
 globals.HLPackagesListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "reselectItem:",
+protocol: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._forceSelectedPackage_(anItem);
+return self}, function($ctx1) {$ctx1.fill(self,"reselectItem:",{anItem:anItem},globals.HLPackagesListWidget)})},
+args: ["anItem"],
+source: "reselectItem: anItem\x0a\x09self model forceSelectedPackage: anItem",
+messageSends: ["forceSelectedPackage:", "model"],
+referencedClasses: []
+}),
+globals.HLPackagesListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectItem:",
@@ -3808,6 +3885,22 @@ referencedClasses: []
 }),
 globals.HLProtocolsListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "reselectItem:",
+protocol: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._forceSelectedProtocol_(anItem);
+return self}, function($ctx1) {$ctx1.fill(self,"reselectItem:",{anItem:anItem},globals.HLProtocolsListWidget)})},
+args: ["anItem"],
+source: "reselectItem: anItem\x0a\x09self model forceSelectedProtocol: anItem",
+messageSends: ["forceSelectedProtocol:", "model"],
+referencedClasses: []
+}),
+globals.HLProtocolsListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectItem:",

+ 31 - 5
js/Helios-Browser.st → src/Helios-Browser.st

@@ -263,6 +263,10 @@ focusOnClasses
 	self announcer announce: HLClassesFocusRequested new
 !
 
+focusOnDocumentation
+	self announcer announce: HLDocumentationFocusRequested new
+!
+
 focusOnMethods
 	self announcer announce: HLMethodsFocusRequested new
 !
@@ -499,6 +503,10 @@ observeSystem
 		to: self
 !
 
+reselectItem: anItem
+	self model forceSelectedClass: anItem
+!
+
 selectItem: aClass
     self model selectedClass: aClass
 !
@@ -684,7 +692,7 @@ renderItem: aClass level: anInteger on: html
             		(html tag: 'i') class: (self cssClassForItem: aClass).
   					self renderItemLabel: aClass level: anInteger on: html ];
 				onClick: [
-                  	self activateListItem: li asJQuery ] ].
+                  	self reactivateListItem: li asJQuery ] ].
                     
     (self getChildrenOf: aClass) do: [ :each |
     	self renderItem: each level: anInteger + 1 on: html ]
@@ -775,6 +783,10 @@ observeModel
 		
 		on: HLEditComment
 		send: #onEditDocumentation
+		to: self;
+		
+		on: HLDocumentationFocusRequested
+		send: #onDocumentationFocusRequested
 		to: self
 !
 
@@ -807,6 +819,8 @@ defaultHead
 !HLDocumentationWidget methodsFor: 'reactions'!
 
 onClassCommentChanged: anAnnouncement
+	self model selectedClass ifNil: [ ^ self ].
+	
 	anAnnouncement theClass = self model selectedClass theNonMetaClass
 		ifTrue: [ self refresh ]
 !
@@ -815,6 +829,10 @@ onClassSelected: anAnnouncement
 	self refresh
 !
 
+onDocumentationFocusRequested
+	self focus
+!
+
 onEditDocumentation
 	self 
 		request: self model selectedClass theNonMetaClass name, ' comment'
@@ -993,6 +1011,10 @@ observeSystem
 		to: self
 !
 
+reselectItem: aSelector
+	self model forceSelectedMethod: (self methodForSelector: aSelector)
+!
+
 selectItem: aSelector
 	aSelector ifNil: [ ^ self model selectedMethod: nil ].
 
@@ -1147,10 +1169,6 @@ label
 
 !HLPackagesListWidget methodsFor: 'actions'!
 
-commitPackage
-	self model commitPackage
-!
-
 focusClassesListWidget
 	self model announcer announce: HLClassesListFocus new
 !
@@ -1178,6 +1196,10 @@ observeSystem
 		to: self
 !
 
+reselectItem: anItem
+	self model forceSelectedPackage: anItem
+!
+
 selectItem: aPackage
 	super selectItem: aPackage.
 	self model selectedPackage: aPackage
@@ -1289,6 +1311,10 @@ observeSystem
 		to: self
 !
 
+reselectItem: anItem
+	self model forceSelectedProtocol: anItem
+!
+
 selectItem: aString
     self model selectedProtocol: aString
 ! !

+ 49 - 0
js/Helios-Commands-Browser.js → src/Helios-Commands-Browser.js

@@ -123,6 +123,55 @@ referencedClasses: []
 globals.HLGoToClassesCommand.klass);
 
 
+smalltalk.addClass('HLGoToDocumentationCommand', globals.HLBrowserGoToCommand, [], 'Helios-Commands-Browser');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._focusOnDocumentation();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLGoToDocumentationCommand)})},
+args: [],
+source: "execute\x0a\x09self model focusOnDocumentation",
+messageSends: ["focusOnDocumentation", "model"],
+referencedClasses: []
+}),
+globals.HLGoToDocumentationCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "d";
+},
+args: [],
+source: "key\x0a\x09^ 'd'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLGoToDocumentationCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Documentation";
+},
+args: [],
+source: "label\x0a\x09^ 'Documentation'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLGoToDocumentationCommand.klass);
+
+
 smalltalk.addClass('HLGoToMethodsCommand', globals.HLBrowserGoToCommand, [], 'Helios-Commands-Browser');
 smalltalk.addMethod(
 smalltalk.method({

+ 20 - 0
js/Helios-Commands-Browser.st → src/Helios-Commands-Browser.st

@@ -49,6 +49,26 @@ label
 	^ 'Classes'
 ! !
 
+HLBrowserGoToCommand subclass: #HLGoToDocumentationCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-Browser'!
+
+!HLGoToDocumentationCommand methodsFor: 'executing'!
+
+execute
+	self model focusOnDocumentation
+! !
+
+!HLGoToDocumentationCommand class methodsFor: 'accessing'!
+
+key
+	^ 'd'
+!
+
+label
+	^ 'Documentation'
+! !
+
 HLBrowserGoToCommand subclass: #HLGoToMethodsCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-Browser'!

+ 52 - 0
js/Helios-Commands-Core.js → src/Helios-Commands-Core.js

@@ -768,6 +768,58 @@ referencedClasses: []
 globals.HLOpenBrowserCommand.klass);
 
 
+smalltalk.addClass('HLOpenSUnitCommand', globals.HLOpenCommand, [], 'Helios-Commands-Core');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+function $HLSUnit(){return globals.HLSUnit||(typeof HLSUnit=="undefined"?nil:HLSUnit)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($HLSUnit())._openAsTab();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLOpenSUnitCommand)})},
+args: [],
+source: "execute\x0a\x09^ HLSUnit openAsTab",
+messageSends: ["openAsTab"],
+referencedClasses: ["HLSUnit"]
+}),
+globals.HLOpenSUnitCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "s";
+},
+args: [],
+source: "key\x0a\x09^ 's'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLOpenSUnitCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "SUnit";
+},
+args: [],
+source: "label\x0a\x09^ 'SUnit'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLOpenSUnitCommand.klass);
+
+
 smalltalk.addClass('HLOpenWorkspaceCommand', globals.HLOpenCommand, [], 'Helios-Commands-Core');
 smalltalk.addMethod(
 smalltalk.method({

+ 20 - 0
js/Helios-Commands-Core.st → src/Helios-Commands-Core.st

@@ -253,6 +253,26 @@ label
 	^ 'Browser'
 ! !
 
+HLOpenCommand subclass: #HLOpenSUnitCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-Core'!
+
+!HLOpenSUnitCommand methodsFor: 'executing'!
+
+execute
+	^ HLSUnit openAsTab
+! !
+
+!HLOpenSUnitCommand class methodsFor: 'accessing'!
+
+key
+	^ 's'
+!
+
+label
+	^ 'SUnit'
+! !
+
 HLOpenCommand subclass: #HLOpenWorkspaceCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-Core'!

+ 66 - 7
js/Helios-Commands-Tools.js → src/Helios-Commands-Tools.js

@@ -157,6 +157,28 @@ referencedClasses: []
 }),
 globals.HLCommitPackageCommand);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitPackage",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._commitPackageOnSuccess_onError_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._informSuccess();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(error){
+return smalltalk.withContext(function($ctx2) {
+return self._onPackageCommitError_(error);
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLCommitPackageCommand)})},
+args: [],
+source: "commitPackage\x0a\x09self model \x0a\x09\x09commitPackageOnSuccess: [ self informSuccess ]\x0a\x09\x09onError: [ :error | self onPackageCommitError: error ]",
+messageSends: ["commitPackageOnSuccess:onError:", "model", "informSuccess", "onPackageCommitError:"],
+referencedClasses: []
+}),
+globals.HLCommitPackageCommand);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "execute",
@@ -164,15 +186,35 @@ protocol: 'executing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._model())._commitPackage();
+self._commitPackage();
 return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLCommitPackageCommand)})},
 args: [],
-source: "execute\x0a\x09self model commitPackage",
-messageSends: ["commitPackage", "model"],
+source: "execute\x0a\x09self commitPackage",
+messageSends: ["commitPackage"],
 referencedClasses: []
 }),
 globals.HLCommitPackageCommand);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "informSuccess",
+protocol: 'executing',
+fn: function (){
+var self=this;
+function $HLInformationWidget(){return globals.HLInformationWidget||(typeof HLInformationWidget=="undefined"?nil:HLInformationWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($HLInformationWidget())._new();
+_st($1)._informationString_("Commit successful!");
+$2=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"informSuccess",{},globals.HLCommitPackageCommand)})},
+args: [],
+source: "informSuccess\x0a\x09HLInformationWidget new\x0a\x09\x09informationString: 'Commit successful!';\x0a\x09\x09show",
+messageSends: ["informationString:", "new", "show"],
+referencedClasses: ["HLInformationWidget"]
+}),
+globals.HLCommitPackageCommand);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isActive",
@@ -182,12 +224,29 @@ var self=this;
 return true;
 },
 args: [],
-source: "isActive\x0a\x09^ true\x0a\x09\x22 slf model isPackageDirty\x22",
+source: "isActive\x0a\x09^ true\x0a\x09\x22self model isPackageDirty\x22",
 messageSends: [],
 referencedClasses: []
 }),
 globals.HLCommitPackageCommand);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onPackageCommitError:",
+protocol: 'error handling',
+fn: function (anError){
+var self=this;
+function $HLPackageCommitErrorHelper(){return globals.HLPackageCommitErrorHelper||(typeof HLPackageCommitErrorHelper=="undefined"?nil:HLPackageCommitErrorHelper)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st($HLPackageCommitErrorHelper())._on_(self._model()))._showHelp();
+return self}, function($ctx1) {$ctx1.fill(self,"onPackageCommitError:",{anError:anError},globals.HLCommitPackageCommand)})},
+args: ["anError"],
+source: "onPackageCommitError: anError\x0a\x09(HLPackageCommitErrorHelper on: self model)\x0a\x09\x09showHelp",
+messageSends: ["showHelp", "on:", "model"],
+referencedClasses: ["HLPackageCommitErrorHelper"]
+}),
+globals.HLCommitPackageCommand);
+
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -277,12 +336,12 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(_st(self._model())._selectedClass())._name();
+$1=_st(_st(_st(self._model())._selectedClass())._theNonMetaClass())._name();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"defaultInput",{},globals.HLCopyClassCommand)})},
 args: [],
-source: "defaultInput\x0a\x09^ self model selectedClass name",
-messageSends: ["name", "selectedClass", "model"],
+source: "defaultInput\x0a\x09^ self model selectedClass theNonMetaClass name",
+messageSends: ["name", "theNonMetaClass", "selectedClass", "model"],
 referencedClasses: []
 }),
 globals.HLCopyClassCommand);

+ 22 - 3
js/Helios-Commands-Tools.st → src/Helios-Commands-Tools.st

@@ -65,17 +65,36 @@ category
 	^ 'Packages'
 ! !
 
+!HLCommitPackageCommand methodsFor: 'error handling'!
+
+onPackageCommitError: anError
+	(HLPackageCommitErrorHelper on: self model)
+		showHelp
+! !
+
 !HLCommitPackageCommand methodsFor: 'executing'!
 
+commitPackage
+	self model 
+		commitPackageOnSuccess: [ self informSuccess ]
+		onError: [ :error | self onPackageCommitError: error ]
+!
+
 execute
-	self model commitPackage
+	self commitPackage
+!
+
+informSuccess
+	HLInformationWidget new
+		informationString: 'Commit successful!!';
+		show
 ! !
 
 !HLCommitPackageCommand methodsFor: 'testing'!
 
 isActive
 	^ true
-	" slf model isPackageDirty"
+	"self model isPackageDirty"
 ! !
 
 !HLCommitPackageCommand class methodsFor: 'accessing'!
@@ -119,7 +138,7 @@ displayLabel
 !HLCopyClassCommand methodsFor: 'defaults'!
 
 defaultInput
-	^ self model selectedClass name
+	^ self model selectedClass theNonMetaClass name
 ! !
 
 !HLCopyClassCommand methodsFor: 'executing'!

Diff do ficheiro suprimidas por serem muito extensas
+ 558 - 164
src/Helios-Core.js


+ 266 - 85
js/Helios-Core.st → src/Helios-Core.st

@@ -39,7 +39,8 @@ systemAnnouncer
 withChangesDo: aBlock
 	[ 
 		self announcer announce: (HLAboutToChange new
-			actionBlock: aBlock).
+			actionBlock: aBlock;
+			yourself).
 		aBlock value.
 	]
 		on: HLChangeForbidden 
@@ -60,6 +61,36 @@ isToolModel
 	^ false
 ! !
 
+HLModel subclass: #HLFinder
+	instanceVariableNames: ''
+	package: 'Helios-Core'!
+!HLFinder commentStamp!
+I am the `Finder` service handler of Helios.
+
+Finding a class will open a new class browser, while finding a method will open a references browser.!
+
+!HLFinder methodsFor: 'finding'!
+
+findClass: aClass
+	HLBrowser openAsTab openClassNamed: aClass name
+!
+
+findMethod: aCompiledMethod
+	HLBrowser openAsTab openMethod: aCompiledMethod
+!
+
+findString: aString
+	| foundClass |
+	
+	foundClass := self environment classes 
+		detect: [ :each | each name = aString ]
+		ifNone: [ nil ].
+	
+	foundClass 
+		ifNil: [ HLReferences openAsTab search: aString ]
+		ifNotNil: [ self findClass: foundClass ]
+! !
+
 HLModel subclass: #HLToolModel
 	instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
 	package: 'Helios-Core'!
@@ -92,6 +123,34 @@ availableProtocols
 	^ self environment availableProtocolsFor: self selectedClass
 !
 
+forceSelectedClass: aClass
+	self withChangesDo: [
+		self 	
+			selectedClass: nil;
+			selectedClass: aClass ]
+!
+
+forceSelectedMethod: aMethod
+	self withChangesDo: [
+		self 	
+			selectedMethod: nil;
+			selectedMethod: aMethod ]
+!
+
+forceSelectedPackage: aPackage
+	self withChangesDo: [
+		self 	
+			selectedPackage: nil;
+			selectedPackage: aPackage ]
+!
+
+forceSelectedProtocol: aProtocol
+	self withChangesDo: [
+		self 	
+			selectedProtocol: nil;
+			selectedProtocol: aProtocol ]
+!
+
 packageToCommit
 	"Answer the package to commit depending on the context:
 	- if a Method is selected, answer its package
@@ -200,8 +259,11 @@ saveSourceCode
 
 !HLToolModel methodsFor: 'commands actions'!
 
-commitPackage
-	self environment commitPackage: self packageToCommit
+commitPackageOnSuccess: aBlock onError: anotherBlock
+	self environment 
+		commitPackage: self packageToCommit
+		onSuccess: aBlock
+		onError: anotherBlock
 !
 
 copyClassTo: aClassName
@@ -574,6 +636,10 @@ I provide common methods, additional behavior to widgets useful for Helios, like
 
 !HLWidget methodsFor: 'accessing'!
 
+cssClass
+	^ 'hl_widget'
+!
+
 manager
 	^ HLManager current
 !
@@ -592,12 +658,23 @@ confirm: aString ifTrue: aBlock
 	self manager confirm: aString ifTrue: aBlock
 !
 
+confirm: aString ifTrue: aBlock ifFalse: anotherBlock
+	self manager 
+		confirm: aString 
+		ifTrue: aBlock
+		ifFalse: anotherBlock
+!
+
 execute: aCommand
 	HLManager current keyBinder
 		activate;
 		applyBinding: aCommand asBinding
 !
 
+inform: aString
+	self manager inform: aString
+!
+
 openAsTab
 	HLManager current addTab: (HLTabWidget on: self labelled: self class tabLabel)
 !
@@ -645,7 +722,9 @@ renderContentOn: html
 !
 
 renderOn: html
-	wrapper := html div.
+	wrapper := html div
+		class: self cssClass;
+		yourself.
     [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
 ! !
 
@@ -729,7 +808,7 @@ renderContentOn: html
 
 renderOn: html
     wrapper := html div 
-    	class: 'hl_widget';
+    	class: self cssClass;
 		yourself.
 		
        wrapper with: [ self renderContentOn: html ].
@@ -850,11 +929,19 @@ focus
 		self selectedItem ifNil: [ self activateFirstListItem ] ]
 !
 
+reactivateListItem: aListItem
+	self activateListItem: aListItem.
+	self reselectItem: self selectedItem
+!
+
 refresh
 	super refresh.
 	self selectedItem ifNotNil: [self ensureVisible: (self findListItemFor: self selectedItem)].
 !
 
+reselectItem: anObject
+!
+
 selectItem: anObject
 	self selectedItem: anObject
 ! !
@@ -871,7 +958,11 @@ setupKeyBindings
 	(HLRepeatedKeyDownHandler on: self)
 		whileKeyDown: 38 do: [ self activatePreviousListItem ];
 		whileKeyDown: 40 do: [ self activateNextListItem ];
-		rebindKeys
+		rebindKeys.
+		
+	self wrapper asJQuery keydown: [ :e |
+        e which = 13 ifTrue: [ 
+        	self reselectItem: self selectedItem ] ]
 ! !
 
 !HLListWidget methodsFor: 'rendering'!
@@ -902,7 +993,7 @@ renderItem: anObject on: html
             		(html tag: 'i') class: (self cssClassForItem: anObject).
   					self renderItemLabel: anObject on: html ];
 				onClick: [
-                  	self activateListItem: li asJQuery ] ]
+                  	self reactivateListItem: li asJQuery ] ]
 !
 
 renderItemLabel: anObject on: html
@@ -1024,6 +1115,10 @@ observeModel
 observeSystem
 !
 
+reactivateListItem: anItem
+	self model withChangesDo: [ super reactivateListItem: anItem ]
+!
+
 unregister
 	super unregister.
 	
@@ -1058,7 +1153,7 @@ renderMenuOn: html
 			html a
 				class: 'btn dropdown-toggle';
 				at: 'data-toggle' put: 'dropdown';
-				with: [ (html tag: 'i') class: 'icon-cog' ].
+				with: [ (html tag: 'i') class: 'icon-chevron-down' ].
 		html ul 
 			class: 'dropdown-menu pull-right';
 			with: [ 
@@ -1178,16 +1273,30 @@ addToHistory: aTab
 !
 
 confirm: aString ifFalse: aBlock
-	HLConfirmationWidget new
-		confirmationString: aString;
-		cancelBlock: aBlock;
-		show
+	self 
+		confirm: aString
+		ifTrue: []
+		ifFalse: aBlock
 !
 
 confirm: aString ifTrue: aBlock
+	self 
+		confirm: aString
+		ifTrue: aBlock
+		ifFalse: []
+!
+
+confirm: aString ifTrue: aBlock ifFalse: anotherBlock
 	HLConfirmationWidget new
 		confirmationString: aString;
 		actionBlock: aBlock;
+		cancelBlock: anotherBlock;
+		show
+!
+
+inform: aString
+	HLInformationWidget new
+		informationString: aString;
 		show
 !
 
@@ -1245,7 +1354,9 @@ defaultEnvironment
 !HLManager methodsFor: 'initialization'!
 
 setup
-	self registerServices.
+	self 
+		registerServices;
+		setupEvents.
     self keyBinder 
 		setupEvents;
 		setupHelper
@@ -1258,16 +1369,24 @@ registerServices
 		registerInspector;
 		registerErrorHandler;
 		registerProgressHandler;
-		registerTranscript
+		registerTranscript;
+		registrFinder
+!
+
+setupEvents
+	"on ctrl keydown, adds a 'navigation' css class to <body>
+	for the CodeMirror navigation links. See `HLCodeWidget`."
+	
+	'body' asJQuery keydown: [ :event |
+		event ctrlKey ifTrue: [
+			'body' asJQuery addClass: 'navigation' ] ].
+			
+	'body' asJQuery keyup: [ :event |
+		'body' asJQuery removeClass: 'navigation' ]
 ! !
 
 !HLManager methodsFor: 'rendering'!
 
-refresh
-	'.navbar' asJQuery remove.
-	self appendToJQuery: 'body' asJQuery
-!
-
 renderAddOn: html
     html li 
     	class: 'dropdown';
@@ -1330,6 +1449,11 @@ registerErrorHandler
 	ErrorHandler register: HLErrorHandler new
 !
 
+registerFinder
+	self environment registerFinder: HLFinder new.
+	Finder register: HLFinder new
+!
+
 registerInspector
 	self environment registerInspector: HLInspector.
 	Inspector register: HLInspector
@@ -1374,28 +1498,13 @@ HLWidget subclass: #HLModalWidget
 !HLModalWidget commentStamp!
 I implement an abstract modal widget.!
 
-!HLModalWidget methodsFor: 'accessing'!
-
-cssClass
-	^ ''
-! !
-
 !HLModalWidget methodsFor: 'actions'!
 
-cancel
-	self remove
-!
-
-confirm
-	"Override in subclasses"
-	self remove
-!
-
 remove
 	'.dialog' asJQuery removeClass: 'active'.
 	[ 
 		'#overlay' asJQuery remove.
-		'.dialog' asJQuery remove
+		wrapper asJQuery remove
 	] valueWithTimeout: 300
 !
 
@@ -1416,27 +1525,13 @@ hasButtons
 !
 
 renderButtonsOn: html
-	| confirmButton |
-	
-	html div 
-		class: 'buttons';
-		with: [
-			html button
-				class: 'button';
-				with: 'Cancel';
-				onClick: [ self cancel ].
-			confirmButton := html button
-				class: 'button default';
-				with: 'Confirm';
-				onClick: [ self confirm ] ].
-
-	self giveFocusToButton:confirmButton
 !
 
 renderContentOn: html
 	| confirmButton |
 	
 	html div id: 'overlay'.
+	
 	html div 
 		class: 'dialog ', self cssClass;
 		with: [
@@ -1457,12 +1552,14 @@ setupKeyBindings
 ! !
 
 HLModalWidget subclass: #HLConfirmationWidget
-	instanceVariableNames: 'confirmationString actionBlock cancelBlock'
+	instanceVariableNames: 'cancelButtonLabel confirmButtonLabel confirmationString actionBlock cancelBlock'
 	package: 'Helios-Core'!
 !HLConfirmationWidget commentStamp!
-I display confirmation messages. 
+I display confirmation dialog. 
+
+## API
 
-Instead of creating an instance directly, use `HLWidget >> #confirm:ifTrue:`.!
+HLWidget contains convenience methods like `HLWidget >> #confirm:ifTrue:` for creating confirmation dialogs.!
 
 !HLConfirmationWidget methodsFor: 'accessing'!
 
@@ -1482,6 +1579,22 @@ cancelBlock: aBlock
 	cancelBlock := aBlock
 !
 
+cancelButtonLabel
+	^ cancelButtonLabel ifNil: [ 'Cancel' ]
+!
+
+cancelButtonLabel: aString
+	^ cancelButtonLabel := aString
+!
+
+confirmButtonLabel
+	^ confirmButtonLabel ifNil: [ 'Confirm' ]
+!
+
+confirmButtonLabel: aString
+	^ confirmButtonLabel := aString
+!
+
 confirmationString
 	^ confirmationString ifNil: [ 'Confirm' ]
 !
@@ -1494,30 +1607,60 @@ confirmationString: aString
 
 cancel
 	self cancelBlock value.
-	super cancel
+	self remove
 !
 
 confirm
-	super confirm.
+	self remove.
 	self actionBlock value
 ! !
 
 !HLConfirmationWidget methodsFor: 'rendering'!
 
+renderButtonsOn: html
+	| confirmButton |
+	
+	html div 
+		class: 'buttons';
+		with: [
+			html button
+				class: 'button';
+				with: self cancelButtonLabel;
+				onClick: [ self cancel ].
+			confirmButton := html button
+				class: 'button default';
+				with: self confirmButtonLabel;
+				onClick: [ self confirm ] ].
+
+	self giveFocusToButton:confirmButton
+!
+
 renderMainOn: html
-	html span with: self confirmationString
+	html span 
+		class: 'head'; 
+		with: self confirmationString
 ! !
 
 HLConfirmationWidget subclass: #HLRequestWidget
-	instanceVariableNames: 'input value'
+	instanceVariableNames: 'input multiline value'
 	package: 'Helios-Core'!
 !HLRequestWidget commentStamp!
 I display a modal window requesting user input.
 
-Instead of creating instances manually, use `HLWidget >> #request:do:` and `#request:value:do:`.!
+## API
+
+`HLWidget >> #request:do:` and `#request:value:do:` are convenience methods for creating modal request dialogs.!
 
 !HLRequestWidget methodsFor: 'accessing'!
 
+beMultiline
+	multiline := true
+!
+
+beSingleline
+	multiline := false
+!
+
 cssClass
 	^ 'large'
 !
@@ -1533,8 +1676,10 @@ value: aString
 !HLRequestWidget methodsFor: 'actions'!
 
 confirm
-	super confirm.
-	self actionBlock value: input asJQuery val
+	| val |
+	val := input asJQuery val.
+	self remove.
+	self actionBlock value: val
 ! !
 
 !HLRequestWidget methodsFor: 'private'!
@@ -1546,12 +1691,72 @@ giveFocusToButton: aButton
 
 renderMainOn: html
 	super renderMainOn: html.
-	input := html textarea.
+	self isMultiline
+		ifTrue: [ input := html textarea ]
+		ifFalse: [ input := html input 
+			type: 'text';
+			onKeyDown: [ :event |
+				event keyCode = 13 ifTrue: [
+					self confirm ] ];
+			yourself ].
 	input asJQuery 
 		val: self value;
 		focus
 ! !
 
+!HLRequestWidget methodsFor: 'testing'!
+
+isMultiline
+	^ multiline ifNil: [ true ]
+! !
+
+HLModalWidget subclass: #HLInformationWidget
+	instanceVariableNames: 'buttonLabel informationString'
+	package: 'Helios-Core'!
+!HLInformationWidget commentStamp!
+I display an information dialog.
+
+## API
+
+`HLWidget >> #inform:` is a convenience method for creating information dialogs.!
+
+!HLInformationWidget methodsFor: 'accessing'!
+
+buttonLabel
+	^ buttonLabel ifNil: [ 'Ok' ]
+!
+
+buttonLabel: aString
+	buttonLabel := aString
+!
+
+informationString
+	^ informationString ifNil: [ '' ]
+!
+
+informationString: anObject
+	informationString := anObject
+! !
+
+!HLInformationWidget methodsFor: 'rendering'!
+
+renderButtonsOn: html
+	| button |
+	html div 
+		class: 'buttons';
+		with: [
+			button := html button
+				class: 'button default';
+				with: self buttonLabel;
+				onClick: [ self remove ] ].
+
+	self giveFocusToButton: button
+!
+
+renderMainOn: html
+	html span with: self informationString
+! !
+
 HLModalWidget subclass: #HLProgressWidget
 	instanceVariableNames: 'progressBars visible'
 	package: 'Helios-Core'!
@@ -1838,27 +2043,3 @@ default
 	^ default ifNil: [ default := self new ]
 ! !
 
-HLWidget subclass: #HLSUnit
-	instanceVariableNames: ''
-	package: 'Helios-Core'!
-
-!HLSUnit class methodsFor: 'accessing'!
-
-tabClass
-	^ 'sunit'
-!
-
-tabLabel
-	^ 'SUnit'
-!
-
-tabPriority
-	^ 1000
-! !
-
-!HLSUnit class methodsFor: 'testing'!
-
-canBeOpenAsTab
-	^ true
-! !
-

+ 186 - 37
js/Helios-Debugger.js → src/Helios-Debugger.js

@@ -107,7 +107,7 @@ globals.HLDebugger.comment="I am the main widget for the Helios debugger.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "codeWidget",
-protocol: 'accessing',
+protocol: 'widgets',
 fn: function (){
 var self=this;
 function $HLDebuggerCodeWidget(){return globals.HLDebuggerCodeWidget||(typeof HLDebuggerCodeWidget=="undefined"?nil:HLDebuggerCodeWidget)}
@@ -144,6 +144,24 @@ referencedClasses: ["HLDebuggerCodeWidget", "HLDebuggerCodeModel"]
 }),
 globals.HLDebugger);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cssClass",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(globals.HLDebugger.superclass.fn.prototype._cssClass.apply(_st(self), [])).__comma(" hl_debugger");
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cssClass",{},globals.HLDebugger)})},
+args: [],
+source: "cssClass\x0a\x09^ super cssClass, ' hl_debugger'",
+messageSends: [",", "cssClass"],
+referencedClasses: []
+}),
+globals.HLDebugger);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "focus",
@@ -162,17 +180,17 @@ globals.HLDebugger);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "initializeFromMethodContext:",
-protocol: 'accessing',
-fn: function (aMethodContext){
+selector: "initializeFromError:",
+protocol: 'initialization',
+fn: function (anError){
 var self=this;
 function $HLDebuggerModel(){return globals.HLDebuggerModel||(typeof HLDebuggerModel=="undefined"?nil:HLDebuggerModel)}
 return smalltalk.withContext(function($ctx1) { 
-self["@model"]=_st($HLDebuggerModel())._on_(aMethodContext);
+self["@model"]=_st($HLDebuggerModel())._on_(anError);
 self._observeModel();
-return self}, function($ctx1) {$ctx1.fill(self,"initializeFromMethodContext:",{aMethodContext:aMethodContext},globals.HLDebugger)})},
-args: ["aMethodContext"],
-source: "initializeFromMethodContext: aMethodContext\x0a\x09model := HLDebuggerModel on: aMethodContext.\x0a\x09self observeModel",
+return self}, function($ctx1) {$ctx1.fill(self,"initializeFromError:",{anError:anError},globals.HLDebugger)})},
+args: ["anError"],
+source: "initializeFromError: anError\x0a\x09model := HLDebuggerModel on: anError.\x0a\x09self observeModel",
 messageSends: ["on:", "observeModel"],
 referencedClasses: ["HLDebuggerModel"]
 }),
@@ -181,7 +199,7 @@ globals.HLDebugger);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "inspectorWidget",
-protocol: 'accessing',
+protocol: 'widgets',
 fn: function (){
 var self=this;
 function $HLInspectorWidget(){return globals.HLInspectorWidget||(typeof HLInspectorWidget=="undefined"?nil:HLInspectorWidget)}
@@ -298,6 +316,7 @@ function $HLHorizontalSplitter(){return globals.HLHorizontalSplitter||(typeof HL
 function $HLVerticalSplitter(){return globals.HLVerticalSplitter||(typeof HLVerticalSplitter=="undefined"?nil:HLVerticalSplitter)}
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
+self._renderHeadOn_(html);
 $2=_st($HLHorizontalSplitter())._with_with_(self._stackListWidget(),_st($HLVerticalSplitter())._with_with_(self._codeWidget(),self._inspectorWidget()));
 $ctx1.sendIdx["with:with:"]=1;
 $1=_st($HLContainer())._with_($2);
@@ -305,16 +324,39 @@ _st(html)._with_($1);
 $ctx1.sendIdx["with:"]=1;
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLDebugger)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html with: (HLContainer with: (HLHorizontalSplitter\x0a\x09\x09with: self stackListWidget\x0a\x09\x09with: (HLVerticalSplitter\x0a\x09\x09\x09with: self codeWidget\x0a\x09\x09\x09with: self inspectorWidget)))",
-messageSends: ["with:", "with:with:", "stackListWidget", "codeWidget", "inspectorWidget"],
+source: "renderContentOn: html\x0a\x09self renderHeadOn: html.\x0a\x09html with: (HLContainer with: (HLHorizontalSplitter\x0a\x09\x09with: self stackListWidget\x0a\x09\x09with: (HLVerticalSplitter\x0a\x09\x09\x09with: self codeWidget\x0a\x09\x09\x09with: self inspectorWidget)))",
+messageSends: ["renderHeadOn:", "with:", "with:with:", "stackListWidget", "codeWidget", "inspectorWidget"],
 referencedClasses: ["HLContainer", "HLHorizontalSplitter", "HLVerticalSplitter"]
 }),
 globals.HLDebugger);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderHeadOn:",
+protocol: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st(html)._div();
+_st($1)._class_("head");
+$2=_st($1)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(html)._h2())._with_(_st(_st(self._model())._error())._messageText());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$ctx1.sendIdx["with:"]=1;
+return self}, function($ctx1) {$ctx1.fill(self,"renderHeadOn:",{html:html},globals.HLDebugger)})},
+args: ["html"],
+source: "renderHeadOn: html\x0a\x09html div \x0a\x09\x09class: 'head'; \x0a\x09\x09with: [ html h2 with: self model error messageText ]",
+messageSends: ["class:", "div", "with:", "h2", "messageText", "error", "model"],
+referencedClasses: []
+}),
+globals.HLDebugger);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "stackListWidget",
-protocol: 'accessing',
+protocol: 'widgets',
 fn: function (){
 var self=this;
 function $HLStackListWidget(){return globals.HLStackListWidget||(typeof HLStackListWidget=="undefined"?nil:HLStackListWidget)}
@@ -362,19 +404,19 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "on:",
 protocol: 'instance creation',
-fn: function (aMethodContext){
+fn: function (anError){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
 $2=self._new();
-_st($2)._initializeFromMethodContext_(aMethodContext);
+_st($2)._initializeFromError_(anError);
 $3=_st($2)._yourself();
 $1=$3;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"on:",{aMethodContext:aMethodContext},globals.HLDebugger.klass)})},
-args: ["aMethodContext"],
-source: "on: aMethodContext\x0a\x09^ self new\x0a\x09\x09initializeFromMethodContext: aMethodContext;\x0a\x09\x09yourself",
-messageSends: ["initializeFromMethodContext:", "new", "yourself"],
+}, function($ctx1) {$ctx1.fill(self,"on:",{anError:anError},globals.HLDebugger.klass)})},
+args: ["anError"],
+source: "on: anError\x0a\x09^ self new\x0a\x09\x09initializeFromError: anError;\x0a\x09\x09yourself",
+messageSends: ["initializeFromError:", "new", "yourself"],
 referencedClasses: []
 }),
 globals.HLDebugger.klass);
@@ -449,15 +491,23 @@ selector: "doIt:",
 protocol: 'actions',
 fn: function (aString){
 var self=this;
+function $ErrorHandler(){return globals.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self._debuggerModel())._evaluate_(aString);
+$1=self._try_catch_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._debuggerModel())._evaluate_(aString);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(e){
+return smalltalk.withContext(function($ctx2) {
+_st($ErrorHandler())._handleError_(e);
+return nil;
+}, function($ctx2) {$ctx2.fillBlock({e:e},$ctx1,2)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLDebuggerCodeModel)})},
 args: ["aString"],
-source: "doIt: aString\x0a\x09^ self debuggerModel evaluate: aString",
-messageSends: ["evaluate:", "debuggerModel"],
-referencedClasses: []
+source: "doIt: aString\x0a\x09^ self \x0a\x09\x09try: [ self debuggerModel evaluate: aString ]\x0a\x09\x09catch: [ :e | \x0a\x09\x09\x09ErrorHandler handleError: e.\x0a\x09\x09\x09nil ]",
+messageSends: ["try:catch:", "evaluate:", "debuggerModel", "handleError:"],
+referencedClasses: ["ErrorHandler"]
 }),
 globals.HLDebuggerCodeModel);
 
@@ -649,7 +699,7 @@ globals.HLDebuggerCodeWidget);
 
 
 
-smalltalk.addClass('HLDebuggerModel', globals.HLToolModel, ['rootContext', 'currentContext', 'contexts'], 'Helios-Debugger');
+smalltalk.addClass('HLDebuggerModel', globals.HLToolModel, ['rootContext', 'currentContext', 'contexts', 'error'], 'Helios-Debugger');
 globals.HLDebuggerModel.comment="I am a model for debugging Amber code in Helios.\x0a\x0aMy instances hold a reference to an `AIContext` instance, built from a `MethodContext`. The context should be the root of the context stack.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -719,6 +769,38 @@ referencedClasses: ["HLDebuggerContextSelected"]
 }),
 globals.HLDebuggerModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "error",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@error"];
+return $1;
+},
+args: [],
+source: "error\x0a\x09^ error",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLDebuggerModel);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "error:",
+protocol: 'accessing',
+fn: function (anError){
+var self=this;
+self["@error"]=anError;
+return self},
+args: ["anError"],
+source: "error: anError\x0a\x09error := anError",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLDebuggerModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "evaluate:",
@@ -804,6 +886,32 @@ referencedClasses: ["AIContext"]
 }),
 globals.HLDebuggerModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "initializeFromError:",
+protocol: 'initialization',
+fn: function (anError){
+var self=this;
+function $AIContext(){return globals.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+self["@error"]=anError;
+_st(console)._log_(self["@error"]);
+$ctx1.sendIdx["log:"]=1;
+$1=console;
+$2=_st(self["@error"])._context();
+$ctx1.sendIdx["context"]=1;
+_st($1)._log_($2);
+self["@rootContext"]=_st($AIContext())._fromMethodContext_(_st(self["@error"])._context());
+self._initializeContexts();
+return self}, function($ctx1) {$ctx1.fill(self,"initializeFromError:",{anError:anError},globals.HLDebuggerModel)})},
+args: ["anError"],
+source: "initializeFromError: anError\x0a\x09error := anError.\x0a\x09console log: error.\x0a\x09console log: error context.\x0a\x09rootContext := (AIContext fromMethodContext: error context).\x0a\x09self initializeContexts",
+messageSends: ["log:", "context", "fromMethodContext:", "initializeContexts"],
+referencedClasses: ["AIContext"]
+}),
+globals.HLDebuggerModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "interpreter",
@@ -948,19 +1056,19 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "on:",
 protocol: 'instance creation',
-fn: function (aMethodContext){
+fn: function (anError){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
 $2=self._new();
-_st($2)._initializeFromContext_(aMethodContext);
+_st($2)._initializeFromError_(anError);
 $3=_st($2)._yourself();
 $1=$3;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"on:",{aMethodContext:aMethodContext},globals.HLDebuggerModel.klass)})},
-args: ["aMethodContext"],
-source: "on: aMethodContext\x0a\x09^ self new\x0a\x09\x09initializeFromContext: aMethodContext;\x0a\x09\x09yourself",
-messageSends: ["initializeFromContext:", "new", "yourself"],
+}, function($ctx1) {$ctx1.fill(self,"on:",{anError:anError},globals.HLDebuggerModel.klass)})},
+args: ["anError"],
+source: "on: anError\x0a\x09^ self new\x0a\x09\x09initializeFromError: anError;\x0a\x09\x09yourself",
+messageSends: ["initializeFromError:", "new", "yourself"],
 referencedClasses: []
 }),
 globals.HLDebuggerModel.klass);
@@ -969,27 +1077,68 @@ globals.HLDebuggerModel.klass);
 smalltalk.addClass('HLErrorHandler', globals.Object, [], 'Helios-Debugger');
 smalltalk.addMethod(
 smalltalk.method({
-selector: "handleError:",
+selector: "confirmDebugError:",
+protocol: 'error handling',
+fn: function (anError){
+var self=this;
+function $HLConfirmationWidget(){return globals.HLConfirmationWidget||(typeof HLConfirmationWidget=="undefined"?nil:HLConfirmationWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($HLConfirmationWidget())._new();
+_st($1)._confirmationString_(_st(anError)._messageText());
+_st($1)._actionBlock_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._debugError_(anError);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+_st($1)._cancelButtonLabel_("Abandon");
+_st($1)._confirmButtonLabel_("Debug");
+$2=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"confirmDebugError:",{anError:anError},globals.HLErrorHandler)})},
+args: ["anError"],
+source: "confirmDebugError: anError\x0a\x09HLConfirmationWidget new\x0a\x09\x09confirmationString: anError messageText;\x0a\x09\x09actionBlock: [ self debugError: anError ];\x0a\x09\x09cancelButtonLabel: 'Abandon';\x0a\x09\x09confirmButtonLabel: 'Debug';\x0a\x09\x09show",
+messageSends: ["confirmationString:", "new", "messageText", "actionBlock:", "debugError:", "cancelButtonLabel:", "confirmButtonLabel:", "show"],
+referencedClasses: ["HLConfirmationWidget"]
+}),
+globals.HLErrorHandler);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "debugError:",
 protocol: 'error handling',
 fn: function (anError){
 var self=this;
 function $HLDebugger(){return globals.HLDebugger||(typeof HLDebugger=="undefined"?nil:HLDebugger)}
 function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
-function $ErrorHandler(){return globals.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
+function $ConsoleErrorHandler(){return globals.ConsoleErrorHandler||(typeof ConsoleErrorHandler=="undefined"?nil:ConsoleErrorHandler)}
 return smalltalk.withContext(function($ctx1) { 
-self._onErrorHandled();
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(_st($HLDebugger())._on_(_st(anError)._context()))._openAsTab();
+return _st(_st($HLDebugger())._on_(anError))._openAsTab();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(error){
 return smalltalk.withContext(function($ctx2) {
-return _st(_st($ErrorHandler())._new())._handleError_(error);
+return _st(_st($ConsoleErrorHandler())._new())._handleError_(error);
 }, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"debugError:",{anError:anError},globals.HLErrorHandler)})},
+args: ["anError"],
+source: "debugError: anError\x0a\x0a\x09[ \x0a\x09\x09(HLDebugger on: anError) openAsTab \x0a\x09] \x0a\x09\x09on: Error \x0a\x09\x09do: [ :error | ConsoleErrorHandler new handleError: error ]",
+messageSends: ["on:do:", "openAsTab", "on:", "handleError:", "new"],
+referencedClasses: ["HLDebugger", "Error", "ConsoleErrorHandler"]
+}),
+globals.HLErrorHandler);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "handleError:",
+protocol: 'error handling',
+fn: function (anError){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._confirmDebugError_(anError);
 return self}, function($ctx1) {$ctx1.fill(self,"handleError:",{anError:anError},globals.HLErrorHandler)})},
 args: ["anError"],
-source: "handleError: anError\x0a\x09self onErrorHandled.\x0a\x0a\x09[ \x0a\x09\x09(HLDebugger on: anError context) openAsTab \x0a\x09] \x0a\x09\x09on: Error \x0a\x09\x09do: [ :error | ErrorHandler new handleError: error ]",
-messageSends: ["onErrorHandled", "on:do:", "openAsTab", "on:", "context", "handleError:", "new"],
-referencedClasses: ["HLDebugger", "Error", "ErrorHandler"]
+source: "handleError: anError\x0a\x09self confirmDebugError: anError",
+messageSends: ["confirmDebugError:"],
+referencedClasses: []
 }),
 globals.HLErrorHandler);
 

+ 81 - 34
js/Helios-Debugger.st → src/Helios-Debugger.st

@@ -51,34 +51,12 @@ I am the main widget for the Helios debugger.!
 
 !HLDebugger methodsFor: 'accessing'!
 
-codeWidget
-	^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new
-		model: (HLDebuggerCodeModel new
-			debuggerModel: self model;
-			yourself);
-		browserModel: self model;
-		yourself ]
-!
-
-initializeFromMethodContext: aMethodContext
-	model := HLDebuggerModel on: aMethodContext.
-	self observeModel
-!
-
-inspectorWidget
-	^ inspectorWidget ifNil: [ 
-		inspectorWidget := HLInspectorWidget new ]
+cssClass
+	^ super cssClass, ' hl_debugger'
 !
 
 model
 	^ model ifNil: [ model := HLDebuggerModel new ]
-!
-
-stackListWidget
-	^ stackListWidget ifNil: [ 
-		stackListWidget := (HLStackListWidget on: self model)
-			next: self codeWidget;
-			yourself ]
 ! !
 
 !HLDebugger methodsFor: 'actions'!
@@ -104,6 +82,13 @@ unregister
 	self inspectorWidget unregister
 ! !
 
+!HLDebugger methodsFor: 'initialization'!
+
+initializeFromError: anError
+	model := HLDebuggerModel on: anError.
+	self observeModel
+! !
+
 !HLDebugger methodsFor: 'keybindings'!
 
 registerBindingsOn: aBindingGroup
@@ -121,11 +106,41 @@ onContextSelected: anAnnouncement
 !HLDebugger methodsFor: 'rendering'!
 
 renderContentOn: html
+	self renderHeadOn: html.
 	html with: (HLContainer with: (HLHorizontalSplitter
 		with: self stackListWidget
 		with: (HLVerticalSplitter
 			with: self codeWidget
 			with: self inspectorWidget)))
+!
+
+renderHeadOn: html
+	html div 
+		class: 'head'; 
+		with: [ html h2 with: self model error messageText ]
+! !
+
+!HLDebugger methodsFor: 'widgets'!
+
+codeWidget
+	^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new
+		model: (HLDebuggerCodeModel new
+			debuggerModel: self model;
+			yourself);
+		browserModel: self model;
+		yourself ]
+!
+
+inspectorWidget
+	^ inspectorWidget ifNil: [ 
+		inspectorWidget := HLInspectorWidget new ]
+!
+
+stackListWidget
+	^ stackListWidget ifNil: [ 
+		stackListWidget := (HLStackListWidget on: self model)
+			next: self codeWidget;
+			yourself ]
 ! !
 
 !HLDebugger class methodsFor: 'accessing'!
@@ -140,9 +155,9 @@ tabLabel
 
 !HLDebugger class methodsFor: 'instance creation'!
 
-on: aMethodContext
+on: anError
 	^ self new
-		initializeFromMethodContext: aMethodContext;
+		initializeFromError: anError;
 		yourself
 ! !
 
@@ -163,7 +178,11 @@ debuggerModel: anObject
 !HLDebuggerCodeModel methodsFor: 'actions'!
 
 doIt: aString
-	^ self debuggerModel evaluate: aString
+	^ self 
+		try: [ self debuggerModel evaluate: aString ]
+		catch: [ :e | 
+			ErrorHandler handleError: e.
+			nil ]
 ! !
 
 HLBrowserCodeWidget subclass: #HLDebuggerCodeWidget
@@ -239,7 +258,7 @@ onContextSelected
 ! !
 
 HLToolModel subclass: #HLDebuggerModel
-	instanceVariableNames: 'rootContext currentContext contexts'
+	instanceVariableNames: 'rootContext currentContext contexts error'
 	package: 'Helios-Debugger'!
 !HLDebuggerModel commentStamp!
 I am a model for debugging Amber code in Helios.
@@ -266,6 +285,14 @@ currentContext: aContext
 			yourself) ]
 !
 
+error
+	^ error
+!
+
+error: anError
+	error := anError
+!
+
 interpreter
 	^ self currentContext interpreter
 !
@@ -337,6 +364,14 @@ initializeContexts
 initializeFromContext: aMethodContext
 	rootContext := (AIContext fromMethodContext: aMethodContext).
 	self initializeContexts
+!
+
+initializeFromError: anError
+	error := anError.
+	console log: error.
+	console log: error context.
+	rootContext := (AIContext fromMethodContext: error context).
+	self initializeContexts
 ! !
 
 !HLDebuggerModel methodsFor: 'private'!
@@ -352,9 +387,9 @@ flushInnerContexts
 
 !HLDebuggerModel class methodsFor: 'instance creation'!
 
-on: aMethodContext
+on: anError
 	^ self new
-		initializeFromContext: aMethodContext;
+		initializeFromError: anError;
 		yourself
 ! !
 
@@ -364,14 +399,26 @@ Object subclass: #HLErrorHandler
 
 !HLErrorHandler methodsFor: 'error handling'!
 
-handleError: anError
-	self onErrorHandled.
+confirmDebugError: anError
+	HLConfirmationWidget new
+		confirmationString: anError messageText;
+		actionBlock: [ self debugError: anError ];
+		cancelButtonLabel: 'Abandon';
+		confirmButtonLabel: 'Debug';
+		show
+!
+
+debugError: anError
 
 	[ 
-		(HLDebugger on: anError context) openAsTab 
+		(HLDebugger on: anError) openAsTab 
 	] 
 		on: Error 
-		do: [ :error | ErrorHandler new handleError: error ]
+		do: [ :error | ConsoleErrorHandler new handleError: error ]
+!
+
+handleError: anError
+	self confirmDebugError: anError
 !
 
 onErrorHandled

+ 0 - 0
js/Helios-Exceptions.js → src/Helios-Exceptions.js


+ 0 - 0
js/Helios-Exceptions.st → src/Helios-Exceptions.st


+ 168 - 4
js/Helios-Helpers.js → src/Helios-Helpers.js

@@ -639,7 +639,7 @@ globals.HLMethodClassifier);
 
 
 smalltalk.addClass('HLMethodGenerator', globals.Object, ['output'], 'Helios-Helpers');
-globals.HLMethodGenerator.comment="I am the abstract super class of the method generators.\x0a\x0aMy main method is `generate` which produce an `output` object";
+globals.HLMethodGenerator.comment="I am the abstract super class of the method generators.\x0a\x0aMy main method is `generate` which produces an `output` object accessed with `#output`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "class:",
@@ -716,7 +716,7 @@ globals.HLMethodGenerator);
 
 
 smalltalk.addClass('HLAccessorsGenerator', globals.HLMethodGenerator, [], 'Helios-Helpers');
-globals.HLAccessorsGenerator.comment="I am a generator used to compile the getters/setters of a class";
+globals.HLAccessorsGenerator.comment="I am a generator used to compile the getters/setters of a class.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "accessorProtocolForObject",
@@ -846,7 +846,7 @@ globals.HLAccessorsGenerator);
 
 
 smalltalk.addClass('HLInitializeGenerator', globals.HLMethodGenerator, [], 'Helios-Helpers');
-globals.HLInitializeGenerator.comment="I am used to double-dispatch the `initialize` method(s) generation.\x0a\x0aUsage:\x0a\x0a    ^ HLInitializeGenerator new\x0a        class: aClass;\x0a        generate;\x0a        output\x0a\x0aI am a disposable object";
+globals.HLInitializeGenerator.comment="I am used to double-dispatch the `initialize` method(s) generation. I am a disposable object.\x0a\x0a## Usage\x0a\x0a    ^ HLInitializeGenerator new\x0a        class: aClass;\x0a        generate;\x0a        output";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "generate",
@@ -982,7 +982,7 @@ globals.HLInitializeGenerator);
 
 
 smalltalk.addClass('HLMethodSourceCode', globals.Object, ['selector', 'sourceCode'], 'Helios-Helpers');
-globals.HLMethodSourceCode.comment="I am a simple data object keeping track of the information about a method that will be compiled at the end of the generation process";
+globals.HLMethodSourceCode.comment="I am a simple data object keeping track of the information about a method that will be compiled at the end of the generation process.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selector",
@@ -1048,4 +1048,168 @@ referencedClasses: []
 globals.HLMethodSourceCode);
 
 
+
+smalltalk.addClass('HLPackageCommitErrorHelper', globals.Object, ['model'], 'Helios-Helpers');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitPackage",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLCommitPackageCommand(){return globals.HLCommitPackageCommand||(typeof HLCommitPackageCommand=="undefined"?nil:HLCommitPackageCommand)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st($HLCommitPackageCommand())._for_(self._model()))._execute();
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "commitPackage\x0a\x09(HLCommitPackageCommand for: self model)\x0a\x09\x09execute",
+messageSends: ["execute", "for:", "model"],
+referencedClasses: ["HLCommitPackageCommand"]
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitToPath:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(require)._basicAt_("config"))._value_(globals.HashedCollection._newFromPairs_(["paths",globals.HashedCollection._newFromPairs_([_st(_st(self._package())._transport())._namespace(),aString])]));
+self._commitPackage();
+return self}, function($ctx1) {$ctx1.fill(self,"commitToPath:",{aString:aString},globals.HLPackageCommitErrorHelper)})},
+args: ["aString"],
+source: "commitToPath: aString\x0a\x09\x22We only take AMD package transport into account for now\x22\x0a\x09\x0a\x09(require basicAt: 'config') value: #{\x0a\x09\x09'paths' -> #{\x0a\x09\x09\x09self package transport namespace -> aString\x0a\x09\x09}\x0a\x09}.\x0a\x09\x0a\x09self commitPackage",
+messageSends: ["value:", "basicAt:", "namespace", "transport", "package", "commitPackage"],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@model"];
+return $1;
+},
+args: [],
+source: "model\x0a\x09^ model",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model:",
+protocol: 'accessing',
+fn: function (aToolModel){
+var self=this;
+self["@model"]=aToolModel;
+return self},
+args: ["aToolModel"],
+source: "model: aToolModel\x0a\x09model := aToolModel",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "package",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._model())._packageToCommit();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"package",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "package\x0a\x09^ self model packageToCommit",
+messageSends: ["packageToCommit", "model"],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "showHelp",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLConfirmationWidget(){return globals.HLConfirmationWidget||(typeof HLConfirmationWidget=="undefined"?nil:HLConfirmationWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4;
+$1=_st($HLConfirmationWidget())._new();
+$2=$1;
+$3=_st("Commit failed for namespace \x22".__comma(_st(_st(self._package())._transport())._namespace())).__comma("\x22. Do you want to commit to another path?");
+$ctx1.sendIdx[","]=1;
+_st($2)._confirmationString_($3);
+_st($1)._actionBlock_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._showNewCommitPath();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+_st($1)._cancelButtonLabel_("Abandon");
+_st($1)._confirmButtonLabel_("Set path");
+$4=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"showHelp",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "showHelp\x0a\x09HLConfirmationWidget new\x0a\x09\x09confirmationString: 'Commit failed for namespace \x22', self package transport namespace, '\x22. Do you want to commit to another path?';\x0a\x09\x09actionBlock: [ self showNewCommitPath ];\x0a\x09\x09cancelButtonLabel: 'Abandon';\x0a\x09\x09confirmButtonLabel: 'Set path';\x0a\x09\x09show\x0a\x09",
+messageSends: ["confirmationString:", "new", ",", "namespace", "transport", "package", "actionBlock:", "showNewCommitPath", "cancelButtonLabel:", "confirmButtonLabel:", "show"],
+referencedClasses: ["HLConfirmationWidget"]
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "showNewCommitPath",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLRequestWidget(){return globals.HLRequestWidget||(typeof HLRequestWidget=="undefined"?nil:HLRequestWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($HLRequestWidget())._new();
+_st($1)._beSingleline();
+_st($1)._confirmationString_("Set commit path");
+_st($1)._actionBlock_((function(url){
+return smalltalk.withContext(function($ctx2) {
+return self._commitToPath_(url);
+}, function($ctx2) {$ctx2.fillBlock({url:url},$ctx1,1)})}));
+_st($1)._confirmButtonLabel_("Commit with new path");
+_st($1)._value_("/src");
+$2=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"showNewCommitPath",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "showNewCommitPath\x0a\x09HLRequestWidget new\x0a\x09\x09beSingleline;\x0a\x09\x09confirmationString: 'Set commit path';\x0a\x09\x09actionBlock: [ :url | self commitToPath: url ];\x0a\x09\x09confirmButtonLabel: 'Commit with new path';\x0a\x09\x09value: '/src';\x0a\x09\x09show",
+messageSends: ["beSingleline", "new", "confirmationString:", "actionBlock:", "commitToPath:", "confirmButtonLabel:", "value:", "show"],
+referencedClasses: ["HLRequestWidget"]
+}),
+globals.HLPackageCommitErrorHelper);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "on:",
+protocol: 'instance creation',
+fn: function (aToolModel){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._new();
+_st($2)._model_(aToolModel);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"on:",{aToolModel:aToolModel},globals.HLPackageCommitErrorHelper.klass)})},
+args: ["aToolModel"],
+source: "on: aToolModel\x0a\x09^ self new\x0a\x09\x09model: aToolModel;\x0a\x09\x09yourself",
+messageSends: ["model:", "new", "yourself"],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper.klass);
+
 });

+ 70 - 8
js/Helios-Helpers.st → src/Helios-Helpers.st

@@ -277,7 +277,7 @@ Object subclass: #HLMethodGenerator
 !HLMethodGenerator commentStamp!
 I am the abstract super class of the method generators.
 
-My main method is `generate` which produce an `output` object!
+My main method is `generate` which produces an `output` object accessed with `#output`.!
 
 !HLMethodGenerator methodsFor: 'accessing'!
 
@@ -307,7 +307,7 @@ HLMethodGenerator subclass: #HLAccessorsGenerator
 	instanceVariableNames: ''
 	package: 'Helios-Helpers'!
 !HLAccessorsGenerator commentStamp!
-I am a generator used to compile the getters/setters of a class!
+I am a generator used to compile the getters/setters of a class.!
 
 !HLAccessorsGenerator methodsFor: 'double-dispatch'!
 
@@ -360,16 +360,14 @@ HLMethodGenerator subclass: #HLInitializeGenerator
 	instanceVariableNames: ''
 	package: 'Helios-Helpers'!
 !HLInitializeGenerator commentStamp!
-I am used to double-dispatch the `initialize` method(s) generation.
+I am used to double-dispatch the `initialize` method(s) generation. I am a disposable object.
 
-Usage:
+## Usage
 
     ^ HLInitializeGenerator new
         class: aClass;
         generate;
-        output
-
-I am a disposable object!
+        output!
 
 !HLInitializeGenerator methodsFor: 'double-dispatch'!
 
@@ -417,7 +415,7 @@ Object subclass: #HLMethodSourceCode
 	instanceVariableNames: 'selector sourceCode'
 	package: 'Helios-Helpers'!
 !HLMethodSourceCode commentStamp!
-I am a simple data object keeping track of the information about a method that will be compiled at the end of the generation process!
+I am a simple data object keeping track of the information about a method that will be compiled at the end of the generation process.!
 
 !HLMethodSourceCode methodsFor: 'accessing'!
 
@@ -437,3 +435,67 @@ sourceCode: aString
 	sourceCode := aString
 ! !
 
+Object subclass: #HLPackageCommitErrorHelper
+	instanceVariableNames: 'model'
+	package: 'Helios-Helpers'!
+
+!HLPackageCommitErrorHelper methodsFor: 'accessing'!
+
+model
+	^ model
+!
+
+model: aToolModel
+	model := aToolModel
+!
+
+package
+	^ self model packageToCommit
+! !
+
+!HLPackageCommitErrorHelper methodsFor: 'actions'!
+
+commitPackage
+	(HLCommitPackageCommand for: self model)
+		execute
+!
+
+commitToPath: aString
+	"We only take AMD package transport into account for now"
+	
+	(require basicAt: 'config') value: #{
+		'paths' -> #{
+			self package transport namespace -> aString
+		}
+	}.
+	
+	self commitPackage
+!
+
+showHelp
+	HLConfirmationWidget new
+		confirmationString: 'Commit failed for namespace "', self package transport namespace, '". Do you want to commit to another path?';
+		actionBlock: [ self showNewCommitPath ];
+		cancelButtonLabel: 'Abandon';
+		confirmButtonLabel: 'Set path';
+		show
+!
+
+showNewCommitPath
+	HLRequestWidget new
+		beSingleline;
+		confirmationString: 'Set commit path';
+		actionBlock: [ :url | self commitToPath: url ];
+		confirmButtonLabel: 'Commit with new path';
+		value: '/src';
+		show
+! !
+
+!HLPackageCommitErrorHelper class methodsFor: 'instance creation'!
+
+on: aToolModel
+	^ self new
+		model: aToolModel;
+		yourself
+! !
+

+ 128 - 129
js/Helios-Inspector.js → src/Helios-Inspector.js

@@ -1,20 +1,20 @@
-define("amber_core/Helios-Inspector", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Helios-Core", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Helios-Inspector", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Helios-Core"], function(smalltalk,nil,_st, globals){
 smalltalk.addPackage('Helios-Inspector');
 smalltalk.packages["Helios-Inspector"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
-smalltalk.addClass('HLInspectorDisplayWidget', globals.HLNavigationListWidget, ['model'], 'Helios-Inspector');
+smalltalk.addClass('HLInspectorDisplayWidget', globals.HLNavigationListWidget, ['inspector'], 'Helios-Inspector');
 smalltalk.addMethod(
 smalltalk.method({
-selector: "model",
+selector: "inspector",
 protocol: 'accessing',
 fn: function (){
 var self=this;
 var $1;
-$1=self["@model"];
+$1=self["@inspector"];
 return $1;
 },
 args: [],
-source: "model\x0a\x0a\x09^ model",
+source: "inspector\x0a\x09^ inspector",
 messageSends: [],
 referencedClasses: []
 }),
@@ -22,19 +22,37 @@ globals.HLInspectorDisplayWidget);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "model:",
+selector: "inspector:",
 protocol: 'accessing',
-fn: function (aModel){
+fn: function (anInspector){
 var self=this;
-self["@model"]=aModel;
+self["@inspector"]=anInspector;
 return self},
-args: ["aModel"],
-source: "model: aModel\x0a\x0a\x09model := aModel",
+args: ["anInspector"],
+source: "inspector: anInspector\x0a\x09inspector := anInspector",
 messageSends: [],
 referencedClasses: []
 }),
 globals.HLInspectorDisplayWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._inspector())._model();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"model",{},globals.HLInspectorDisplayWidget)})},
+args: [],
+source: "model\x0a\x0a\x09^ self inspector model",
+messageSends: ["model", "inspector"],
+referencedClasses: []
+}),
+globals.HLInspectorDisplayWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderContentOn:",
@@ -59,51 +77,32 @@ fn: function (){
 var self=this;
 var selection;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-selection=_st(self["@model"])._selection();
-$2=_st(_st(self["@model"])._variables())._includesKey_(selection);
-if(smalltalk.assert($2)){
-$1=_st(_st(self["@model"])._instVarObjectAt_(selection))._printString();
+var $1,$5,$4,$3,$2;
+$1=self._model();
+$ctx1.sendIdx["model"]=1;
+selection=_st($1)._selection();
+$5=self._model();
+$ctx1.sendIdx["model"]=2;
+$4=_st($5)._variables();
+$3=_st($4)._includesKey_(selection);
+if(smalltalk.assert($3)){
+$2=_st(_st(self._model())._instVarObjectAt_(selection))._printString();
 } else {
-$1="";
+$2="";
 };
-return $1;
+return $2;
 }, function($ctx1) {$ctx1.fill(self,"selectionDisplayString",{selection:selection},globals.HLInspectorDisplayWidget)})},
 args: [],
-source: "selectionDisplayString\x0a\x09|selection|\x0a\x09selection := model selection.\x0a    ^ (model variables includesKey: selection)\x0a    \x09ifTrue:[ (model instVarObjectAt: selection) printString ]\x0a      \x09ifFalse:[ '' ]",
-messageSends: ["selection", "ifTrue:ifFalse:", "includesKey:", "variables", "printString", "instVarObjectAt:"],
+source: "selectionDisplayString\x0a\x09|selection|\x0a\x09selection := self model selection.\x0a    ^ (self model variables includesKey: selection)\x0a    \x09ifTrue:[ (self model instVarObjectAt: selection) printString ]\x0a      \x09ifFalse:[ '' ]",
+messageSends: ["selection", "model", "ifTrue:ifFalse:", "includesKey:", "variables", "printString", "instVarObjectAt:"],
 referencedClasses: []
 }),
 globals.HLInspectorDisplayWidget);
 
 
 
-smalltalk.addClass('HLInspectorModel', globals.Object, ['announcer', 'environment', 'inspectee', 'code', 'variables', 'label', 'selection'], 'Helios-Inspector');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "announcer",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-function $Announcer(){return globals.Announcer||(typeof Announcer=="undefined"?nil:Announcer)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@announcer"];
-if(($receiver = $2) == nil || $receiver == null){
-self["@announcer"]=_st($Announcer())._new();
-$1=self["@announcer"];
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"announcer",{},globals.HLInspectorModel)})},
-args: [],
-source: "announcer\x0a\x09^ announcer ifNil: [ announcer := Announcer new ]",
-messageSends: ["ifNil:", "new"],
-referencedClasses: ["Announcer"]
-}),
-globals.HLInspectorModel);
-
+smalltalk.addClass('HLInspectorModel', globals.HLModel, ['inspectee', 'code', 'variables', 'label', 'selection'], 'Helios-Inspector');
+globals.HLInspectorModel.comment="I am the model of the Helios inspector `HLInspectorWidget`.\x0a\x0a## API\x0a\x0aUse the method `inspect:on:` to inspect an object on an inspector.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "code",
@@ -129,45 +128,6 @@ referencedClasses: ["HLCodeModel"]
 }),
 globals.HLInspectorModel);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "environment",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-function $HLManager(){return globals.HLManager||(typeof HLManager=="undefined"?nil:HLManager)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@environment"];
-if(($receiver = $2) == nil || $receiver == null){
-$1=_st(_st($HLManager())._current())._environment();
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"environment",{},globals.HLInspectorModel)})},
-args: [],
-source: "environment\x0a\x09^ environment ifNil: [ HLManager current environment ]",
-messageSends: ["ifNil:", "environment", "current"],
-referencedClasses: ["HLManager"]
-}),
-globals.HLInspectorModel);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "environment:",
-protocol: 'accessing',
-fn: function (anEnvironment){
-var self=this;
-self["@environment"]=anEnvironment;
-return self},
-args: ["anEnvironment"],
-source: "environment: anEnvironment\x0a\x09environment := anEnvironment",
-messageSends: [],
-referencedClasses: []
-}),
-globals.HLInspectorModel);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "inspect:on:",
@@ -427,7 +387,7 @@ referencedClasses: []
 globals.HLInspectorModel.klass);
 
 
-smalltalk.addClass('HLInspectorVariablesWidget', globals.HLNavigationListWidget, ['announcer', 'model', 'list', 'diveButton'], 'Helios-Inspector');
+smalltalk.addClass('HLInspectorVariablesWidget', globals.HLNavigationListWidget, ['announcer', 'inspector', 'list', 'diveButton'], 'Helios-Inspector');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "announcer",
@@ -473,34 +433,33 @@ globals.HLInspectorVariablesWidget);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "label",
-protocol: 'accessing',
+selector: "dive",
+protocol: 'actions',
 fn: function (){
 var self=this;
+function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(self._model())._label();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"label",{},globals.HLInspectorVariablesWidget)})},
+_st(self._announcer())._announce_(_st($HLDiveRequested())._new());
+return self}, function($ctx1) {$ctx1.fill(self,"dive",{},globals.HLInspectorVariablesWidget)})},
 args: [],
-source: "label\x0a\x09^ self model label",
-messageSends: ["label", "model"],
-referencedClasses: []
+source: "dive\x0a\x09self announcer announce: HLDiveRequested new",
+messageSends: ["announce:", "announcer", "new"],
+referencedClasses: ["HLDiveRequested"]
 }),
 globals.HLInspectorVariablesWidget);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "model",
+selector: "inspector",
 protocol: 'accessing',
 fn: function (){
 var self=this;
 var $1;
-$1=self["@model"];
+$1=self["@inspector"];
 return $1;
 },
 args: [],
-source: "model\x0a    ^ model",
+source: "inspector\x0a\x09^ inspector",
 messageSends: [],
 referencedClasses: []
 }),
@@ -508,19 +467,55 @@ globals.HLInspectorVariablesWidget);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "model:",
+selector: "inspector:",
 protocol: 'accessing',
-fn: function (aModel){
+fn: function (anInspector){
 var self=this;
-self["@model"]=aModel;
+self["@inspector"]=anInspector;
 return self},
-args: ["aModel"],
-source: "model: aModel\x0a    model := aModel",
+args: ["anInspector"],
+source: "inspector: anInspector\x0a\x09inspector := anInspector",
 messageSends: [],
 referencedClasses: []
 }),
 globals.HLInspectorVariablesWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._model())._label();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"label",{},globals.HLInspectorVariablesWidget)})},
+args: [],
+source: "label\x0a\x09^ self model label",
+messageSends: ["label", "model"],
+referencedClasses: []
+}),
+globals.HLInspectorVariablesWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._inspector())._model();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"model",{},globals.HLInspectorVariablesWidget)})},
+args: [],
+source: "model\x0a    ^ self inspector model",
+messageSends: ["model", "inspector"],
+referencedClasses: []
+}),
+globals.HLInspectorVariablesWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "refresh",
@@ -548,7 +543,6 @@ selector: "renderButtonsOn:",
 protocol: 'rendering',
 fn: function (html){
 var self=this;
-function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 $1=_st(html)._button();
@@ -556,14 +550,14 @@ _st($1)._class_("btn");
 _st($1)._with_("Dive");
 $2=_st($1)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(self._announcer())._announce_(_st($HLDiveRequested())._new());
+return self._dive();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 self["@diveButton"]=$2;
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},globals.HLInspectorVariablesWidget)})},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x09diveButton := html button \x0a\x09\x09class: 'btn';\x0a\x09\x09with: 'Dive'; \x0a\x09\x09onClick: [ self announcer announce: HLDiveRequested new ]",
-messageSends: ["class:", "button", "with:", "onClick:", "announce:", "announcer", "new"],
-referencedClasses: ["HLDiveRequested"]
+source: "renderButtonsOn: html\x0a\x09diveButton := html button \x0a\x09\x09class: 'btn';\x0a\x09\x09with: 'Dive'; \x0a\x09\x09onClick: [ self dive ]",
+messageSends: ["class:", "button", "with:", "onClick:", "dive"],
+referencedClasses: []
 }),
 globals.HLInspectorVariablesWidget);
 
@@ -576,10 +570,14 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 self._renderHeadOn_(html);
 globals.HLInspectorVariablesWidget.superclass.fn.prototype._renderContentOn_.apply(_st(self), [html]);
+_st(self._wrapper())._onDblClick_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._dive();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLInspectorVariablesWidget)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09self renderHeadOn: html.\x0a\x09super renderContentOn: html",
-messageSends: ["renderHeadOn:", "renderContentOn:"],
+source: "renderContentOn: html\x0a\x09self renderHeadOn: html.\x0a\x09super renderContentOn: html.\x0a\x09self wrapper onDblClick: [ self dive ]",
+messageSends: ["renderHeadOn:", "renderContentOn:", "onDblClick:", "wrapper", "dive"],
 referencedClasses: []
 }),
 globals.HLInspectorVariablesWidget);
@@ -682,14 +680,18 @@ fn: function (){
 var self=this;
 function $HLCodeWidget(){return globals.HLCodeWidget||(typeof HLCodeWidget=="undefined"?nil:HLCodeWidget)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$1;
+var $2,$3,$4,$6,$5,$7,$1;
 $2=self["@codeWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLCodeWidget())._new();
-_st($3)._model_(_st(self["@model"])._code());
-_st($3)._receiver_(_st(self["@model"])._inspectee());
-$4=_st($3)._yourself();
-self["@codeWidget"]=$4;
+$4=$3;
+$6=self._model();
+$ctx1.sendIdx["model"]=1;
+$5=_st($6)._code();
+_st($4)._model_($5);
+_st($3)._receiver_(_st(self._model())._inspectee());
+$7=_st($3)._yourself();
+self["@codeWidget"]=$7;
 $1=self["@codeWidget"];
 } else {
 $1=$2;
@@ -697,8 +699,8 @@ $1=$2;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"codeWidget",{},globals.HLInspectorWidget)})},
 args: [],
-source: "codeWidget\x0a\x09^ codeWidget ifNil: [\x0a\x09\x09codeWidget := HLCodeWidget new\x0a    \x09\x09model: model code;\x0a        \x09receiver: model inspectee;\x0a        \x09yourself ]",
-messageSends: ["ifNil:", "model:", "new", "code", "receiver:", "inspectee", "yourself"],
+source: "codeWidget\x0a\x09^ codeWidget ifNil: [\x0a\x09\x09codeWidget := HLCodeWidget new\x0a    \x09\x09model: self model code;\x0a        \x09receiver: self model inspectee;\x0a        \x09yourself ]",
+messageSends: ["ifNil:", "model:", "new", "code", "model", "receiver:", "inspectee", "yourself"],
 referencedClasses: ["HLCodeWidget"]
 }),
 globals.HLInspectorWidget);
@@ -715,7 +717,7 @@ var $2,$3,$4,$1;
 $2=self["@displayWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLInspectorDisplayWidget())._new();
-_st($3)._model_(self._model());
+_st($3)._inspector_(self);
 $4=_st($3)._yourself();
 self["@displayWidget"]=$4;
 $1=self["@displayWidget"];
@@ -725,8 +727,8 @@ $1=$2;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"displayWidget",{},globals.HLInspectorWidget)})},
 args: [],
-source: "displayWidget\x0a\x09^ displayWidget ifNil: [\x0a\x09\x09displayWidget := HLInspectorDisplayWidget new\x0a    \x09\x09model: self model;\x0a        \x09yourself ]",
-messageSends: ["ifNil:", "model:", "new", "model", "yourself"],
+source: "displayWidget\x0a\x09^ displayWidget ifNil: [\x0a\x09\x09displayWidget := HLInspectorDisplayWidget new\x0a    \x09\x09inspector: self;\x0a        \x09yourself ]",
+messageSends: ["ifNil:", "inspector:", "new", "yourself"],
 referencedClasses: ["HLInspectorDisplayWidget"]
 }),
 globals.HLInspectorWidget);
@@ -911,14 +913,11 @@ fn: function (){
 var self=this;
 function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self._variablesWidget())._announcer())._on_do_($HLDiveRequested(),(function(){
-return smalltalk.withContext(function($ctx2) {
-return self._onDive();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+_st(_st(self._variablesWidget())._announcer())._on_send_to_($HLDiveRequested(),"onDive",self);
 return self}, function($ctx1) {$ctx1.fill(self,"observeVariablesWidget",{},globals.HLInspectorWidget)})},
 args: [],
-source: "observeVariablesWidget\x0a\x09self variablesWidget announcer \x0a        on: HLDiveRequested do:[ self onDive ]",
-messageSends: ["on:do:", "announcer", "variablesWidget", "onDive"],
+source: "observeVariablesWidget\x0a\x09self variablesWidget announcer \x0a        on: HLDiveRequested \x0a\x09\x09send: #onDive\x0a\x09\x09to: self",
+messageSends: ["on:send:to:", "announcer", "variablesWidget"],
 referencedClasses: ["HLDiveRequested"]
 }),
 globals.HLInspectorWidget);
@@ -937,7 +936,7 @@ _st($1)._inspect_(_st(self._model())._selectedInstVarObject());
 $2=_st($1)._openAsTab();
 return self}, function($ctx1) {$ctx1.fill(self,"onDive",{},globals.HLInspectorWidget)})},
 args: [],
-source: "onDive\x0a\x0a\x09HLInspector new \x0a\x09\x09inspect: self model selectedInstVarObject;\x0a\x09\x09openAsTab",
+source: "onDive\x0a\x09HLInspector new \x0a\x09\x09inspect: self model selectedInstVarObject;\x0a\x09\x09openAsTab",
 messageSends: ["inspect:", "new", "selectedInstVarObject", "model", "openAsTab"],
 referencedClasses: ["HLInspector"]
 }),
@@ -1166,7 +1165,7 @@ var $2,$3,$4,$1;
 $2=self["@variablesWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLInspectorVariablesWidget())._new();
-_st($3)._model_(self._model());
+_st($3)._inspector_(self);
 $4=_st($3)._yourself();
 self["@variablesWidget"]=$4;
 $1=self["@variablesWidget"];
@@ -1176,8 +1175,8 @@ $1=$2;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"variablesWidget",{},globals.HLInspectorWidget)})},
 args: [],
-source: "variablesWidget\x0a\x09^ variablesWidget ifNil: [\x0a\x09\x09variablesWidget := HLInspectorVariablesWidget new\x0a    \x09\x09model: self model;\x0a        \x09yourself ]",
-messageSends: ["ifNil:", "model:", "new", "model", "yourself"],
+source: "variablesWidget\x0a\x09^ variablesWidget ifNil: [\x0a\x09\x09variablesWidget := HLInspectorVariablesWidget new\x0a    \x09\x09inspector: self;\x0a        \x09yourself ]",
+messageSends: ["ifNil:", "inspector:", "new", "yourself"],
 referencedClasses: ["HLInspectorVariablesWidget"]
 }),
 globals.HLInspectorWidget);

+ 43 - 36
js/Helios-Inspector.st → src/Helios-Inspector.st

@@ -1,18 +1,21 @@
 Smalltalk createPackage: 'Helios-Inspector'!
 HLNavigationListWidget subclass: #HLInspectorDisplayWidget
-	instanceVariableNames: 'model'
+	instanceVariableNames: 'inspector'
 	package: 'Helios-Inspector'!
 
 !HLInspectorDisplayWidget methodsFor: 'accessing'!
 
-model
+inspector
+	^ inspector
+!
 
-	^ model
+inspector: anInspector
+	inspector := anInspector
 !
 
-model: aModel
+model
 
-	model := aModel
+	^ self inspector model
 ! !
 
 !HLInspectorDisplayWidget methodsFor: 'rendering'!
@@ -24,35 +27,29 @@ renderContentOn: html
 
 selectionDisplayString
 	|selection|
-	selection := model selection.
-    ^ (model variables includesKey: selection)
-    	ifTrue:[ (model instVarObjectAt: selection) printString ]
+	selection := self model selection.
+    ^ (self model variables includesKey: selection)
+    	ifTrue:[ (self model instVarObjectAt: selection) printString ]
       	ifFalse:[ '' ]
 ! !
 
-Object subclass: #HLInspectorModel
-	instanceVariableNames: 'announcer environment inspectee code variables label selection'
+HLModel subclass: #HLInspectorModel
+	instanceVariableNames: 'inspectee code variables label selection'
 	package: 'Helios-Inspector'!
+!HLInspectorModel commentStamp!
+I am the model of the Helios inspector `HLInspectorWidget`.
 
-!HLInspectorModel methodsFor: 'accessing'!
+## API
 
-announcer
-	^ announcer ifNil: [ announcer := Announcer new ]
-!
+Use the method `inspect:on:` to inspect an object on an inspector.!
+
+!HLInspectorModel methodsFor: 'accessing'!
 
 code
 	"Answers the code model working for this workspace model"
 	^ code ifNil:[ code := HLCodeModel on: self environment ]
 !
 
-environment
-	^ environment ifNil: [ HLManager current environment ]
-!
-
-environment: anEnvironment
-	environment := anEnvironment
-!
-
 inspectee 
 	^ inspectee
 !
@@ -121,7 +118,7 @@ on: anEnvironment
 ! !
 
 HLNavigationListWidget subclass: #HLInspectorVariablesWidget
-	instanceVariableNames: 'announcer model list diveButton'
+	instanceVariableNames: 'announcer inspector list diveButton'
 	package: 'Helios-Inspector'!
 
 !HLInspectorVariablesWidget methodsFor: 'accessing'!
@@ -130,16 +127,20 @@ announcer
 	^ announcer ifNil:[ announcer := Announcer new ]
 !
 
+inspector
+	^ inspector
+!
+
+inspector: anInspector
+	inspector := anInspector
+!
+
 label
 	^ self model label
 !
 
 model
-    ^ model
-!
-
-model: aModel
-    model := aModel
+    ^ self inspector model
 !
 
 selection
@@ -152,6 +153,10 @@ variables
 
 !HLInspectorVariablesWidget methodsFor: 'actions'!
 
+dive
+	self announcer announce: HLDiveRequested new
+!
+
 refresh
 	self variables = self items ifFalse: [
 		self resetItems.
@@ -181,12 +186,13 @@ renderButtonsOn: html
 	diveButton := html button 
 		class: 'btn';
 		with: 'Dive'; 
-		onClick: [ self announcer announce: HLDiveRequested new ]
+		onClick: [ self dive ]
 !
 
 renderContentOn: html
 	self renderHeadOn: html.
-	super renderContentOn: html
+	super renderContentOn: html.
+	self wrapper onDblClick: [ self dive ]
 !
 
 renderHeadOn: html
@@ -204,15 +210,15 @@ HLWidget subclass: #HLInspectorWidget
 codeWidget
 	^ codeWidget ifNil: [
 		codeWidget := HLCodeWidget new
-    		model: model code;
-        	receiver: model inspectee;
+    		model: self model code;
+        	receiver: self model inspectee;
         	yourself ]
 !
 
 displayWidget
 	^ displayWidget ifNil: [
 		displayWidget := HLInspectorDisplayWidget new
-    		model: self model;
+    		inspector: self;
         	yourself ]
 !
 
@@ -256,7 +262,7 @@ tabLabel
 variablesWidget
 	^ variablesWidget ifNil: [
 		variablesWidget := HLInspectorVariablesWidget new
-    		model: self model;
+    		inspector: self;
         	yourself ]
 ! !
 
@@ -286,7 +292,9 @@ observeModel
 
 observeVariablesWidget
 	self variablesWidget announcer 
-        on: HLDiveRequested do:[ self onDive ]
+        on: HLDiveRequested 
+		send: #onDive
+		to: self
 !
 
 refresh
@@ -312,7 +320,6 @@ setVariables: aDictionary
 !HLInspectorWidget methodsFor: 'reactions'!
 
 onDive
-
 	HLInspector new 
 		inspect: self model selectedInstVarObject;
 		openAsTab

+ 20 - 11
js/Helios-KeyBindings.js → src/Helios-KeyBindings.js

@@ -1240,29 +1240,38 @@ protocol: 'events',
 fn: function (event){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1,$4;
+var $3,$2,$6,$5,$4,$1,$7;
 $3=_st(event)._which();
 $ctx1.sendIdx["which"]=1;
 $2=_st($3).__eq(self._escapeKey());
 $ctx1.sendIdx["="]=1;
 $1=_st($2)._or_((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(_st(_st(event)._which()).__eq((71)))._and_((function(){
+$6=_st(event)._which();
+$ctx2.sendIdx["which"]=2;
+$5=_st($6).__eq((71));
+$ctx2.sendIdx["="]=2;
+$4=_st($5)._or_((function(){
 return smalltalk.withContext(function($ctx3) {
-return _st(event)._ctrlKey();
+return _st(_st(event)._which()).__eq(self._activationKey());
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+return _st($4)._and_((function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(event)._ctrlKey();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$ctx1.sendIdx["or:"]=1;
 if(smalltalk.assert($1)){
 self._deactivate();
 _st(event)._preventDefault();
 return false;
 };
-$4=self._handleBindingFor_(event);
-return $4;
+$7=self._handleBindingFor_(event);
+return $7;
 }, function($ctx1) {$ctx1.fill(self,"handleActiveKeyDown:",{event:event},globals.HLKeyBinder)})},
 args: ["event"],
-source: "handleActiveKeyDown: event\x0a\x0a\x09\x22ESC or ctrl+g deactivate the keyBinder\x22\x0a\x09(event which = self escapeKey or: [\x0a\x09\x09event which = 71 and: [ event ctrlKey ] ])\x0a        \x09ifTrue: [ \x0a            \x09self deactivate.\x0a\x09\x09\x09\x09event preventDefault.\x0a\x09\x09\x09\x09^ false ].\x0a            \x0a    \x22Handle the keybinding\x22\x0a    ^ self handleBindingFor: event",
-messageSends: ["ifTrue:", "or:", "=", "which", "escapeKey", "and:", "ctrlKey", "deactivate", "preventDefault", "handleBindingFor:"],
+source: "handleActiveKeyDown: event\x0a\x0a\x09\x22ESC, ctrl+g ctrl+space deactivate the keyBinder\x22\x0a\x09(event which = self escapeKey or: [\x0a\x09\x09(event which = 71 or: [ event which = self activationKey ]) \x0a\x09\x09\x09and: [ event ctrlKey ] ])\x0a        \x09\x09ifTrue: [ \x0a           \x09\x09\x09self deactivate.\x0a\x09\x09\x09\x09\x09event preventDefault.\x0a\x09\x09\x09\x09\x09^ false ].\x0a            \x0a    \x22Handle the keybinding\x22\x0a    ^ self handleBindingFor: event",
+messageSends: ["ifTrue:", "or:", "=", "which", "escapeKey", "and:", "activationKey", "ctrlKey", "deactivate", "preventDefault", "handleBindingFor:"],
 referencedClasses: []
 }),
 globals.HLKeyBinder);
@@ -1583,11 +1592,11 @@ $1=_st(".".__comma(self._cssClass()))._asJQuery();
 $ctx1.sendIdx["asJQuery"]=1;
 _st($1)._remove();
 $ctx1.sendIdx["remove"]=1;
-_st("#overlay"._asJQuery())._remove();
+_st(".helper_overlay"._asJQuery())._remove();
 self._showCog();
 return self}, function($ctx1) {$ctx1.fill(self,"hide",{},globals.HLKeyBinderHelperWidget)})},
 args: [],
-source: "hide\x0a\x09('.', self cssClass) asJQuery remove.\x0a\x09'#overlay' asJQuery remove.\x0a\x09self showCog",
+source: "hide\x0a\x09('.', self cssClass) asJQuery remove.\x0a\x09'.helper_overlay' asJQuery remove.\x0a\x09self showCog",
 messageSends: ["remove", "asJQuery", ",", "cssClass", "showCog"],
 referencedClasses: []
 }),
@@ -1793,7 +1802,7 @@ $1=_st(html)._div();
 $ctx1.sendIdx["div"]=1;
 _st($1)._id_("overlay");
 $ctx1.sendIdx["id:"]=1;
-_st($1)._class_("light");
+_st($1)._class_("helper_overlay");
 $ctx1.sendIdx["class:"]=1;
 $2=_st($1)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
@@ -1818,7 +1827,7 @@ $ctx1.sendIdx["with:"]=1;
 _st(":focus"._asJQuery())._blur();
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLKeyBinderHelperWidget)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html div \x0a\x09\x09id: 'overlay';\x0a\x09\x09class: 'light';\x0a\x09\x09onClick: [ self deactivate ].\x0a\x09\x0a\x09html div class: self cssClass; with: [\x0a      \x09self renderLabelOn: html.\x0a\x09\x09html div\x0a\x09\x09\x09id: self mainId;\x0a\x09\x09\x09with: [ self renderSelectedBindingOn: html ].\x0a\x09\x09self renderCloseOn: html ].\x0a\x09\x09\x0a\x09':focus' asJQuery blur",
+source: "renderContentOn: html\x0a\x09html div \x0a\x09\x09id: 'overlay';\x0a\x09\x09class: 'helper_overlay';\x0a\x09\x09onClick: [ self deactivate ].\x0a\x09\x0a\x09html div class: self cssClass; with: [\x0a      \x09self renderLabelOn: html.\x0a\x09\x09html div\x0a\x09\x09\x09id: self mainId;\x0a\x09\x09\x09with: [ self renderSelectedBindingOn: html ].\x0a\x09\x09self renderCloseOn: html ].\x0a\x09\x09\x0a\x09':focus' asJQuery blur",
 messageSends: ["id:", "div", "class:", "onClick:", "deactivate", "cssClass", "with:", "renderLabelOn:", "mainId", "renderSelectedBindingOn:", "renderCloseOn:", "blur", "asJQuery"],
 referencedClasses: []
 }),

+ 9 - 8
js/Helios-KeyBindings.st → src/Helios-KeyBindings.st

@@ -429,13 +429,14 @@ defaultBindings
 
 handleActiveKeyDown: event
 
-	"ESC or ctrl+g deactivate the keyBinder"
+	"ESC, ctrl+g ctrl+space deactivate the keyBinder"
 	(event which = self escapeKey or: [
-		event which = 71 and: [ event ctrlKey ] ])
-        	ifTrue: [ 
-            	self deactivate.
-				event preventDefault.
-				^ false ].
+		(event which = 71 or: [ event which = self activationKey ]) 
+			and: [ event ctrlKey ] ])
+        		ifTrue: [ 
+           			self deactivate.
+					event preventDefault.
+					^ false ].
             
     "Handle the keybinding"
     ^ self handleBindingFor: event
@@ -542,7 +543,7 @@ deactivate
 
 hide
 	('.', self cssClass) asJQuery remove.
-	'#overlay' asJQuery remove.
+	'.helper_overlay' asJQuery remove.
 	self showCog
 !
 
@@ -607,7 +608,7 @@ renderCog
 renderContentOn: html
 	html div 
 		id: 'overlay';
-		class: 'light';
+		class: 'helper_overlay';
 		onClick: [ self deactivate ].
 	
 	html div class: self cssClass; with: [

+ 1 - 1
js/Helios-Layout.js → src/Helios-Layout.js

@@ -1,4 +1,4 @@
-define("amber_core/Helios-Layout", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Helios-Core", "amber_core/Canvas", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Helios-Layout", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Helios-Core", "amber_core/Web", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
 smalltalk.addPackage('Helios-Layout');
 smalltalk.packages["Helios-Layout"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 0 - 0
js/Helios-Layout.st → src/Helios-Layout.st


+ 0 - 0
js/Helios-References.js → src/Helios-References.js


+ 0 - 0
js/Helios-References.st → src/Helios-References.st


+ 67 - 0
src/Helios-SUnit.js

@@ -0,0 +1,67 @@
+define("amber_core/Helios-SUnit", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Helios-Core"], function(smalltalk,nil,_st, globals){
+smalltalk.addPackage('Helios-SUnit');
+smalltalk.packages["Helios-SUnit"].transport = {"type":"amd","amdNamespace":"amber_core"};
+
+smalltalk.addClass('HLSUnit', globals.HLWidget, [], 'Helios-SUnit');
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "canBeOpenAsTab",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+},
+args: [],
+source: "canBeOpenAsTab\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnit.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tabClass",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "sunit";
+},
+args: [],
+source: "tabClass\x0a\x09^ 'sunit'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnit.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tabLabel",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "SUnit";
+},
+args: [],
+source: "tabLabel\x0a\x09^ 'SUnit'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnit.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tabPriority",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return (1000);
+},
+args: [],
+source: "tabPriority\x0a\x09^ 1000",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnit.klass);
+
+});

+ 25 - 0
src/Helios-SUnit.st

@@ -0,0 +1,25 @@
+Smalltalk createPackage: 'Helios-SUnit'!
+HLWidget subclass: #HLSUnit
+	instanceVariableNames: ''
+	package: 'Helios-SUnit'!
+
+!HLSUnit class methodsFor: 'accessing'!
+
+tabClass
+	^ 'sunit'
+!
+
+tabLabel
+	^ 'SUnit'
+!
+
+tabPriority
+	^ 1000
+! !
+
+!HLSUnit class methodsFor: 'testing'!
+
+canBeOpenAsTab
+	^ true
+! !
+

+ 2 - 2
js/Helios-Transcript.js → src/Helios-Transcript.js

@@ -3,7 +3,7 @@ smalltalk.addPackage('Helios-Transcript');
 smalltalk.packages["Helios-Transcript"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 smalltalk.addClass('HLTranscript', globals.HLWidget, ['textarea'], 'Helios-Transcript');
-globals.HLTranscript.comment="I am a widget responsible for displaying transcript contents.\x0a\x0a## Transcript API\x0a\x0a    Transcript \x0a        show: 'hello world';\x0a        cr;\x0a        show: anObject.\x0a\x0a    Transcript clear.\x0a\x0aSee the `Transcript` class.";
+globals.HLTranscript.comment="I am a widget responsible for displaying transcript contents.\x0a\x0a## Transcript API\x0a\x0a    Transcript \x0a        show: 'hello world';\x0a        cr;\x0a        show: anObject.\x0a\x0a    Transcript clear.\x0a\x0aSee the `Transcript` service class.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "clear",
@@ -120,7 +120,7 @@ globals.HLTranscript);
 
 
 smalltalk.addClass('HLTranscriptHandler', globals.Object, [], 'Helios-Transcript');
-globals.HLTranscriptHandler.comment="I handle transcript events, dispatching them to all instances of `HLTranscript`.\x0a\x0a## API\x0a\x0aOn class initialization I am automatically registered as the current transcript.";
+globals.HLTranscriptHandler.comment="I handle transcript events, dispatching them to all instances of `HLTranscript`.\x0a\x0a## API\x0a\x0aUse the class-side method `#register:` to add transcript instances.";
 
 globals.HLTranscriptHandler.klass.iVarNames = ['transcripts'];
 smalltalk.addMethod(

+ 2 - 2
js/Helios-Transcript.st → src/Helios-Transcript.st

@@ -14,7 +14,7 @@ I am a widget responsible for displaying transcript contents.
 
     Transcript clear.
 
-See the `Transcript` class.!
+See the `Transcript` service class.!
 
 !HLTranscript methodsFor: 'actions'!
 
@@ -61,7 +61,7 @@ I handle transcript events, dispatching them to all instances of `HLTranscript`.
 
 ## API
 
-On class initialization I am automatically registered as the current transcript.!
+Use the class-side method `#register:` to add transcript instances.!
 
 HLTranscriptHandler class instanceVariableNames: 'transcripts'!
 

+ 0 - 0
js/Helios-Workspace-Tests.js → src/Helios-Workspace-Tests.js


+ 0 - 0
js/Helios-Workspace-Tests.st → src/Helios-Workspace-Tests.st


+ 182 - 63
js/Helios-Workspace.js → src/Helios-Workspace.js

@@ -28,6 +28,22 @@ referencedClasses: ["Announcer"]
 }),
 globals.HLCodeModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "browse:",
+protocol: 'actions',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(anObject)._browse();
+return self}, function($ctx1) {$ctx1.fill(self,"browse:",{anObject:anObject},globals.HLCodeModel)})},
+args: ["anObject"],
+source: "browse: anObject\x0a\x09anObject browse",
+messageSends: ["browse"],
+referencedClasses: []
+}),
+globals.HLCodeModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "defaultReceiver",
@@ -52,15 +68,23 @@ selector: "doIt:",
 protocol: 'actions',
 fn: function (aString){
 var self=this;
+function $ErrorHandler(){return globals.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self._environment())._eval_on_(aString,self._receiver());
+$1=self._try_catch_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._environment())._eval_on_(aString,self._receiver());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(e){
+return smalltalk.withContext(function($ctx2) {
+_st($ErrorHandler())._handleError_(e);
+return nil;
+}, function($ctx2) {$ctx2.fillBlock({e:e},$ctx1,2)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLCodeModel)})},
 args: ["aString"],
-source: "doIt: aString\x0a\x0a\x09^ self environment eval: aString on: self receiver",
-messageSends: ["eval:on:", "environment", "receiver"],
-referencedClasses: []
+source: "doIt: aString\x0a\x09\x22Evaluate aString in the receiver's `environment`.\x0a\x09\x0a\x09Note: Catch any error and handle it manually, bypassing\x0a\x09boot.js behavior to avoid the browser default action on\x0a\x09ctrl+d/ctrl+p.\x0a\x09\x0a\x09See https://github.com/amber-smalltalk/amber/issues/882\x22\x0a\x0a\x09^ self \x0a\x09\x09try: [ self environment eval: aString on: self receiver ]\x0a\x09\x09catch: [ :e | \x0a\x09\x09\x09ErrorHandler handleError: e.\x0a\x09\x09\x09nil ]",
+messageSends: ["try:catch:", "eval:on:", "environment", "receiver", "handleError:"],
+referencedClasses: ["ErrorHandler"]
 }),
 globals.HLCodeModel);
 
@@ -200,6 +224,38 @@ referencedClasses: []
 }),
 globals.HLCodeWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "browseIt",
+protocol: 'actions',
+fn: function (){
+var self=this;
+var result;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+function $ErrorHandler(){return globals.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+var $early={};
+try {
+result=_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._doIt();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(exception){
+return smalltalk.withContext(function($ctx2) {
+$1=_st($ErrorHandler())._handleError_(exception);
+throw $early=[$1];
+}, function($ctx2) {$ctx2.fillBlock({exception:exception},$ctx1,2)})}));
+_st(self._model())._browse_(result);
+return self}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"browseIt",{result:result},globals.HLCodeWidget)})},
+args: [],
+source: "browseIt\x0a\x09| result |\x0a\x09\x0a\x09result := [ self doIt ] on: Error do: [ :exception | \x0a\x09\x09^ ErrorHandler handleError: exception ].\x0a\x09\x09\x0a\x09self model browse: result",
+messageSends: ["on:do:", "doIt", "handleError:", "browse:", "model"],
+referencedClasses: ["Error", "ErrorHandler"]
+}),
+globals.HLCodeWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "canHaveFocus",
@@ -238,18 +294,31 @@ protocol: 'actions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
+var $1,$2,$3;
 $1=self._editor();
 $ctx1.sendIdx["editor"]=1;
 _st($1)._at_put_("amberCodeWidget",self);
-_st(self._editor())._on_do_("change",(function(){
+$2=self._editor();
+$ctx1.sendIdx["editor"]=2;
+_st($2)._on_do_("change",(function(){
 return smalltalk.withContext(function($ctx2) {
 return self._onChange();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+_st(_st(self._wrapper())._asJQuery())._on_in_do_("mousedown",".CodeMirror pre",(function(event){
+var position,node;
+return smalltalk.withContext(function($ctx2) {
+$3=_st(event)._at_("ctrlKey");
+if(smalltalk.assert($3)){
+position=_st(self._editor())._coordsChar_(globals.HashedCollection._newFromPairs_(["left",_st(event)._clientX(),"top",_st(event)._clientY()]));
+position;
+self._onCtrlClickAt_(_st(_st(_st(position)._line()).__at(_st(position)._ch())).__plus((1)));
+return _st(event)._preventDefault();
+};
+}, function($ctx2) {$ctx2.fillBlock({event:event,position:position,node:node},$ctx1,2)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"configureEditor",{},globals.HLCodeWidget)})},
 args: [],
-source: "configureEditor\x0a\x09self editor at: 'amberCodeWidget' put: self.\x0a\x09self editor on: 'change' do: [ self onChange ]",
-messageSends: ["at:put:", "editor", "on:do:", "onChange"],
+source: "configureEditor\x0a\x09self editor at: 'amberCodeWidget' put: self.\x0a\x09self editor on: 'change' do: [ self onChange ].\x0a\x0a\x09self wrapper asJQuery on: 'mousedown' in: '.CodeMirror pre' do: [ :event | | position node |\x0a\x09\x09(event at: 'ctrlKey') ifTrue: [\x0a\x09\x09\x09position := self editor coordsChar: #{ \x0a\x09\x09\x09\x09'left' -> event clientX.\x0a\x09\x09\x09\x09'top' -> event clientY\x0a\x09\x09\x09}.\x0a\x09\x09\x09self onCtrlClickAt: (position line @ position ch) + 1.\x0a\x09\x09\x09event preventDefault ] ]",
+messageSends: ["at:put:", "editor", "on:do:", "onChange", "on:in:do:", "asJQuery", "wrapper", "ifTrue:", "at:", "coordsChar:", "clientX", "clientY", "onCtrlClickAt:", "+", "@", "line", "ch", "preventDefault"],
 referencedClasses: []
 }),
 globals.HLCodeWidget);
@@ -343,27 +412,20 @@ protocol: 'actions',
 fn: function (){
 var self=this;
 var result;
-function $HLDoItRequested(){return globals.HLDoItRequested||(typeof HLDoItRequested=="undefined"?nil:HLDoItRequested)}
 function $HLDoItExecuted(){return globals.HLDoItExecuted||(typeof HLDoItExecuted=="undefined"?nil:HLDoItExecuted)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$3,$4;
-$2=self._model();
+var $1,$2;
+$1=self._model();
 $ctx1.sendIdx["model"]=1;
-$1=_st($2)._announcer();
-$ctx1.sendIdx["announcer"]=1;
-$3=_st($HLDoItRequested())._on_(self["@model"]);
-$ctx1.sendIdx["on:"]=1;
-_st($1)._announce_($3);
-$ctx1.sendIdx["announce:"]=1;
-result=_st(self["@model"])._doIt_(self._currentLineOrSelection());
+result=_st($1)._doIt_(self._currentLineOrSelection());
 _st(_st(self._model())._announcer())._announce_(_st($HLDoItExecuted())._on_(self["@model"]));
-$4=result;
-return $4;
+$2=result;
+return $2;
 }, function($ctx1) {$ctx1.fill(self,"doIt",{result:result},globals.HLCodeWidget)})},
 args: [],
-source: "doIt\x0a\x09| result |\x0a\x0a\x09self model announcer announce: (HLDoItRequested on: model).\x0a\x09result := model doIt: self currentLineOrSelection.\x0a\x09self model announcer announce: (HLDoItExecuted on: model).\x0a\x0a\x09^ result",
-messageSends: ["announce:", "announcer", "model", "on:", "doIt:", "currentLineOrSelection"],
-referencedClasses: ["HLDoItRequested", "HLDoItExecuted"]
+source: "doIt\x0a\x09| result |\x0a\x0a\x09result := self model doIt: self currentLineOrSelection.\x0a\x09self model announcer announce: (HLDoItExecuted on: model).\x0a\x0a\x09^ result",
+messageSends: ["doIt:", "model", "currentLineOrSelection", "announce:", "announcer", "on:"],
+referencedClasses: ["HLDoItExecuted"]
 }),
 globals.HLCodeWidget);
 
@@ -460,20 +522,13 @@ selector: "inspectIt",
 protocol: 'actions',
 fn: function (){
 var self=this;
-var newInspector;
-function $HLInspectItRequested(){return globals.HLInspectItRequested||(typeof HLInspectItRequested=="undefined"?nil:HLInspectItRequested)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._model();
-$ctx1.sendIdx["model"]=1;
-$1=_st($2)._announcer();
-_st($1)._announce_(_st($HLInspectItRequested())._on_(self["@model"]));
 _st(self._model())._inspect_(self._doIt());
-return self}, function($ctx1) {$ctx1.fill(self,"inspectIt",{newInspector:newInspector},globals.HLCodeWidget)})},
+return self}, function($ctx1) {$ctx1.fill(self,"inspectIt",{},globals.HLCodeWidget)})},
 args: [],
-source: "inspectIt\x0a\x09| newInspector |\x0a       \x0a\x09self model announcer announce: (HLInspectItRequested on: model).\x0a\x09self model inspect: self doIt",
-messageSends: ["announce:", "announcer", "model", "on:", "inspect:", "doIt"],
-referencedClasses: ["HLInspectItRequested"]
+source: "inspectIt\x0a\x09self model inspect: self doIt",
+messageSends: ["inspect:", "model", "doIt"],
+referencedClasses: []
 }),
 globals.HLCodeWidget);
 
@@ -544,6 +599,40 @@ referencedClasses: []
 }),
 globals.HLCodeWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "navigateTo:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+function $Finder(){return globals.Finder||(typeof Finder=="undefined"?nil:Finder)}
+return smalltalk.withContext(function($ctx1) { 
+_st($Finder())._findString_(aString);
+return self}, function($ctx1) {$ctx1.fill(self,"navigateTo:",{aString:aString},globals.HLCodeWidget)})},
+args: ["aString"],
+source: "navigateTo: aString\x0a\x09Finder findString: aString",
+messageSends: ["findString:"],
+referencedClasses: ["Finder"]
+}),
+globals.HLCodeWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "navigateToReference:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+function $HLReferences(){return globals.HLReferences||(typeof HLReferences=="undefined"?nil:HLReferences)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st($HLReferences())._openAsTab())._search_(aString);
+return self}, function($ctx1) {$ctx1.fill(self,"navigateToReference:",{aString:aString},globals.HLCodeWidget)})},
+args: ["aString"],
+source: "navigateToReference: aString\x0a\x09(HLReferences openAsTab)\x0a\x09\x09search: aString",
+messageSends: ["search:", "openAsTab"],
+referencedClasses: ["HLReferences"]
+}),
+globals.HLCodeWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "onChange",
@@ -562,17 +651,33 @@ globals.HLCodeWidget);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onDoIt",
+selector: "onCtrlClickAt:",
 protocol: 'reactions',
-fn: function (){
+fn: function (aPoint){
 var self=this;
+var ast,node;
+function $Smalltalk(){return globals.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
 return smalltalk.withContext(function($ctx1) { 
-self._doIt();
-return self}, function($ctx1) {$ctx1.fill(self,"onDoIt",{},globals.HLCodeWidget)})},
-args: [],
-source: "onDoIt\x0a\x09\x0a\x09self doIt",
-messageSends: ["doIt"],
-referencedClasses: []
+var $early={};
+try {
+ast=_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st($Smalltalk())._parse_(_st(self._editor())._getValue());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(error){
+throw $early=[self];
+}));
+node=_st(ast)._navigationNodeAt_ifAbsent_(aPoint,(function(){
+throw $early=[nil];
+}));
+self._navigateTo_(_st(node)._navigationLink());
+return self}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"onCtrlClickAt:",{aPoint:aPoint,ast:ast,node:node},globals.HLCodeWidget)})},
+args: ["aPoint"],
+source: "onCtrlClickAt: aPoint\x0a\x09| ast node |\x0a\x09\x0a\x09ast := [ Smalltalk parse: self editor getValue ] \x0a\x09\x09on: Error \x0a\x09\x09do: [ :error | ^ self ].\x0a\x09\x0a\x09node := ast \x0a\x09\x09navigationNodeAt: aPoint \x0a\x09\x09ifAbsent: [ ^ nil ].\x0a\x09\x09\x0a\x09self navigateTo: node navigationLink",
+messageSends: ["on:do:", "parse:", "getValue", "editor", "navigationNodeAt:ifAbsent:", "navigateTo:", "navigationLink"],
+referencedClasses: ["Smalltalk", "Error"]
 }),
 globals.HLCodeWidget);
 
@@ -686,18 +791,14 @@ selector: "printIt",
 protocol: 'actions',
 fn: function (){
 var self=this;
-var result;
-function $HLPrintItRequested(){return globals.HLPrintItRequested||(typeof HLPrintItRequested=="undefined"?nil:HLPrintItRequested)}
 return smalltalk.withContext(function($ctx1) { 
-result=self._doIt();
-_st(_st(self._model())._announcer())._announce_(_st($HLPrintItRequested())._on_(self["@model"]));
-self._print_(_st(result)._printString());
+self._print_(_st(self._doIt())._printString());
 self._focus();
-return self}, function($ctx1) {$ctx1.fill(self,"printIt",{result:result},globals.HLCodeWidget)})},
+return self}, function($ctx1) {$ctx1.fill(self,"printIt",{},globals.HLCodeWidget)})},
 args: [],
-source: "printIt\x0a\x09| result |\x0a\x0a\x09result := self doIt.       \x0a\x09self model announcer announce: (HLPrintItRequested on: model).\x0a\x09self print: result printString.\x0a\x09\x0a\x09self focus.",
-messageSends: ["doIt", "announce:", "announcer", "model", "on:", "print:", "printString", "focus"],
-referencedClasses: ["HLPrintItRequested"]
+source: "printIt\x0a\x09self print: self doIt printString.\x0a\x09self focus.",
+messageSends: ["print:", "printString", "doIt", "focus"],
+referencedClasses: []
 }),
 globals.HLCodeWidget);
 
@@ -742,7 +843,7 @@ protocol: 'rendering',
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5,$6;
+var $1,$2,$3,$4,$5,$6,$7,$8;
 $1=_st(html)._button();
 $ctx1.sendIdx["button"]=1;
 _st($1)._class_("button");
@@ -766,16 +867,27 @@ return self._printIt();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 $ctx1.sendIdx["onClick:"]=2;
 $5=_st(html)._button();
+$ctx1.sendIdx["button"]=3;
 _st($5)._class_("button");
+$ctx1.sendIdx["class:"]=3;
 _st($5)._with_("InspectIt");
+$ctx1.sendIdx["with:"]=3;
 $6=_st($5)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
 return self._inspectIt();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+$ctx1.sendIdx["onClick:"]=3;
+$7=_st(html)._button();
+_st($7)._class_("button");
+_st($7)._with_("BrowseIt");
+$8=_st($7)._onClick_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._browseIt();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},globals.HLCodeWidget)})},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'DoIt';\x0a\x09\x09onClick: [ self doIt ].\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'PrintIt';\x0a\x09\x09onClick: [ self printIt ].\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'InspectIt';\x0a\x09\x09onClick: [ self inspectIt ]",
-messageSends: ["class:", "button", "with:", "onClick:", "doIt", "printIt", "inspectIt"],
+source: "renderButtonsOn: html\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'DoIt';\x0a\x09\x09onClick: [ self doIt ].\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'PrintIt';\x0a\x09\x09onClick: [ self printIt ].\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'InspectIt';\x0a\x09\x09onClick: [ self inspectIt ].\x0a\x09html button \x0a\x09\x09class: 'button';\x0a\x09\x09with: 'BrowseIt';\x0a\x09\x09onClick: [ self browseIt ]",
+messageSends: ["class:", "button", "with:", "onClick:", "doIt", "printIt", "inspectIt", "browseIt"],
 referencedClasses: []
 }),
 globals.HLCodeWidget);
@@ -1102,11 +1214,11 @@ protocol: 'accessing',
 fn: function (){
 var self=this;
 var $1;
-$1=globals.HashedCollection._newFromPairs_(["Alt-Backspace","delWordBefore","Alt-Delete","delWordAfter","Alt-Left","goWordLeft","Alt-Right","goWordRight","Cmd-A","selectAll","Cmd-Alt-F","replace","Cmd-D","doIt","Cmd-Down","goDocEnd","Cmd-End","goDocEnd","Cmd-F","find","Cmd-G","findNext","Cmd-I","inspectIt","Cmd-Left","goLineStart","Cmd-P","printIt","Cmd-Right","goLineEnd","Cmd-S","saveIt","Cmd-Up","goDocStart","Cmd-Y","redo","Cmd-Z","undo","Cmd-[","indentLess","Cmd-]","indentMore","Ctrl-Alt-Backspace","delWordAfter","Shift-Cmd-Alt-F","replaceAll","Shift-Cmd-G","findPrev","Shift-Cmd-Z","redo","fallthrough",["basic","emacsy"]]);
+$1=globals.HashedCollection._newFromPairs_(["Alt-Backspace","delWordBefore","Alt-Delete","delWordAfter","Alt-Left","goWordLeft","Alt-Right","goWordRight","Cmd-A","selectAll","Cmd-Alt-F","replace","Cmd-D","doIt","Cmd-B","browseIt","Cmd-Down","goDocEnd","Cmd-End","goDocEnd","Cmd-F","find","Cmd-G","findNext","Cmd-I","inspectIt","Cmd-Left","goLineStart","Cmd-P","printIt","Cmd-Right","goLineEnd","Cmd-S","saveIt","Cmd-Up","goDocStart","Cmd-Y","redo","Cmd-Z","undo","Cmd-[","indentLess","Cmd-]","indentMore","Ctrl-Alt-Backspace","delWordAfter","Shift-Cmd-Alt-F","replaceAll","Shift-Cmd-G","findPrev","Shift-Cmd-Z","redo","fallthrough",["basic","emacsy"]]);
 return $1;
 },
 args: [],
-source: "macKeyMap\x0a\x09^ #{\x0a\x09\x09'Alt-Backspace'\x09\x09\x09-> 'delWordBefore'.\x0a\x09\x09'Alt-Delete'\x09\x09\x09-> 'delWordAfter'. \x0a\x09\x09'Alt-Left'\x09\x09\x09\x09-> 'goWordLeft'.\x0a\x09\x09'Alt-Right'\x09\x09\x09\x09-> 'goWordRight'. \x0a\x09\x09'Cmd-A'\x09\x09\x09\x09\x09-> 'selectAll'. \x0a\x09\x09'Cmd-Alt-F'\x09\x09\x09\x09-> 'replace'. \x0a\x09\x09'Cmd-D'\x09\x09\x09\x09\x09-> 'doIt'. \x0a\x09\x09'Cmd-Down'\x09\x09\x09\x09-> 'goDocEnd'. \x0a\x09\x09'Cmd-End'\x09\x09\x09\x09-> 'goDocEnd'. \x0a\x09\x09'Cmd-F'\x09\x09\x09\x09\x09-> 'find'.\x0a\x09\x09'Cmd-G'\x09\x09\x09\x09\x09-> 'findNext'. \x0a\x09\x09'Cmd-I'\x09\x09\x09\x09\x09-> 'inspectIt'. \x0a\x09\x09'Cmd-Left'\x09\x09\x09\x09-> 'goLineStart'. \x0a\x09\x09'Cmd-P'\x09\x09\x09\x09\x09-> 'printIt'. \x0a\x09\x09'Cmd-Right'\x09\x09\x09\x09-> 'goLineEnd'. \x0a\x09\x09'Cmd-S'\x09\x09\x09\x09\x09-> 'saveIt'. \x0a\x09\x09'Cmd-Up'\x09\x09\x09\x09-> 'goDocStart'. \x0a\x09\x09'Cmd-Y'\x09\x09\x09\x09\x09-> 'redo'.\x0a\x09\x09'Cmd-Z'\x09\x09\x09\x09\x09-> 'undo'. \x0a\x09\x09'Cmd-['\x09\x09\x09\x09\x09-> 'indentLess'. \x0a\x09\x09'Cmd-]'\x09\x09\x09\x09\x09-> 'indentMore'.\x0a\x09\x09'Ctrl-Alt-Backspace'\x09-> 'delWordAfter'. \x0a\x09\x09'Shift-Cmd-Alt-F'\x09\x09-> 'replaceAll'.\x0a\x09\x09'Shift-Cmd-G'\x09\x09\x09-> 'findPrev'. \x0a\x09\x09'Shift-Cmd-Z'\x09\x09\x09-> 'redo'. \x0a    \x09'fallthrough' \x09\x09\x09-> { 'basic'. 'emacsy' }\x0a  }",
+source: "macKeyMap\x0a\x09^ #{\x0a\x09\x09'Alt-Backspace'\x09\x09\x09-> 'delWordBefore'.\x0a\x09\x09'Alt-Delete'\x09\x09\x09-> 'delWordAfter'. \x0a\x09\x09'Alt-Left'\x09\x09\x09\x09-> 'goWordLeft'.\x0a\x09\x09'Alt-Right'\x09\x09\x09\x09-> 'goWordRight'. \x0a\x09\x09'Cmd-A'\x09\x09\x09\x09\x09-> 'selectAll'. \x0a\x09\x09'Cmd-Alt-F'\x09\x09\x09\x09-> 'replace'. \x0a\x09\x09'Cmd-D'\x09\x09\x09\x09\x09-> 'doIt'. \x0a\x09\x09'Cmd-B'\x09\x09\x09\x09\x09-> 'browseIt'. \x0a\x09\x09'Cmd-Down'\x09\x09\x09\x09-> 'goDocEnd'. \x0a\x09\x09'Cmd-End'\x09\x09\x09\x09-> 'goDocEnd'. \x0a\x09\x09'Cmd-F'\x09\x09\x09\x09\x09-> 'find'.\x0a\x09\x09'Cmd-G'\x09\x09\x09\x09\x09-> 'findNext'. \x0a\x09\x09'Cmd-I'\x09\x09\x09\x09\x09-> 'inspectIt'. \x0a\x09\x09'Cmd-Left'\x09\x09\x09\x09-> 'goLineStart'. \x0a\x09\x09'Cmd-P'\x09\x09\x09\x09\x09-> 'printIt'. \x0a\x09\x09'Cmd-Right'\x09\x09\x09\x09-> 'goLineEnd'. \x0a\x09\x09'Cmd-S'\x09\x09\x09\x09\x09-> 'saveIt'. \x0a\x09\x09'Cmd-Up'\x09\x09\x09\x09-> 'goDocStart'. \x0a\x09\x09'Cmd-Y'\x09\x09\x09\x09\x09-> 'redo'.\x0a\x09\x09'Cmd-Z'\x09\x09\x09\x09\x09-> 'undo'. \x0a\x09\x09'Cmd-['\x09\x09\x09\x09\x09-> 'indentLess'. \x0a\x09\x09'Cmd-]'\x09\x09\x09\x09\x09-> 'indentMore'.\x0a\x09\x09'Ctrl-Alt-Backspace'\x09-> 'delWordAfter'. \x0a\x09\x09'Shift-Cmd-Alt-F'\x09\x09-> 'replaceAll'.\x0a\x09\x09'Shift-Cmd-G'\x09\x09\x09-> 'findPrev'. \x0a\x09\x09'Shift-Cmd-Z'\x09\x09\x09-> 'redo'. \x0a    \x09'fallthrough' \x09\x09\x09-> { 'basic'. 'emacsy' }\x0a  }",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1137,11 +1249,11 @@ protocol: 'accessing',
 fn: function (){
 var self=this;
 var $1;
-$1=globals.HashedCollection._newFromPairs_(["Alt-Left","goLineStart","Alt-Right","goLineEnd","Alt-Up","goDocStart","Ctrl-A","selectAll","Ctrl-Backspace","delWordBefore","Ctrl-D","doIt","Ctrl-Delete","delWordAfter","Ctrl-Down","goDocEnd","Ctrl-End","goDocEnd","Ctrl-F","find","Ctrl-G","findNext","Ctrl-I","inspectIt","Ctrl-Home","goDocStart","Ctrl-Left","goWordLeft","Ctrl-P","printIt","Ctrl-Right","goWordRight","Ctrl-S","saveIt","Ctrl-Y","redo","Ctrl-Z","undo","Ctrl-[","indentLess","Ctrl-]","indentMore","Shift-Ctrl-F","replace","Shift-Ctrl-G","findPrev","Shift-Ctrl-R","replaceAll","Shift-Ctrl-Z","redo","fallthrough",["basic"]]);
+$1=globals.HashedCollection._newFromPairs_(["Alt-Left","goLineStart","Alt-Right","goLineEnd","Alt-Up","goDocStart","Ctrl-A","selectAll","Ctrl-Backspace","delWordBefore","Ctrl-D","doIt","Ctrl-B","browseIt","Ctrl-Delete","delWordAfter","Ctrl-Down","goDocEnd","Ctrl-End","goDocEnd","Ctrl-F","find","Ctrl-G","findNext","Ctrl-I","inspectIt","Ctrl-Home","goDocStart","Ctrl-Left","goWordLeft","Ctrl-P","printIt","Ctrl-Right","goWordRight","Ctrl-S","saveIt","Ctrl-Y","redo","Ctrl-Z","undo","Ctrl-[","indentLess","Ctrl-]","indentMore","Shift-Ctrl-F","replace","Shift-Ctrl-G","findPrev","Shift-Ctrl-R","replaceAll","Shift-Ctrl-Z","redo","fallthrough",["basic"]]);
 return $1;
 },
 args: [],
-source: "pcKeyMap\x0a\x09^ #{\x0a\x09\x09'Alt-Left' -> \x09\x09'goLineStart'. \x0a\x09\x09'Alt-Right' -> \x09\x09'goLineEnd'.\x0a\x09\x09'Alt-Up' -> \x09\x09'goDocStart'. \x0a\x09\x09'Ctrl-A' -> \x09\x09'selectAll'. \x0a\x09\x09'Ctrl-Backspace' -> 'delWordBefore'. \x0a\x09\x09'Ctrl-D' -> \x09\x09'doIt'. \x0a\x09\x09'Ctrl-Delete' -> \x09\x09'delWordAfter'. \x0a\x09\x09'Ctrl-Down' -> \x09\x09'goDocEnd'.\x0a\x09\x09'Ctrl-End' -> \x09\x09'goDocEnd'. \x0a\x09\x09'Ctrl-F' -> \x09\x09'find'.\x0a\x09\x09'Ctrl-G' -> \x09\x09'findNext'. \x0a\x09\x09'Ctrl-I' -> \x09\x09'inspectIt'.\x0a\x09\x09'Ctrl-Home' -> \x09\x09'goDocStart'. \x0a\x09\x09'Ctrl-Left' -> \x09\x09'goWordLeft'. \x0a\x09\x09'Ctrl-P' -> \x09\x09'printIt'.\x0a\x09\x09'Ctrl-Right' -> \x09'goWordRight'. \x0a\x09\x09'Ctrl-S' -> \x09\x09'saveIt'. \x0a\x09\x09'Ctrl-Y' -> \x09\x09'redo'.\x0a\x09\x09'Ctrl-Z' -> \x09\x09'undo'. \x0a\x09\x09'Ctrl-[' -> \x09\x09'indentLess'. \x0a\x09\x09'Ctrl-]' -> \x09\x09'indentMore'.\x0a\x09\x09'Shift-Ctrl-F' -> \x09'replace'. \x0a\x09\x09'Shift-Ctrl-G' -> \x09'findPrev'. \x0a\x09\x09'Shift-Ctrl-R' -> \x09'replaceAll'.\x0a\x09\x09'Shift-Ctrl-Z' -> \x09'redo'. \x0a\x09\x09'fallthrough' -> \x09#('basic')\x0a}",
+source: "pcKeyMap\x0a\x09^ #{\x0a\x09\x09'Alt-Left' -> \x09\x09'goLineStart'. \x0a\x09\x09'Alt-Right' -> \x09\x09'goLineEnd'.\x0a\x09\x09'Alt-Up' -> \x09\x09'goDocStart'. \x0a\x09\x09'Ctrl-A' -> \x09\x09'selectAll'. \x0a\x09\x09'Ctrl-Backspace' -> 'delWordBefore'. \x0a\x09\x09'Ctrl-D' -> \x09\x09'doIt'. \x0a\x09\x09'Ctrl-B' -> \x09\x09'browseIt'. \x0a\x09\x09'Ctrl-Delete' -> \x09\x09'delWordAfter'. \x0a\x09\x09'Ctrl-Down' -> \x09\x09'goDocEnd'.\x0a\x09\x09'Ctrl-End' -> \x09\x09'goDocEnd'. \x0a\x09\x09'Ctrl-F' -> \x09\x09'find'.\x0a\x09\x09'Ctrl-G' -> \x09\x09'findNext'. \x0a\x09\x09'Ctrl-I' -> \x09\x09'inspectIt'.\x0a\x09\x09'Ctrl-Home' -> \x09\x09'goDocStart'. \x0a\x09\x09'Ctrl-Left' -> \x09\x09'goWordLeft'. \x0a\x09\x09'Ctrl-P' -> \x09\x09'printIt'.\x0a\x09\x09'Ctrl-Right' -> \x09'goWordRight'. \x0a\x09\x09'Ctrl-S' -> \x09\x09'saveIt'. \x0a\x09\x09'Ctrl-Y' -> \x09\x09'redo'.\x0a\x09\x09'Ctrl-Z' -> \x09\x09'undo'. \x0a\x09\x09'Ctrl-[' -> \x09\x09'indentLess'. \x0a\x09\x09'Ctrl-]' -> \x09\x09'indentMore'.\x0a\x09\x09'Shift-Ctrl-F' -> \x09'replace'. \x0a\x09\x09'Shift-Ctrl-G' -> \x09'findPrev'. \x0a\x09\x09'Shift-Ctrl-R' -> \x09'replaceAll'.\x0a\x09\x09'Shift-Ctrl-Z' -> \x09'redo'. \x0a\x09\x09'fallthrough' -> \x09#('basic')\x0a}",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1176,7 +1288,7 @@ fn: function (){
 var self=this;
 function $CodeMirror(){return globals.CodeMirror||(typeof CodeMirror=="undefined"?nil:CodeMirror)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5;
+var $1,$2,$3,$4,$5,$6;
 $1=_st($CodeMirror())._basicAt_("commands");
 _st($1)._at_put_("doIt",(function(cm){
 return smalltalk.withContext(function($ctx2) {
@@ -1199,14 +1311,21 @@ $ctx2.sendIdx["amberCodeWidget"]=3;
 return _st($4)._printIt();
 }, function($ctx2) {$ctx2.fillBlock({cm:cm},$ctx1,3)})}));
 $ctx1.sendIdx["at:put:"]=3;
-$5=_st($1)._at_put_("saveIt",(function(cm){
+_st($1)._at_put_("saveIt",(function(cm){
 return smalltalk.withContext(function($ctx2) {
-return _st(_st(cm)._amberCodeWidget())._saveIt();
+$5=_st(cm)._amberCodeWidget();
+$ctx2.sendIdx["amberCodeWidget"]=4;
+return _st($5)._saveIt();
 }, function($ctx2) {$ctx2.fillBlock({cm:cm},$ctx1,4)})}));
+$ctx1.sendIdx["at:put:"]=4;
+$6=_st($1)._at_put_("browseIt",(function(cm){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(cm)._amberCodeWidget())._browseIt();
+}, function($ctx2) {$ctx2.fillBlock({cm:cm},$ctx1,5)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"setupCommands",{},globals.HLCodeWidget.klass)})},
 args: [],
-source: "setupCommands\x0a\x09(CodeMirror basicAt: 'commands') \x0a\x09\x09at: 'doIt' put: [ :cm | cm amberCodeWidget doIt ];\x0a\x09\x09at: 'inspectIt' put: [ :cm | cm amberCodeWidget inspectIt ];\x0a\x09\x09at: 'printIt' put: [ :cm | cm amberCodeWidget printIt ];\x0a\x09\x09at: 'saveIt' put: [ :cm | cm amberCodeWidget saveIt ]",
-messageSends: ["at:put:", "basicAt:", "doIt", "amberCodeWidget", "inspectIt", "printIt", "saveIt"],
+source: "setupCommands\x0a\x09(CodeMirror basicAt: 'commands') \x0a\x09\x09at: 'doIt' put: [ :cm | cm amberCodeWidget doIt ];\x0a\x09\x09at: 'inspectIt' put: [ :cm | cm amberCodeWidget inspectIt ];\x0a\x09\x09at: 'printIt' put: [ :cm | cm amberCodeWidget printIt ];\x0a\x09\x09at: 'saveIt' put: [ :cm | cm amberCodeWidget saveIt ];\x0a\x09\x09at: 'browseIt' put: [ :cm | cm amberCodeWidget browseIt ]",
+messageSends: ["at:put:", "basicAt:", "doIt", "amberCodeWidget", "inspectIt", "printIt", "saveIt", "browseIt"],
 referencedClasses: ["CodeMirror"]
 }),
 globals.HLCodeWidget.klass);

+ 66 - 17
js/Helios-Workspace.st → src/Helios-Workspace.st

@@ -27,9 +27,24 @@ receiver: anObject
 
 !HLCodeModel methodsFor: 'actions'!
 
+browse: anObject
+	anObject browse
+!
+
 doIt: aString
+	"Evaluate aString in the receiver's `environment`.
+	
+	Note: Catch any error and handle it manually, bypassing
+	boot.js behavior to avoid the browser default action on
+	ctrl+d/ctrl+p.
+	
+	See https://github.com/amber-smalltalk/amber/issues/882"
 
-	^ self environment eval: aString on: self receiver
+	^ self 
+		try: [ self environment eval: aString on: self receiver ]
+		catch: [ :e | 
+			ErrorHandler handleError: e.
+			nil ]
 !
 
 inspect: anObject
@@ -133,20 +148,37 @@ selectionStart: anInteger
 
 !HLCodeWidget methodsFor: 'actions'!
 
+browseIt
+	| result |
+	
+	result := [ self doIt ] on: Error do: [ :exception | 
+		^ ErrorHandler handleError: exception ].
+		
+	self model browse: result
+!
+
 clear
 	self contents: ''
 !
 
 configureEditor
 	self editor at: 'amberCodeWidget' put: self.
-	self editor on: 'change' do: [ self onChange ]
+	self editor on: 'change' do: [ self onChange ].
+
+	self wrapper asJQuery on: 'mousedown' in: '.CodeMirror pre' do: [ :event | | position node |
+		(event at: 'ctrlKey') ifTrue: [
+			position := self editor coordsChar: #{ 
+				'left' -> event clientX.
+				'top' -> event clientY
+			}.
+			self onCtrlClickAt: (position line @ position ch) + 1.
+			event preventDefault ] ]
 !
 
 doIt
 	| result |
 
-	self model announcer announce: (HLDoItRequested on: model).
-	result := model doIt: self currentLineOrSelection.
+	result := self model doIt: self currentLineOrSelection.
 	self model announcer announce: (HLDoItExecuted on: model).
 
 	^ result
@@ -161,12 +193,18 @@ focus
 !
 
 inspectIt
-	| newInspector |
-       
-	self model announcer announce: (HLInspectItRequested on: model).
 	self model inspect: self doIt
 !
 
+navigateTo: aString
+	Finder findString: aString
+!
+
+navigateToReference: aString
+	(HLReferences openAsTab)
+		search: aString
+!
+
 print: aString
 	| start stop currentLine |
     currentLine := (editor getCursor: false) line.
@@ -188,12 +226,7 @@ print: aString
 !
 
 printIt
-	| result |
-
-	result := self doIt.       
-	self model announcer announce: (HLPrintItRequested on: model).
-	self print: result printString.
-	
+	self print: self doIt printString.
 	self focus.
 !
 
@@ -233,9 +266,18 @@ onChange
 	self updateState
 !
 
-onDoIt
+onCtrlClickAt: aPoint
+	| ast node |
+	
+	ast := [ Smalltalk parse: self editor getValue ] 
+		on: Error 
+		do: [ :error | ^ self ].
 	
-	self doIt
+	node := ast 
+		navigationNodeAt: aPoint 
+		ifAbsent: [ ^ nil ].
+		
+	self navigateTo: node navigationLink
 !
 
 onInspectIt
@@ -266,7 +308,11 @@ renderButtonsOn: html
 	html button 
 		class: 'button';
 		with: 'InspectIt';
-		onClick: [ self inspectIt ]
+		onClick: [ self inspectIt ].
+	html button 
+		class: 'button';
+		with: 'BrowseIt';
+		onClick: [ self browseIt ]
 !
 
 renderContentOn: html
@@ -323,6 +369,7 @@ macKeyMap
 		'Cmd-A'					-> 'selectAll'. 
 		'Cmd-Alt-F'				-> 'replace'. 
 		'Cmd-D'					-> 'doIt'. 
+		'Cmd-B'					-> 'browseIt'. 
 		'Cmd-Down'				-> 'goDocEnd'. 
 		'Cmd-End'				-> 'goDocEnd'. 
 		'Cmd-F'					-> 'find'.
@@ -353,6 +400,7 @@ pcKeyMap
 		'Ctrl-A' -> 		'selectAll'. 
 		'Ctrl-Backspace' -> 'delWordBefore'. 
 		'Ctrl-D' -> 		'doIt'. 
+		'Ctrl-B' -> 		'browseIt'. 
 		'Ctrl-Delete' -> 		'delWordAfter'. 
 		'Ctrl-Down' -> 		'goDocEnd'.
 		'Ctrl-End' -> 		'goDocEnd'. 
@@ -431,7 +479,8 @@ setupCommands
 		at: 'doIt' put: [ :cm | cm amberCodeWidget doIt ];
 		at: 'inspectIt' put: [ :cm | cm amberCodeWidget inspectIt ];
 		at: 'printIt' put: [ :cm | cm amberCodeWidget printIt ];
-		at: 'saveIt' put: [ :cm | cm amberCodeWidget saveIt ]
+		at: 'saveIt' put: [ :cm | cm amberCodeWidget saveIt ];
+		at: 'browseIt' put: [ :cm | cm amberCodeWidget browseIt ]
 !
 
 setupKeyMaps

+ 1 - 1
js/IDE.js → src/IDE.js

@@ -1,4 +1,4 @@
-define("amber_core/IDE", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Canvas", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections", "amber_core/Kernel-Methods"], function(smalltalk,nil,_st, globals){
+define("amber_core/IDE", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Web", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections", "amber_core/Kernel-Methods"], function(smalltalk,nil,_st, globals){
 smalltalk.addPackage('IDE');
 smalltalk.packages["IDE"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 0 - 0
js/IDE.st → src/IDE.st


+ 142 - 10
js/Kernel-Announcements.js → src/Kernel-Announcements.js

@@ -175,6 +175,110 @@ globals.AnnouncementSubscription);
 
 
 
+smalltalk.addClass('AnnouncementValuable', globals.Object, ['valuable', 'receiver'], 'Kernel-Announcements');
+globals.AnnouncementValuable.comment="I wrap `valuable` objects (typically instances of `BlockClosure`) with a `receiver` to be able to unregister subscriptions based on a `receiver`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "receiver",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@receiver"];
+return $1;
+},
+args: [],
+source: "receiver\x0a\x09^ receiver",
+messageSends: [],
+referencedClasses: []
+}),
+globals.AnnouncementValuable);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "receiver:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@receiver"]=anObject;
+return self},
+args: ["anObject"],
+source: "receiver: anObject\x0a\x09receiver := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.AnnouncementValuable);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "valuable",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@valuable"];
+return $1;
+},
+args: [],
+source: "valuable\x0a\x09^ valuable",
+messageSends: [],
+referencedClasses: []
+}),
+globals.AnnouncementValuable);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "valuable:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@valuable"]=anObject;
+return self},
+args: ["anObject"],
+source: "valuable: anObject\x0a\x09valuable := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.AnnouncementValuable);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value",
+protocol: 'evaluating',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._valuable())._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value",{},globals.AnnouncementValuable)})},
+args: [],
+source: "value\x0a\x09^ self valuable value",
+messageSends: ["value", "valuable"],
+referencedClasses: []
+}),
+globals.AnnouncementValuable);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value:",
+protocol: 'evaluating',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._valuable())._value_(anObject);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value:",{anObject:anObject},globals.AnnouncementValuable)})},
+args: ["anObject"],
+source: "value: anObject\x0a\x09^ self valuable value: anObject",
+messageSends: ["value:", "valuable"],
+referencedClasses: []
+}),
+globals.AnnouncementValuable);
+
+
+
 smalltalk.addClass('Announcer', globals.Object, ['registry', 'subscriptions'], 'Kernel-Announcements');
 globals.Announcer.comment="I hold annoncement subscriptions (instances of `AnnouncementSubscription`) in a private registry.\x0aI announce (trigger) announces, which are then dispatched to all subscriptions.\x0a\x0aThe code is based on the announcements as [described by Vassili Bykov](http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?searchCategory=Announcements%20Framework).\x0a\x0a## API\x0a\x0aUse `#announce:` to trigger an announcement.\x0a\x0aUse `#on:do:` or `#on:send:to:` to register subscriptions.\x0a\x0aWhen using `#on:send:to:`, unregistration can be done with `#unregister:`.\x0a\x0a## Usage example:\x0a\x0a    SystemAnnouncer current\x0a        on: ClassAdded\x0a        do: [ :ann | window alert: ann theClass name, ' added' ].";
 smalltalk.addMethod(
@@ -220,19 +324,47 @@ selector: "on:do:",
 protocol: 'subscribing',
 fn: function (aClass,aBlock){
 var self=this;
-function $AnnouncementSubscription(){return globals.AnnouncementSubscription||(typeof AnnouncementSubscription=="undefined"?nil:AnnouncementSubscription)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=_st($AnnouncementSubscription())._new();
-_st($1)._valuable_(aBlock);
-_st($1)._announcementClass_(aClass);
-$2=_st($1)._yourself();
-_st(self["@subscriptions"])._add_($2);
+self._on_do_for_(aClass,aBlock,nil);
 return self}, function($ctx1) {$ctx1.fill(self,"on:do:",{aClass:aClass,aBlock:aBlock},globals.Announcer)})},
 args: ["aClass", "aBlock"],
-source: "on: aClass do: aBlock\x0a\x09subscriptions add: (AnnouncementSubscription new\x0a\x09\x09valuable: aBlock;\x0a\x09\x09announcementClass: aClass;\x0a\x09\x09yourself)",
-messageSends: ["add:", "valuable:", "new", "announcementClass:", "yourself"],
-referencedClasses: ["AnnouncementSubscription"]
+source: "on: aClass do: aBlock\x0a\x09self on: aClass do: aBlock for: nil",
+messageSends: ["on:do:for:"],
+referencedClasses: []
+}),
+globals.Announcer);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "on:do:for:",
+protocol: 'subscribing',
+fn: function (aClass,aBlock,aReceiver){
+var self=this;
+function $AnnouncementSubscription(){return globals.AnnouncementSubscription||(typeof AnnouncementSubscription=="undefined"?nil:AnnouncementSubscription)}
+function $AnnouncementValuable(){return globals.AnnouncementValuable||(typeof AnnouncementValuable=="undefined"?nil:AnnouncementValuable)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$4,$6,$7,$5,$8,$2;
+$1=self["@subscriptions"];
+$3=_st($AnnouncementSubscription())._new();
+$ctx1.sendIdx["new"]=1;
+$4=$3;
+$6=_st($AnnouncementValuable())._new();
+_st($6)._valuable_(aBlock);
+_st($6)._receiver_(aReceiver);
+$7=_st($6)._yourself();
+$ctx1.sendIdx["yourself"]=1;
+$5=$7;
+_st($4)._valuable_($5);
+$ctx1.sendIdx["valuable:"]=1;
+_st($3)._announcementClass_(aClass);
+$8=_st($3)._yourself();
+$2=$8;
+_st($1)._add_($2);
+return self}, function($ctx1) {$ctx1.fill(self,"on:do:for:",{aClass:aClass,aBlock:aBlock,aReceiver:aReceiver},globals.Announcer)})},
+args: ["aClass", "aBlock", "aReceiver"],
+source: "on: aClass do: aBlock for: aReceiver\x0a\x09subscriptions add: (AnnouncementSubscription new\x0a\x09\x09valuable: (AnnouncementValuable new\x0a\x09\x09\x09valuable: aBlock;\x0a\x09\x09\x09receiver: aReceiver;\x0a\x09\x09\x09yourself);\x0a\x09\x09announcementClass: aClass;\x0a\x09\x09yourself)",
+messageSends: ["add:", "valuable:", "new", "receiver:", "yourself", "announcementClass:"],
+referencedClasses: ["AnnouncementSubscription", "AnnouncementValuable"]
 }),
 globals.Announcer);
 

+ 42 - 1
js/Kernel-Announcements.st → src/Kernel-Announcements.st

@@ -58,6 +58,40 @@ handlesAnnouncement: anAnnouncement
 		(Smalltalk globals at: anAnnouncement class theNonMetaClass name) includesBehavior: class ]
 ! !
 
+Object subclass: #AnnouncementValuable
+	instanceVariableNames: 'valuable receiver'
+	package: 'Kernel-Announcements'!
+!AnnouncementValuable commentStamp!
+I wrap `valuable` objects (typically instances of `BlockClosure`) with a `receiver` to be able to unregister subscriptions based on a `receiver`.!
+
+!AnnouncementValuable methodsFor: 'accessing'!
+
+receiver
+	^ receiver
+!
+
+receiver: anObject
+	receiver := anObject
+!
+
+valuable
+	^ valuable
+!
+
+valuable: anObject
+	valuable := anObject
+! !
+
+!AnnouncementValuable methodsFor: 'evaluating'!
+
+value
+	^ self valuable value
+!
+
+value: anObject
+	^ self valuable value: anObject
+! !
+
 Object subclass: #Announcer
 	instanceVariableNames: 'registry subscriptions'
 	package: 'Kernel-Announcements'!
@@ -98,8 +132,15 @@ initialize
 !Announcer methodsFor: 'subscribing'!
 
 on: aClass do: aBlock
+	self on: aClass do: aBlock for: nil
+!
+
+on: aClass do: aBlock for: aReceiver
 	subscriptions add: (AnnouncementSubscription new
-		valuable: aBlock;
+		valuable: (AnnouncementValuable new
+			valuable: aBlock;
+			receiver: aReceiver;
+			yourself);
 		announcementClass: aClass;
 		yourself)
 !

+ 17 - 0
js/Kernel-Classes.js → src/Kernel-Classes.js

@@ -1124,6 +1124,23 @@ referencedClasses: []
 }),
 globals.Class);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "browse",
+protocol: 'browsing',
+fn: function (){
+var self=this;
+function $Finder(){return globals.Finder||(typeof Finder=="undefined"?nil:Finder)}
+return smalltalk.withContext(function($ctx1) { 
+_st($Finder())._findClass_(self);
+return self}, function($ctx1) {$ctx1.fill(self,"browse",{},globals.Class)})},
+args: [],
+source: "browse\x0a\x09Finder findClass: self",
+messageSends: ["findClass:"],
+referencedClasses: ["Finder"]
+}),
+globals.Class);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "category",

+ 6 - 0
js/Kernel-Classes.st → src/Kernel-Classes.st

@@ -412,6 +412,12 @@ subclasses
 	<return self.subclasses._copy()>
 ! !
 
+!Class methodsFor: 'browsing'!
+
+browse
+	Finder findClass: self
+! !
+
 !Class methodsFor: 'class creation'!
 
 subclass: aString instanceVariableNames: anotherString

+ 1 - 1
js/Kernel-Collections.js → src/Kernel-Collections.js

@@ -5437,7 +5437,7 @@ globals.String.klass);
 
 
 smalltalk.addClass('Set', globals.Collection, ['defaultBucket', 'slowBucketStores', 'fastBuckets', 'size'], 'Kernel-Collections');
-globals.Set.comment="I represent an unordered set of objects without duplicates.\x0a\x0a## Implementation notes\x0a\x0aI put elements into different stores based on their type.\x0aThe goal is to store some elements into native JS object property names to be fast.\x0a\x0aIf an unboxed element has typeof 'string', 'boolean' or 'number', or an element is nil, null or undefined,\x0aI store it as a property name in an empty (== Object.create(null)) JS object, different for each type\x0a(for simplicity, nil/null/undefined is treated as one and included with the two booleans).\x0a\x0aIf element happen to be an object, I try to store them in `ArrayBucketStore`. I have two of them by default,\x0aone hashed using the Smalltalk class name, the other one using the JS constructor name. It is possible to have more or less\x0ainstances of `ArrayBucketStores`, see `#initializeSlowBucketStores`.\x0a\x0aAs a last resort, if none of the `ArrayBucketStore` instances can find a suitable bucket, the `defaultBucket` is used,\x0awhich is an `Array`.\x0a";
+globals.Set.comment="I represent an unordered set of objects without duplicates.\x0a\x0a## Implementation notes\x0a\x0aI put elements into different stores based on their type.\x0aThe goal is to store some elements into native JS object property names to be fast.\x0a\x0aIf an unboxed element has typeof 'string', 'boolean' or 'number', or an element is nil, null or undefined,\x0aI store it as a property name in an empty (== Object.create(null)) JS object, different for each type\x0a(for simplicity, nil/null/undefined is treated as one and included with the two booleans).\x0a\x0aIf element happen to be an object, I try to store them in `ArrayBucketStore`. I have two of them by default,\x0aone hashed using the Smalltalk class name, the other one using the JS constructor name. It is possible to have more or less\x0ainstances of `ArrayBucketStores`, see `#initializeSlowBucketStores`.\x0a\x0aAs a last resort, if none of the `ArrayBucketStore` instances can find a suitable bucket, the `defaultBucket` is used,\x0awhich is an `Array`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "=",

+ 0 - 0
js/Kernel-Collections.st → src/Kernel-Collections.st


+ 4 - 0
js/Kernel-Exceptions.js → src/Kernel-Exceptions.js

@@ -435,4 +435,8 @@ referencedClasses: []
 globals.NonBooleanReceiver);
 
 
+
+smalltalk.addClass('PackageCommitError', globals.Error, [], 'Kernel-Exceptions');
+globals.PackageCommitError.comment="I get signaled when an attempt to commit a package has failed.";
+
 });

+ 6 - 0
js/Kernel-Exceptions.st → src/Kernel-Exceptions.st

@@ -161,3 +161,9 @@ object: anObject
 	object := anObject
 ! !
 
+Error subclass: #PackageCommitError
+	instanceVariableNames: ''
+	package: 'Kernel-Exceptions'!
+!PackageCommitError commentStamp!
+I get signaled when an attempt to commit a package has failed.!
+

+ 93 - 42
js/Kernel-ImportExport.js → src/Kernel-ImportExport.js

@@ -1426,26 +1426,16 @@ smalltalk.addClass('PackageHandler', globals.InterfacingObject, [], 'Kernel-Impo
 globals.PackageHandler.comment="I am responsible for handling package loading and committing.\x0a\x0aI should not be used directly. Instead, use the corresponding `Package` methods.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "ajaxPutAt:data:",
+selector: "ajaxPutAt:data:onSuccess:onError:",
 protocol: 'private',
-fn: function (aURL,aString){
+fn: function (aURL,aString,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1;
-self._ajax_(globals.HashedCollection._newFromPairs_(["url",aURL,"type","PUT","data",aString,"contentType","text/plain;charset=UTF-8","error",(function(xhr){
-return smalltalk.withContext(function($ctx2) {
-$3=_st("Commiting ".__comma(aURL)).__comma(" failed with reason: \x22");
-$ctx2.sendIdx[","]=3;
-$2=_st($3).__comma(_st(xhr)._responseText());
-$ctx2.sendIdx[","]=2;
-$1=_st($2).__comma("\x22");
-$ctx2.sendIdx[","]=1;
-return self._alert_($1);
-}, function($ctx2) {$ctx2.fillBlock({xhr:xhr},$ctx1,1)})})]));
-return self}, function($ctx1) {$ctx1.fill(self,"ajaxPutAt:data:",{aURL:aURL,aString:aString},globals.PackageHandler)})},
-args: ["aURL", "aString"],
-source: "ajaxPutAt: aURL data: aString\x0a\x09self\x0a\x09\x09ajax: #{\x0a\x09\x09\x09'url' -> aURL.\x0a\x09\x09\x09'type' -> 'PUT'.\x0a\x09\x09\x09'data' -> aString.\x0a\x09\x09\x09'contentType' -> 'text/plain;charset=UTF-8'.\x0a\x09\x09\x09'error' -> [ :xhr | self alert: 'Commiting ' , aURL , ' failed with reason: \x22' , (xhr responseText) , '\x22' ] }",
-messageSends: ["ajax:", "alert:", ",", "responseText"],
+self._ajax_(globals.HashedCollection._newFromPairs_(["url",aURL,"type","PUT","data",aString,"contentType","text/plain;charset=UTF-8","success",aBlock,"error",anotherBlock]));
+return self}, function($ctx1) {$ctx1.fill(self,"ajaxPutAt:data:onSuccess:onError:",{aURL:aURL,aString:aString,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aURL", "aString", "aBlock", "anotherBlock"],
+source: "ajaxPutAt: aURL data: aString onSuccess: aBlock onError: anotherBlock\x0a\x09self\x0a\x09\x09ajax: #{\x0a\x09\x09\x09'url' -> aURL.\x0a\x09\x09\x09'type' -> 'PUT'.\x0a\x09\x09\x09'data' -> aString.\x0a\x09\x09\x09'contentType' -> 'text/plain;charset=UTF-8'.\x0a\x09\x09\x09'success' -> aBlock.\x0a\x09\x09\x09'error' -> anotherBlock\x0a\x09\x09}",
+messageSends: ["ajax:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1512,30 +1502,52 @@ selector: "commit:",
 protocol: 'committing',
 fn: function (aPackage){
 var self=this;
+function $PackageCommitError(){return globals.PackageCommitError||(typeof PackageCommitError=="undefined"?nil:PackageCommitError)}
 return smalltalk.withContext(function($ctx1) { 
-_st([(function(){
-return smalltalk.withContext(function($ctx2) {
-return self._commitStFileFor_(aPackage);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
-return self._commitJsFileFor_(aPackage);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})})])._do_displayingProgress_((function(each){
+var $1,$2,$3,$4;
+self._commit_onSuccess_onError_(aPackage,(function(){
+}),(function(error){
 return smalltalk.withContext(function($ctx2) {
-return _st(each)._value();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,3)})}),"Committing package ".__comma(_st(aPackage)._name()));
+$1=_st($PackageCommitError())._new();
+$2=$1;
+$3=_st("Commiting failed with reason: \x22".__comma(_st(error)._responseText())).__comma("\x22");
+$ctx2.sendIdx[","]=1;
+_st($2)._messageText_($3);
+$4=_st($1)._signal();
+return $4;
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"commit:",{aPackage:aPackage},globals.PackageHandler)})},
 args: ["aPackage"],
-source: "commit: aPackage\x0a\x09{\x0a\x09\x09[ self commitStFileFor: aPackage ].\x0a\x09\x09[ self commitJsFileFor: aPackage ]\x0a\x09}\x0a\x09\x09do: [ :each | each value ]\x0a\x09\x09displayingProgress: 'Committing package ', aPackage name",
-messageSends: ["do:displayingProgress:", "commitStFileFor:", "commitJsFileFor:", "value", ",", "name"],
+source: "commit: aPackage\x0a\x09self \x0a\x09\x09commit: aPackage\x0a\x09\x09onSuccess: []\x0a\x09\x09onError: [ :error |\x0a\x09\x09\x09PackageCommitError new\x0a\x09\x09\x09\x09messageText: 'Commiting failed with reason: \x22' , (error responseText) , '\x22';\x0a\x09\x09\x09\x09signal ]",
+messageSends: ["commit:onSuccess:onError:", "messageText:", "new", ",", "responseText", "signal"],
+referencedClasses: ["PackageCommitError"]
+}),
+globals.PackageHandler);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commit:onSuccess:onError:",
+protocol: 'committing',
+fn: function (aPackage,aBlock,anotherBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._commitJsFileFor_onSuccess_onError_(aPackage,(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._commitStFileFor_onSuccess_onError_(aPackage,aBlock,anotherBlock);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commit:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commit: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09self \x0a\x09\x09commitJsFileFor: aPackage \x0a\x09\x09onSuccess: [\x0a\x09\x09\x09self \x0a\x09\x09\x09commitStFileFor: aPackage \x0a\x09\x09\x09onSuccess: aBlock\x0a\x09\x09\x09onError: anotherBlock ] \x0a\x09\x09onError: anotherBlock",
+messageSends: ["commitJsFileFor:onSuccess:onError:", "commitStFileFor:onSuccess:onError:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitJsFileFor:",
+selector: "commitJsFileFor:onSuccess:onError:",
 protocol: 'committing',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
@@ -1543,11 +1555,11 @@ $2=_st(_st(self._commitPathJsFor_(aPackage)).__comma("/")).__comma(_st(aPackage)
 $ctx1.sendIdx[","]=2;
 $1=_st($2).__comma(".js");
 $ctx1.sendIdx[","]=1;
-self._ajaxPutAt_data_($1,self._contentsFor_(aPackage));
-return self}, function($ctx1) {$ctx1.fill(self,"commitJsFileFor:",{aPackage:aPackage},globals.PackageHandler)})},
-args: ["aPackage"],
-source: "commitJsFileFor: aPackage\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js'\x0a\x09\x09data: (self contentsFor: aPackage)",
-messageSends: ["ajaxPutAt:data:", ",", "commitPathJsFor:", "name", "contentsFor:"],
+self._ajaxPutAt_data_onSuccess_onError_($1,self._contentsFor_(aPackage),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitJsFileFor:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commitJsFileFor: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js'\x0a\x09\x09data: (self contentsFor: aPackage)\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["ajaxPutAt:data:onSuccess:onError:", ",", "commitPathJsFor:", "name", "contentsFor:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1586,9 +1598,9 @@ globals.PackageHandler);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitStFileFor:",
+selector: "commitStFileFor:onSuccess:onError:",
 protocol: 'committing',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
@@ -1596,11 +1608,11 @@ $2=_st(_st(self._commitPathStFor_(aPackage)).__comma("/")).__comma(_st(aPackage)
 $ctx1.sendIdx[","]=2;
 $1=_st($2).__comma(".st");
 $ctx1.sendIdx[","]=1;
-self._ajaxPutAt_data_($1,self._chunkContentsFor_(aPackage));
-return self}, function($ctx1) {$ctx1.fill(self,"commitStFileFor:",{aPackage:aPackage},globals.PackageHandler)})},
-args: ["aPackage"],
-source: "commitStFileFor: aPackage\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st'\x0a\x09\x09data: (self chunkContentsFor: aPackage)",
-messageSends: ["ajaxPutAt:data:", ",", "commitPathStFor:", "name", "chunkContentsFor:"],
+self._ajaxPutAt_data_onSuccess_onError_($1,self._chunkContentsFor_(aPackage),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitStFileFor:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commitStFileFor: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st'\x0a\x09\x09data: (self chunkContentsFor: aPackage)\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["ajaxPutAt:data:onSuccess:onError:", ",", "commitPathStFor:", "name", "chunkContentsFor:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1677,6 +1689,29 @@ referencedClasses: []
 }),
 globals.PackageHandler);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onCommitError:",
+protocol: 'error handling',
+fn: function (anError){
+var self=this;
+function $PackageCommitError(){return globals.PackageCommitError||(typeof PackageCommitError=="undefined"?nil:PackageCommitError)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4;
+$1=_st($PackageCommitError())._new();
+$2=$1;
+$3=_st("Commiting failed with reason: \x22".__comma(_st(anError)._responseText())).__comma("\x22");
+$ctx1.sendIdx[","]=1;
+_st($2)._messageText_($3);
+$4=_st($1)._signal();
+return self}, function($ctx1) {$ctx1.fill(self,"onCommitError:",{anError:anError},globals.PackageHandler)})},
+args: ["anError"],
+source: "onCommitError: anError\x0a\x09PackageCommitError new\x0a\x09\x09messageText: 'Commiting failed with reason: \x22' , (anError responseText) , '\x22';\x0a\x09\x09signal",
+messageSends: ["messageText:", "new", ",", "responseText", "signal"],
+referencedClasses: ["PackageCommitError"]
+}),
+globals.PackageHandler);
+
 
 
 smalltalk.addClass('AmdPackageHandler', globals.PackageHandler, [], 'Kernel-ImportExport');
@@ -1924,6 +1959,22 @@ referencedClasses: []
 }),
 globals.PackageTransport);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitOnSuccess:onError:",
+protocol: 'committing',
+fn: function (aBlock,anotherBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._commitHandler())._commit_onSuccess_onError_(self._package(),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitOnSuccess:onError:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageTransport)})},
+args: ["aBlock", "anotherBlock"],
+source: "commitOnSuccess: aBlock onError: anotherBlock\x0a\x09self commitHandler \x0a\x09\x09commit: self package\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["commit:onSuccess:onError:", "commitHandler", "package"],
+referencedClasses: []
+}),
+globals.PackageTransport);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "definition",

+ 43 - 10
js/Kernel-ImportExport.st → src/Kernel-ImportExport.st

@@ -582,24 +582,48 @@ exporterClass
 !PackageHandler methodsFor: 'committing'!
 
 commit: aPackage
-	{
-		[ self commitStFileFor: aPackage ].
-		[ self commitJsFileFor: aPackage ]
-	}
-		do: [ :each | each value ]
-		displayingProgress: 'Committing package ', aPackage name
+	self 
+		commit: aPackage
+		onSuccess: []
+		onError: [ :error |
+			PackageCommitError new
+				messageText: 'Commiting failed with reason: "' , (error responseText) , '"';
+				signal ]
 !
 
-commitJsFileFor: aPackage
+commit: aPackage onSuccess: aBlock onError: anotherBlock
+	self 
+		commitJsFileFor: aPackage 
+		onSuccess: [
+			self 
+			commitStFileFor: aPackage 
+			onSuccess: aBlock
+			onError: anotherBlock ] 
+		onError: anotherBlock
+!
+
+commitJsFileFor: aPackage onSuccess: aBlock onError: anotherBlock
 	self 
 		ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js'
 		data: (self contentsFor: aPackage)
+		onSuccess: aBlock
+		onError: anotherBlock
 !
 
-commitStFileFor: aPackage
+commitStFileFor: aPackage onSuccess: aBlock onError: anotherBlock
 	self 
 		ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st'
 		data: (self chunkContentsFor: aPackage)
+		onSuccess: aBlock
+		onError: anotherBlock
+! !
+
+!PackageHandler methodsFor: 'error handling'!
+
+onCommitError: anError
+	PackageCommitError new
+		messageText: 'Commiting failed with reason: "' , (anError responseText) , '"';
+		signal
 ! !
 
 !PackageHandler methodsFor: 'factory'!
@@ -620,14 +644,16 @@ load: aPackage
 
 !PackageHandler methodsFor: 'private'!
 
-ajaxPutAt: aURL data: aString
+ajaxPutAt: aURL data: aString onSuccess: aBlock onError: anotherBlock
 	self
 		ajax: #{
 			'url' -> aURL.
 			'type' -> 'PUT'.
 			'data' -> aString.
 			'contentType' -> 'text/plain;charset=UTF-8'.
-			'error' -> [ :xhr | self alert: 'Commiting ' , aURL , ' failed with reason: "' , (xhr responseText) , '"' ] }
+			'success' -> aBlock.
+			'error' -> anotherBlock
+		}
 ! !
 
 PackageHandler subclass: #AmdPackageHandler
@@ -725,6 +751,13 @@ type
 
 commit
 	self commitHandler commit: self package
+!
+
+commitOnSuccess: aBlock onError: anotherBlock
+	self commitHandler 
+		commit: self package
+		onSuccess: aBlock
+		onError: anotherBlock
 ! !
 
 !PackageTransport methodsFor: 'converting'!

+ 83 - 8
js/Kernel-Infrastructure.js → src/Kernel-Infrastructure.js

@@ -391,16 +391,16 @@ globals.Environment);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitPackage:",
+selector: "commitPackage:onSuccess:onError:",
 protocol: 'actions',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(aPackage)._commit();
-return self}, function($ctx1) {$ctx1.fill(self,"commitPackage:",{aPackage:aPackage},globals.Environment)})},
-args: ["aPackage"],
-source: "commitPackage: aPackage\x0a\x09aPackage commit",
-messageSends: ["commit"],
+_st(_st(aPackage)._transport())._commitOnSuccess_onError_(aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackage:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.Environment)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commitPackage: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09aPackage transport\x0a\x09\x09commitOnSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["commitOnSuccess:onError:", "transport"],
 referencedClasses: []
 }),
 globals.Environment);
@@ -731,6 +731,23 @@ referencedClasses: ["ErrorHandler"]
 }),
 globals.Environment);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "registerFinder:",
+protocol: 'services',
+fn: function (aFinder){
+var self=this;
+function $Finder(){return globals.Finder||(typeof Finder=="undefined"?nil:Finder)}
+return smalltalk.withContext(function($ctx1) { 
+_st($Finder())._register_(aFinder);
+return self}, function($ctx1) {$ctx1.fill(self,"registerFinder:",{aFinder:aFinder},globals.Environment)})},
+args: ["aFinder"],
+source: "registerFinder: aFinder\x0a\x09Finder register: aFinder",
+messageSends: ["register:"],
+referencedClasses: ["Finder"]
+}),
+globals.Environment);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "registerInspector:",
@@ -2209,6 +2226,64 @@ referencedClasses: []
 globals.ErrorHandler.klass);
 
 
+smalltalk.addClass('Finder', globals.Service, [], 'Kernel-Infrastructure');
+globals.Finder.comment="I am the service responsible for finding classes/methods.\x0a__There is no default finder.__\x0a\x0a## API\x0a\x0aUse `#browse` on an object to find it.";
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "findClass:",
+protocol: 'finding',
+fn: function (aClass){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._current())._findClass_(aClass);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"findClass:",{aClass:aClass},globals.Finder.klass)})},
+args: ["aClass"],
+source: "findClass: aClass\x0a\x09^ self current findClass: aClass",
+messageSends: ["findClass:", "current"],
+referencedClasses: []
+}),
+globals.Finder.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "findMethod:",
+protocol: 'finding',
+fn: function (aCompiledMethod){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._current())._findMethod_(aCompiledMethod);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"findMethod:",{aCompiledMethod:aCompiledMethod},globals.Finder.klass)})},
+args: ["aCompiledMethod"],
+source: "findMethod: aCompiledMethod\x0a\x09^ self current findMethod: aCompiledMethod",
+messageSends: ["findMethod:", "current"],
+referencedClasses: []
+}),
+globals.Finder.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "findString:",
+protocol: 'finding',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._current())._findString_(aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"findString:",{aString:aString},globals.Finder.klass)})},
+args: ["aString"],
+source: "findString: aString\x0a\x09^ self current findString: aString",
+messageSends: ["findString:", "current"],
+referencedClasses: []
+}),
+globals.Finder.klass);
+
+
 smalltalk.addClass('Inspector', globals.Service, [], 'Kernel-Infrastructure');
 globals.Inspector.comment="I am the service responsible for inspecting objects.\x0a\x0aThe default inspector object is the transcript.";
 
@@ -2484,7 +2559,7 @@ globals.Setting.klass);
 
 
 smalltalk.addClass('SmalltalkImage', globals.Object, [], 'Kernel-Infrastructure');
-globals.SmalltalkImage.comment="I represent the Smalltalk system, wrapping\x0aoperations of variable `smalltalk` declared in `js/boot.js`.\x0a\x0a## API\x0a\x0aI have only one instance, accessed with global variable `Smalltalk`.\x0a\x0aThe `smalltalk` object holds all class and packages defined in the system.\x0a\x0a## Classes\x0a\x0aClasses can be accessed using the following methods:\x0a\x0a- `#classes` answers the full list of Smalltalk classes in the system\x0a- `#at:` answers a specific class or `nil`\x0a\x0a## Packages\x0a\x0aPackages can be accessed using the following methods:\x0a\x0a- `#packages` answers the full list of packages\x0a- `#packageAt:` answers a specific package or `nil`\x0a\x0a## Parsing\x0a\x0aThe `#parse:` method is used to parse Amber source code.\x0aIt requires the `Compiler` package and the `js/parser.js` parser file in order to work.";
+globals.SmalltalkImage.comment="I represent the Smalltalk system, wrapping\x0aoperations of variable `smalltalk` declared in `support/boot.js`.\x0a\x0a## API\x0a\x0aI have only one instance, accessed with global variable `Smalltalk`.\x0a\x0aThe `smalltalk` object holds all class and packages defined in the system.\x0a\x0a## Classes\x0a\x0aClasses can be accessed using the following methods:\x0a\x0a- `#classes` answers the full list of Smalltalk classes in the system\x0a- `#at:` answers a specific class or `nil`\x0a\x0a## Packages\x0a\x0aPackages can be accessed using the following methods:\x0a\x0a- `#packages` answers the full list of packages\x0a- `#packageAt:` answers a specific package or `nil`\x0a\x0a## Parsing\x0a\x0aThe `#parse:` method is used to parse Amber source code.\x0aIt requires the `Compiler` package and the `support/parser.js` parser file in order to work.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "addGlobalJsVariable:",

+ 35 - 4
js/Kernel-Infrastructure.st → src/Kernel-Infrastructure.st

@@ -135,8 +135,10 @@ systemAnnouncer
 
 !Environment methodsFor: 'actions'!
 
-commitPackage: aPackage
-	aPackage commit
+commitPackage: aPackage onSuccess: aBlock onError: anotherBlock
+	aPackage transport
+		commitOnSuccess: aBlock
+		onError: anotherBlock
 !
 
 copyClass: aClass to: aClassName
@@ -273,6 +275,10 @@ registerErrorHandler: anErrorHandler
 	ErrorHandler register: anErrorHandler
 !
 
+registerFinder: aFinder
+	Finder register: aFinder
+!
+
 registerInspector: anInspector
 	Inspector register: anInspector
 !
@@ -840,6 +846,31 @@ handleError: anError
 	self current handleError: anError
 ! !
 
+Service subclass: #Finder
+	instanceVariableNames: ''
+	package: 'Kernel-Infrastructure'!
+!Finder commentStamp!
+I am the service responsible for finding classes/methods.
+__There is no default finder.__
+
+## API
+
+Use `#browse` on an object to find it.!
+
+!Finder class methodsFor: 'finding'!
+
+findClass: aClass
+	^ self current findClass: aClass
+!
+
+findMethod: aCompiledMethod
+	^ self current findMethod: aCompiledMethod
+!
+
+findString: aString
+	^ self current findString: aString
+! !
+
 Service subclass: #Inspector
 	instanceVariableNames: ''
 	package: 'Kernel-Infrastructure'!
@@ -965,7 +996,7 @@ Object subclass: #SmalltalkImage
 	package: 'Kernel-Infrastructure'!
 !SmalltalkImage commentStamp!
 I represent the Smalltalk system, wrapping
-operations of variable `smalltalk` declared in `js/boot.js`.
+operations of variable `smalltalk` declared in `support/boot.js`.
 
 ## API
 
@@ -990,7 +1021,7 @@ Packages can be accessed using the following methods:
 ## Parsing
 
 The `#parse:` method is used to parse Amber source code.
-It requires the `Compiler` package and the `js/parser.js` parser file in order to work.!
+It requires the `Compiler` package and the `support/parser.js` parser file in order to work.!
 
 !SmalltalkImage methodsFor: 'accessing'!
 

+ 17 - 0
js/Kernel-Methods.js → src/Kernel-Methods.js

@@ -481,6 +481,23 @@ referencedClasses: []
 }),
 globals.CompiledMethod);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "browse",
+protocol: 'browsing',
+fn: function (){
+var self=this;
+function $Finder(){return globals.Finder||(typeof Finder=="undefined"?nil:Finder)}
+return smalltalk.withContext(function($ctx1) { 
+_st($Finder())._findMethod_(self);
+return self}, function($ctx1) {$ctx1.fill(self,"browse",{},globals.CompiledMethod)})},
+args: [],
+source: "browse\x0a\x09Finder findMethod: self",
+messageSends: ["findMethod:"],
+referencedClasses: ["Finder"]
+}),
+globals.CompiledMethod);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "category",

+ 6 - 0
js/Kernel-Methods.st → src/Kernel-Methods.st

@@ -276,6 +276,12 @@ source: aString
 	self basicAt: 'source' put: aString
 ! !
 
+!CompiledMethod methodsFor: 'browsing'!
+
+browse
+	Finder findMethod: self
+! !
+
 !CompiledMethod methodsFor: 'defaults'!
 
 defaultProtocol

+ 152 - 2
js/Kernel-Objects.js → src/Kernel-Objects.js

@@ -3,7 +3,7 @@ smalltalk.addPackage('Kernel-Objects');
 smalltalk.packages["Kernel-Objects"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 smalltalk.addClass('ProtoObject', globals.nil, [], 'Kernel-Objects');
-globals.ProtoObject.comment="I implement the basic behavior required for any object in Amber.\x0a\x0aIn most cases, subclassing `ProtoObject` is wrong and `Object` should be used instead. However subclassing `ProtoObject` can be useful in some special cases like proxy implementations. ";
+globals.ProtoObject.comment="I implement the basic behavior required for any object in Amber.\x0a\x0aIn most cases, subclassing `ProtoObject` is wrong and `Object` should be used instead. However subclassing `ProtoObject` can be useful in some special cases like proxy implementations.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "=",
@@ -530,6 +530,23 @@ referencedClasses: []
 }),
 globals.Object);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "browse",
+protocol: 'browsing',
+fn: function (){
+var self=this;
+function $Finder(){return globals.Finder||(typeof Finder=="undefined"?nil:Finder)}
+return smalltalk.withContext(function($ctx1) { 
+_st($Finder())._findClass_(self._class());
+return self}, function($ctx1) {$ctx1.fill(self,"browse",{},globals.Object)})},
+args: [],
+source: "browse\x0a\x09Finder findClass: self class",
+messageSends: ["findClass:", "class"],
+referencedClasses: ["Finder"]
+}),
+globals.Object);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "copy",
@@ -3559,10 +3576,64 @@ referencedClasses: ["Point"]
 }),
 globals.Point);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "<",
+protocol: 'comparing',
+fn: function (aPoint){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$4,$1;
+$3=self._x();
+$ctx1.sendIdx["x"]=1;
+$2=_st($3).__lt(_st(aPoint)._x());
+$ctx1.sendIdx["<"]=1;
+$1=_st($2)._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+$4=self._y();
+$ctx2.sendIdx["y"]=1;
+return _st($4).__lt(_st(aPoint)._y());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"<",{aPoint:aPoint},globals.Point)})},
+args: ["aPoint"],
+source: "< aPoint\x0a\x09^ self x < aPoint x and: [\x0a\x09\x09self y < aPoint y ]",
+messageSends: ["and:", "<", "x", "y"],
+referencedClasses: []
+}),
+globals.Point);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "<=",
+protocol: 'comparing',
+fn: function (aPoint){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$4,$1;
+$3=self._x();
+$ctx1.sendIdx["x"]=1;
+$2=_st($3).__lt_eq(_st(aPoint)._x());
+$ctx1.sendIdx["<="]=1;
+$1=_st($2)._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+$4=self._y();
+$ctx2.sendIdx["y"]=1;
+return _st($4).__lt_eq(_st(aPoint)._y());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"<=",{aPoint:aPoint},globals.Point)})},
+args: ["aPoint"],
+source: "<= aPoint\x0a\x09^ self x <= aPoint x and: [\x0a\x09\x09self y <= aPoint y ]",
+messageSends: ["and:", "<=", "x", "y"],
+referencedClasses: []
+}),
+globals.Point);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "=",
-protocol: 'arithmetic',
+protocol: 'comparing',
 fn: function (aPoint){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3591,6 +3662,60 @@ referencedClasses: []
 }),
 globals.Point);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: ">",
+protocol: 'comparing',
+fn: function (aPoint){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$4,$1;
+$3=self._x();
+$ctx1.sendIdx["x"]=1;
+$2=_st($3).__gt(_st(aPoint)._x());
+$ctx1.sendIdx[">"]=1;
+$1=_st($2)._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+$4=self._y();
+$ctx2.sendIdx["y"]=1;
+return _st($4).__gt(_st(aPoint)._y());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,">",{aPoint:aPoint},globals.Point)})},
+args: ["aPoint"],
+source: "> aPoint\x0a\x09^ self x > aPoint x and: [\x0a\x09\x09self y > aPoint y ]",
+messageSends: ["and:", ">", "x", "y"],
+referencedClasses: []
+}),
+globals.Point);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: ">=",
+protocol: 'comparing',
+fn: function (aPoint){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$4,$1;
+$3=self._x();
+$ctx1.sendIdx["x"]=1;
+$2=_st($3).__gt_eq(_st(aPoint)._x());
+$ctx1.sendIdx[">="]=1;
+$1=_st($2)._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+$4=self._y();
+$ctx2.sendIdx["y"]=1;
+return _st($4).__gt_eq(_st(aPoint)._y());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,">=",{aPoint:aPoint},globals.Point)})},
+args: ["aPoint"],
+source: ">= aPoint\x0a\x09^ self x >= aPoint x and: [\x0a\x09\x09self y >= aPoint y ]",
+messageSends: ["and:", ">=", "x", "y"],
+referencedClasses: []
+}),
+globals.Point);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asPoint",
@@ -3606,6 +3731,31 @@ referencedClasses: []
 }),
 globals.Point);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "dist:",
+protocol: 'transforming',
+fn: function (aPoint){
+var self=this;
+var dx,dy;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$1;
+dx=_st(_st(aPoint)._x()).__minus(self["@x"]);
+$ctx1.sendIdx["-"]=1;
+dy=_st(_st(aPoint)._y()).__minus(self["@y"]);
+$3=_st(dx).__star(dx);
+$ctx1.sendIdx["*"]=1;
+$2=_st($3).__plus(_st(dy).__star(dy));
+$1=_st($2)._sqrt();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"dist:",{aPoint:aPoint,dx:dx,dy:dy},globals.Point)})},
+args: ["aPoint"],
+source: "dist: aPoint \x0a\x09\x22Answer the distance between aPoint and the receiver.\x22\x0a\x09| dx dy |\x0a\x09dx := aPoint x - x.\x0a\x09dy := aPoint y - y.\x0a\x09^ (dx * dx + (dy * dy)) sqrt",
+messageSends: ["-", "x", "y", "sqrt", "+", "*"],
+referencedClasses: []
+}),
+globals.Point);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "printOn:",

+ 36 - 0
js/Kernel-Objects.st → src/Kernel-Objects.st

@@ -182,6 +182,12 @@ value
 	<return self.valueOf()>
 ! !
 
+!Object methodsFor: 'browsing'!
+
+browse
+	Finder findClass: self class
+! !
+
 !Object methodsFor: 'converting'!
 
 -> anObject
@@ -1170,11 +1176,33 @@ y: aNumber
 
 / aPoint
 	^ Point x: self x / aPoint asPoint x y: self y / aPoint asPoint y
+! !
+
+!Point methodsFor: 'comparing'!
+
+< aPoint
+	^ self x < aPoint x and: [
+		self y < aPoint y ]
+!
+
+<= aPoint
+	^ self x <= aPoint x and: [
+		self y <= aPoint y ]
 !
 
 = aPoint
 	^ aPoint class = self class and: [
 		(aPoint x = self x) & (aPoint y = self y) ]
+!
+
+> aPoint
+	^ self x > aPoint x and: [
+		self y > aPoint y ]
+!
+
+>= aPoint
+	^ self x >= aPoint x and: [
+		self y >= aPoint y ]
 ! !
 
 !Point methodsFor: 'converting'!
@@ -1200,6 +1228,14 @@ printOn: aStream
 
 !Point methodsFor: 'transforming'!
 
+dist: aPoint 
+	"Answer the distance between aPoint and the receiver."
+	| dx dy |
+	dx := aPoint x - x.
+	dy := aPoint y - y.
+	^ (dx * dx + (dy * dy)) sqrt
+!
+
 translateBy: delta
 	"Answer a Point translated by delta (an instance of Point)."
 	^ (delta x + x) @ (delta y + y)

+ 118 - 2
js/Kernel-Tests.js → src/Kernel-Tests.js

@@ -44,7 +44,7 @@ smalltalk.addClass('AnnouncerTest', globals.TestCase, [], 'Kernel-Tests');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testOnDo",
-protocol: 'not yet classified',
+protocol: 'tests',
 fn: function (){
 var self=this;
 var counter,announcer;
@@ -77,10 +77,54 @@ referencedClasses: ["Announcer", "SystemAnnouncement"]
 }),
 globals.AnnouncerTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testOnDoFor",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var counter,announcer;
+function $Announcer(){return globals.Announcer||(typeof Announcer=="undefined"?nil:Announcer)}
+function $SystemAnnouncement(){return globals.SystemAnnouncement||(typeof SystemAnnouncement=="undefined"?nil:SystemAnnouncement)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4;
+counter=(0);
+announcer=_st($Announcer())._new();
+$ctx1.sendIdx["new"]=1;
+_st(announcer)._on_do_for_($SystemAnnouncement(),(function(){
+return smalltalk.withContext(function($ctx2) {
+counter=_st(counter).__plus((1));
+return counter;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),self);
+$1=announcer;
+$2=_st($SystemAnnouncement())._new();
+$ctx1.sendIdx["new"]=2;
+_st($1)._announce_($2);
+$ctx1.sendIdx["announce:"]=1;
+self._assert_equals_(counter,(1));
+$ctx1.sendIdx["assert:equals:"]=1;
+$3=announcer;
+$4=_st($SystemAnnouncement())._new();
+$ctx1.sendIdx["new"]=3;
+_st($3)._announce_($4);
+$ctx1.sendIdx["announce:"]=2;
+self._assert_equals_(counter,(2));
+$ctx1.sendIdx["assert:equals:"]=2;
+_st(announcer)._unsubscribe_(self);
+_st(announcer)._announce_(_st($SystemAnnouncement())._new());
+self._assert_equals_(counter,(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testOnDoFor",{counter:counter,announcer:announcer},globals.AnnouncerTest)})},
+args: [],
+source: "testOnDoFor\x0a\x09| counter announcer |\x0a\x09\x0a\x09counter := 0.\x0a\x09announcer := Announcer new.\x0a\x09announcer on: SystemAnnouncement do: [ counter := counter + 1 ] for: self.\x0a\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 1.\x0a\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 2.\x0a\x09\x0a\x09announcer unsubscribe: self.\x0a\x09\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 2.",
+messageSends: ["new", "on:do:for:", "+", "announce:", "assert:equals:", "unsubscribe:"],
+referencedClasses: ["Announcer", "SystemAnnouncement"]
+}),
+globals.AnnouncerTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testOnDoOnce",
-protocol: 'not yet classified',
+protocol: 'tests',
 fn: function (){
 var self=this;
 var counter,announcer;
@@ -8020,6 +8064,78 @@ referencedClasses: ["Point"]
 }),
 globals.PointTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testComparison",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1,$5,$6,$4,$8,$9,$7,$11,$12,$10,$14,$15,$13,$17,$18,$16,$20,$21,$19,$23,$22;
+$2=(3).__at((4));
+$ctx1.sendIdx["@"]=1;
+$3=(4).__at((5));
+$ctx1.sendIdx["@"]=2;
+$1=_st($2).__lt($3);
+$ctx1.sendIdx["<"]=1;
+self._assert_($1);
+$ctx1.sendIdx["assert:"]=1;
+$5=(3).__at((4));
+$ctx1.sendIdx["@"]=3;
+$6=(4).__at((4));
+$ctx1.sendIdx["@"]=4;
+$4=_st($5).__lt($6);
+self._deny_($4);
+$ctx1.sendIdx["deny:"]=1;
+$8=(4).__at((5));
+$ctx1.sendIdx["@"]=5;
+$9=(4).__at((5));
+$ctx1.sendIdx["@"]=6;
+$7=_st($8).__lt_eq($9);
+$ctx1.sendIdx["<="]=1;
+self._assert_($7);
+$ctx1.sendIdx["assert:"]=2;
+$11=(4).__at((5));
+$ctx1.sendIdx["@"]=7;
+$12=(3).__at((5));
+$ctx1.sendIdx["@"]=8;
+$10=_st($11).__lt_eq($12);
+self._deny_($10);
+$ctx1.sendIdx["deny:"]=2;
+$14=(5).__at((6));
+$ctx1.sendIdx["@"]=9;
+$15=(4).__at((5));
+$ctx1.sendIdx["@"]=10;
+$13=_st($14).__gt($15);
+$ctx1.sendIdx[">"]=1;
+self._assert_($13);
+$ctx1.sendIdx["assert:"]=3;
+$17=(5).__at((6));
+$ctx1.sendIdx["@"]=11;
+$18=(6).__at((6));
+$ctx1.sendIdx["@"]=12;
+$16=_st($17).__gt($18);
+self._deny_($16);
+$ctx1.sendIdx["deny:"]=3;
+$20=(4).__at((5));
+$ctx1.sendIdx["@"]=13;
+$21=(4).__at((5));
+$ctx1.sendIdx["@"]=14;
+$19=_st($20).__gt_eq($21);
+$ctx1.sendIdx[">="]=1;
+self._assert_($19);
+$23=(4).__at((5));
+$ctx1.sendIdx["@"]=15;
+$22=_st($23).__gt_eq((5).__at((5)));
+self._deny_($22);
+return self}, function($ctx1) {$ctx1.fill(self,"testComparison",{},globals.PointTest)})},
+args: [],
+source: "testComparison\x0a\x09self assert: 3@4 < (4@5).\x0a\x09self deny: 3@4 < (4@4).\x0a\x09\x0a\x09self assert: 4@5 <= (4@5).\x0a\x09self deny: 4@5 <= (3@5).\x0a\x09\x0a\x09self assert: 5@6 > (4@5).\x0a\x09self deny: 5@6 > (6@6).\x0a\x09\x0a\x09self assert: 4@5 >= (4@5).\x0a\x09self deny: 4@5 >= (5@5)",
+messageSends: ["assert:", "<", "@", "deny:", "<=", ">", ">="],
+referencedClasses: []
+}),
+globals.PointTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testEgality",

+ 34 - 1
js/Kernel-Tests.st → src/Kernel-Tests.st

@@ -26,7 +26,7 @@ TestCase subclass: #AnnouncerTest
 	instanceVariableNames: ''
 	package: 'Kernel-Tests'!
 
-!AnnouncerTest methodsFor: 'not yet classified'!
+!AnnouncerTest methodsFor: 'tests'!
 
 testOnDo
 	| counter announcer |
@@ -42,6 +42,25 @@ testOnDo
 	self assert: counter equals: 2.
 !
 
+testOnDoFor
+	| counter announcer |
+	
+	counter := 0.
+	announcer := Announcer new.
+	announcer on: SystemAnnouncement do: [ counter := counter + 1 ] for: self.
+
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 1.
+
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 2.
+	
+	announcer unsubscribe: self.
+	
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 2.
+!
+
 testOnDoOnce
 	| counter announcer |
 	
@@ -2324,6 +2343,20 @@ testAt
 	self assert: 3@4 equals: (Point x: 3 y: 4)
 !
 
+testComparison
+	self assert: 3@4 < (4@5).
+	self deny: 3@4 < (4@4).
+	
+	self assert: 4@5 <= (4@5).
+	self deny: 4@5 <= (3@5).
+	
+	self assert: 5@6 > (4@5).
+	self deny: 5@6 > (6@6).
+	
+	self assert: 4@5 >= (4@5).
+	self deny: 4@5 >= (5@5)
+!
+
 testEgality
 	self assert: (3@4 = (3@4)).
 	self deny: 3@5 = (3@6)

+ 0 - 0
js/Kernel-Transcript.js → src/Kernel-Transcript.js


+ 0 - 0
js/Kernel-Transcript.st → src/Kernel-Transcript.st


+ 0 - 0
js/SUnit-Tests.js → src/SUnit-Tests.js


+ 0 - 0
js/SUnit-Tests.st → src/SUnit-Tests.st


+ 0 - 0
js/SUnit.js → src/SUnit.js


+ 0 - 0
js/SUnit.st → src/SUnit.st


+ 0 - 0
js/Spaces.js → src/Spaces.js


+ 0 - 0
js/Spaces.st → src/Spaces.st


+ 19 - 19
js/Canvas.js → src/Web.js

@@ -1,8 +1,8 @@
-define("amber_core/Canvas", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure", "amber_core/Kernel-Methods", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st, globals){
-smalltalk.addPackage('Canvas');
-smalltalk.packages["Canvas"].transport = {"type":"amd","amdNamespace":"amber_core"};
+define("amber_core/Web", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure", "amber_core/Kernel-Methods", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st, globals){
+smalltalk.addPackage('Web');
+smalltalk.packages["Web"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
-smalltalk.addClass('BrowserInterface', globals.Object, [], 'Canvas');
+smalltalk.addClass('BrowserInterface', globals.Object, [], 'Web');
 globals.BrowserInterface.comment="I am platform interface class that tries to use window and jQuery; that is, one for browser environment.\x0a\x0a## API\x0a\x0a    self isAvailable. \x22true if window and jQuery exist\x22.\x0a\x0a    self alert: 'Hey, there is a problem'.\x0a    self confirm: 'Affirmative?'.\x0a    self prompt: 'Your name:'.\x0a\x0a    self ajax: #{\x0a        'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'\x0a    }.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -94,7 +94,7 @@ globals.BrowserInterface);
 
 
 
-smalltalk.addClass('HTMLCanvas', globals.Object, ['root'], 'Canvas');
+smalltalk.addClass('HTMLCanvas', globals.Object, ['root'], 'Web');
 globals.HTMLCanvas.comment="I am a canvas for building HTML.\x0a\x0aI provide the `#tag:` method to create a `TagBrush` (wrapping a DOM element) and convenience methods in the `tags` protocol.\x0a\x0a## API\x0a\x0aMy instances are used as the argument of the `#renderOn:` method of `Widget` objects.\x0a\x0aThe `#with:` method is used to compose HTML, nesting tags. `#with:` can take a `TagBrush`, a `String`, a `BlockClosure` or a `Widget` as argument.\x0a\x0a## Usage example:\x0a\x0a    aCanvas a \x0a        with: [ aCanvas span with: 'click me' ];\x0a        onClick: [ window alert: 'clicked!' ]";
 smalltalk.addMethod(
 smalltalk.method({
@@ -2217,7 +2217,7 @@ referencedClasses: []
 globals.HTMLCanvas.klass);
 
 
-smalltalk.addClass('HTMLSnippet', globals.Object, ['snippets'], 'Canvas');
+smalltalk.addClass('HTMLSnippet', globals.Object, ['snippets'], 'Web');
 globals.HTMLSnippet.comment="My sole instance is the registry of html snippets.\x0a`HTMLSnippet current` is the public singleton instance.\x0a\x0aOn startup, it scans the document for any html elements\x0awith `'data-snippet=\x22foo\x22'` attribute and takes them off the document,\x0aremembering them in the store under the specified name.\x0aIt also install method #foo into HTMLCanvas dynamically.\x0a\x0aEvery html snippet should mark a 'caret', a place where contents\x0acan be inserted, by 'data-snippet=\x22*\x22' (a special name for caret).\x0aFor example:\x0a\x0a`<li data-snippet='menuelement' class='...'><a data-snippet='*'></a></li>`\x0a\x0adefines a list element with a link inside; the link itself is marked as a caret.\x0a\x0aYou can later issue\x0a\x0a`html menuelement href: '/foo'; with: 'A foo'`\x0a\x0ato insert the whole snippet and directly manipulate the caret, so it renders:\x0a\x0a`<li class='...'><a href='/foo'>A foo</a></li>`\x0a\x0aFor a self-careting tags (not very useful, but you do not need to fill class etc.\x0ayou can use\x0a\x0a`<div class='lots of classes' attr1='one' attr2='two' data-snippet='*bar'></div>`\x0a\x0aand in code later do:\x0a\x0a`html bar with: [ xxx ]`\x0a\x0ato render\x0a\x0a`<div class='lots of classes' attr1='one' attr2='two'>...added by xxx...</div>`";
 smalltalk.addMethod(
 smalltalk.method({
@@ -2465,7 +2465,7 @@ referencedClasses: []
 globals.HTMLSnippet.klass);
 
 
-smalltalk.addClass('TagBrush', globals.Object, ['canvas', 'element'], 'Canvas');
+smalltalk.addClass('TagBrush', globals.Object, ['canvas', 'element'], 'Web');
 globals.TagBrush.comment="I am a brush for building a single DOM element (which I hold onto).\x0a\x0aAll tags but `<style>` are instances of me (see the `StyleBrush` class).\x0a\x0a## API\x0a\x0a1. Nesting\x0a\x0a    Use `#with:` to nest tags. `#with:` can take aString, `TagBrush` instance, a `Widget` or block closure as parameter.\x0a\x0a    Example: `aTag with: aString with: aCanvas div`\x0a\x0a2. Events\x0a\x0a    The `events` protocol contains all methods related to events (delegating event handling to jQuery).\x0a\x0a    Example: `aTag onClick: [ window alert: 'clicked' ]`\x0a\x0a3. Attributes\x0a\x0a    The `attribute` protocol contains methods for attribute manipulation (delegating to jQuery too).\x0a\x0a    Example: `aTag at: 'value' put: 'hello world'`\x0a\x0a4. Raw access and jQuery\x0a\x0a    The `#element` method can be used to access to JavaScript DOM element object.\x0a\x0a    Example: `aTag element cssStyle`\x0a\x0a    Use `#asJQuery` to access to the receiver converted into a jQuery object.\x0a\x0a    Example: `aTag asJQuery css: 'color' value: 'red'`";
 smalltalk.addMethod(
 smalltalk.method({
@@ -3673,7 +3673,7 @@ referencedClasses: []
 globals.TagBrush.klass);
 
 
-smalltalk.addClass('Widget', globals.InterfacingObject, [], 'Canvas');
+smalltalk.addClass('Widget', globals.InterfacingObject, [], 'Web');
 globals.Widget.comment="I am a presenter building HTML. Subclasses are typically reusable components.\x0a\x0a## API\x0a\x0aUse `#renderContentOn:` to build HTML. (See `HTMLCanvas` and `TagBrush` classes for more about building HTML).\x0a\x0aTo add a widget to the page, the convenience method `#appendToJQuery:` is very useful.\x0a\x0aExemple: \x0a\x0a    Counter new appendToJQuery: 'body' asJQuery";
 smalltalk.addMethod(
 smalltalk.method({
@@ -3741,7 +3741,7 @@ globals.Widget.klass);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToBrush:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aTagBrush){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3757,7 +3757,7 @@ globals.BlockClosure);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToJQuery:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aJQuery){
 var self=this;
 function $HTMLCanvas(){return globals.HTMLCanvas||(typeof HTMLCanvas=="undefined"?nil:HTMLCanvas)}
@@ -3774,7 +3774,7 @@ globals.BlockClosure);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asSnippet",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (){
 var self=this;
 function $HTMLSnippet(){return globals.HTMLSnippet||(typeof HTMLSnippet=="undefined"?nil:HTMLSnippet)}
@@ -3793,7 +3793,7 @@ globals.CharacterArray);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asJQuery",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3809,7 +3809,7 @@ globals.JSObjectProxy);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asJQueryInContext:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3825,7 +3825,7 @@ globals.JSObjectProxy);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToBrush:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aTagBrush){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3841,7 +3841,7 @@ globals.Object);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToJQuery:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aJQuery){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3857,7 +3857,7 @@ globals.Object);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToBrush:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aTagBrush){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3873,7 +3873,7 @@ globals.String);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToJQuery:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aJQuery){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3889,7 +3889,7 @@ globals.String);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asJQuery",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -3905,7 +3905,7 @@ globals.String);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asJQueryInContext:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 

+ 11 - 11
js/Canvas.st → src/Web.st

@@ -1,7 +1,7 @@
-Smalltalk createPackage: 'Canvas'!
+Smalltalk createPackage: 'Web'!
 Object subclass: #BrowserInterface
 	instanceVariableNames: ''
-	package: 'Canvas'!
+	package: 'Web'!
 !BrowserInterface commentStamp!
 I am platform interface class that tries to use window and jQuery; that is, one for browser environment.
 
@@ -43,7 +43,7 @@ isAvailable
 
 Object subclass: #HTMLCanvas
 	instanceVariableNames: 'root'
-	package: 'Canvas'!
+	package: 'Web'!
 !HTMLCanvas commentStamp!
 I am a canvas for building HTML.
 
@@ -565,7 +565,7 @@ onJQuery: aJQuery
 
 Object subclass: #HTMLSnippet
 	instanceVariableNames: 'snippets'
-	package: 'Canvas'!
+	package: 'Web'!
 !HTMLSnippet commentStamp!
 My sole instance is the registry of html snippets.
 `HTMLSnippet current` is the public singleton instance.
@@ -696,7 +696,7 @@ new
 
 Object subclass: #TagBrush
 	instanceVariableNames: 'canvas element'
-	package: 'Canvas'!
+	package: 'Web'!
 !TagBrush commentStamp!
 I am a brush for building a single DOM element (which I hold onto).
 
@@ -1061,7 +1061,7 @@ fromString: aString canvas: aCanvas
 
 InterfacingObject subclass: #Widget
 	instanceVariableNames: ''
-	package: 'Canvas'!
+	package: 'Web'!
 !Widget commentStamp!
 I am a presenter building HTML. Subclasses are typically reusable components.
 
@@ -1097,7 +1097,7 @@ heliosClass
 	^ 'widget'
 ! !
 
-!BlockClosure methodsFor: '*Canvas'!
+!BlockClosure methodsFor: '*Web'!
 
 appendToBrush: aTagBrush
 	aTagBrush appendBlock: self
@@ -1107,13 +1107,13 @@ appendToJQuery: aJQuery
 	self value: (HTMLCanvas onJQuery: aJQuery)
 ! !
 
-!CharacterArray methodsFor: '*Canvas'!
+!CharacterArray methodsFor: '*Web'!
 
 asSnippet
 	^ HTMLSnippet current snippetAt: self asString
 ! !
 
-!JSObjectProxy methodsFor: '*Canvas'!
+!JSObjectProxy methodsFor: '*Web'!
 
 asJQuery
 	<return jQuery(self['@jsObject'])>
@@ -1123,7 +1123,7 @@ asJQueryInContext: aContext
 	<return jQuery(self['@jsObject'], aContext)>
 ! !
 
-!Object methodsFor: '*Canvas'!
+!Object methodsFor: '*Web'!
 
 appendToBrush: aTagBrush
 	aTagBrush append: self asString
@@ -1133,7 +1133,7 @@ appendToJQuery: aJQuery
 	aJQuery append: self asString
 ! !
 
-!String methodsFor: '*Canvas'!
+!String methodsFor: '*Web'!
 
 appendToBrush: aTagBrush
 	aTagBrush appendString: self

+ 5 - 5
support/amber.js

@@ -3,11 +3,11 @@
     either defines 'require', thus passing config, if loaded prior require.js;
     or calls require.config, if loaded post require.js).
   Usage example:
-    require(['amber/devel'], function(smalltalk) {
-        smallralk.initialize({"transport.defaultAmdNamespace": "com_example_myproject"});
+    require(['amber/devel'], function(amber) {
+        amber.initialize({"transport.defaultAmdNamespace": "com_example_myproject"});
 
-        smalltalk.globals.Browser._open(); // for legacy IDE
-        smalltalk.popupHelios(); // for Helios IDE
+        amber.globals.Browser._open(); // for legacy IDE
+        amber.popupHelios(); // for Helios IDE
     });
   For detailed explanation of amber loading, see:
   https://github.com/amber-smalltalk/amber/wiki/How-to-load-amber
@@ -62,7 +62,7 @@ require = function (require) {
             'amber_vm': amber_home + '/support',
             'amber_css': amber_home + '/css',
             'amber_lib': library_home,
-            'amber_core': amber_home + '/js',
+            'amber_core': amber_home + '/src',
             'amber_helios/html': amber_home,
             'jquery': library_home + '/jquery/jquery.min',
             'jquery-ui': library_home + '/jquery-ui/ui/minified/jquery-ui.min',

+ 1 - 1
support/deploy.js

@@ -9,5 +9,5 @@ define([
     'amber_core/Kernel-Exceptions',
     'amber_core/Kernel-Transcript',
     'amber_core/Kernel-Announcements',
-    'amber_core/Canvas'
+    'amber_core/Web'
 ], function (smalltalk) { return smalltalk; });

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff