Sfoglia il codice sorgente

Merge branch 'master' into moka

Nicolas Petton 11 anni fa
parent
commit
e0daaac5d3
100 ha cambiato i file con 3612 aggiunte e 969 eliminazioni
  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
 # Ignoring Mac Finder files
 .DS_Store
 .DS_Store
 
 
-# Ignoring compiled files in st
-st/*.js
-
 # Ignoring run.js in test/
 # Ignoring run.js in test/
 test/amber_test_runner.js
 test/amber_test_runner.js
 test/run.js
 test/run.js

+ 28 - 28
Gruntfile.js

@@ -30,40 +30,40 @@ module.exports = function(grunt) {
         closure_jar: ''
         closure_jar: ''
       },
       },
       all: {
       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']
         jsGlobals: ['navigator']
       },
       },
       amber_kernel: {
       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: {
       amber_IDE: {
-        output_dir : 'js',
-        src: ['st/IDE.st'],
-        libraries: ['Canvas']
+        output_dir : 'src',
+        src: ['src/IDE.st'],
+        libraries: ['Web']
       },
       },
       amber_tests: {
       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']
         libraries: ['SUnit']
       },
       },
       amber_test_runner: {
       amber_test_runner: {
@@ -77,8 +77,8 @@ module.exports = function(grunt) {
         output_name: 'test/amber_test_runner'
         output_name: 'test/amber_test_runner'
       },
       },
       amber_cli: {
       amber_cli: {
-        output_dir: 'cli/js',
-        src: ['cli/st/AmberCli.st'],
+        output_dir: 'cli/src',
+        src: ['cli/src/AmberCli.st'],
         libraries: [
         libraries: [
             'Compiler-Exceptions', 'Compiler-Core', 'Compiler-AST',
             'Compiler-Exceptions', 'Compiler-Core', 'Compiler-AST',
             'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser'
             'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser'
@@ -90,7 +90,7 @@ module.exports = function(grunt) {
     },
     },
 
 
     jshint: {
     jshint: {
-      amber: ['js/*.js'],
+      amber: ['src/*.js'],
       server: ['server/*.js'],
       server: ['server/*.js'],
       repl: ['repl/*.js'],
       repl: ['repl/*.js'],
       tests: ['test/*.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
 1. check that all tests are green
 2. check that the examples are up-to-date
 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
 5. log in to npm with write access for the Amber package
 6. execute `cli/support/release.sh`
 6. execute `cli/support/release.sh`
 7. answer the question about the version number used for the release
 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'>
     <script type='text/javascript'>
     require.config({
     require.config({
         paths: {
         paths: {
-            'amber_cli': 'js',
-            'amber_cli/_source': 'st'
+            'amber_cli': 'src'
         }
         }
     });
     });
     require(
     require(

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

@@ -253,9 +253,8 @@ protocol: 'initialization',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$5,$4,$2,$6;
+var $1;
 $1=_st(self["@fs"])._existsSync_(self._withBasePath_("index.html"));
 $1=_st(self["@fs"])._existsSync_(self._withBasePath_("index.html"));
-$ctx1.sendIdx["existsSync:"]=1;
 if(! smalltalk.assert($1)){
 if(! smalltalk.assert($1)){
 _st(console)._warn_("Warning: project directory does not contain index.html.");
 _st(console)._warn_("Warning: project directory does not contain index.html.");
 $ctx1.sendIdx["warn:"]=1;
 $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,");
 _st(console)._warn_("    You can also specify a page to be served by default,");
 $ctx1.sendIdx["warn:"]=3;
 $ctx1.sendIdx["warn:"]=3;
 _st(console)._warn_("    for all paths that do not map to a file, with --fallback-page.");
 _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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"checkDirectoryLayout",{},globals.FileServer)})},
 args: [],
 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: []
 referencedClasses: []
 }),
 }),
 globals.FileServer);
 globals.FileServer);
@@ -394,7 +377,7 @@ $3="Error creating WriteStream for file ".__comma(file);
 $ctx2.sendIdx[","]=2;
 $ctx2.sendIdx[","]=2;
 _st($2)._warn_($3);
 _st($2)._warn_($3);
 $ctx2.sendIdx["warn:"]=1;
 $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;
 $ctx2.sendIdx["warn:"]=2;
 _st(console)._warn_("    The exact error is: ".__comma(error));
 _st(console)._warn_("    The exact error is: ".__comma(error));
 return self._respondNotCreatedTo_(aResponse);
 return self._respondNotCreatedTo_(aResponse);
@@ -420,7 +403,7 @@ return _st(stream)._end();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"handlePUTRequest:respondTo:",{aRequest:aRequest,aResponse:aResponse,file:file,stream:stream},globals.FileServer)})},
 args: ["aRequest", "aResponse"],
 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"],
 messageSends: ["ifFalse:", "isAuthenticated:", "respondAuthenticationRequiredTo:", ",", "url", "createWriteStream:", "on:do:", "warn:", "respondNotCreatedTo:", "respondCreatedTo:", "setEncoding:", "write:", "ifTrue:", "writable", "end"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -798,11 +781,11 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
 _st(aResponse)._writeHead_options_((400),globals.HashedCollection._newFromPairs_(["Content-Type","text/plain"]));
 _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();
 $1=_st(aResponse)._end();
 return self}, function($ctx1) {$ctx1.fill(self,"respondNotCreatedTo:",{aResponse:aResponse},globals.FileServer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"respondNotCreatedTo:",{aResponse:aResponse},globals.FileServer)})},
 args: ["aResponse"],
 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"],
 messageSends: ["writeHead:options:", "write:", "end"],
 referencedClasses: []
 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 specify the directory containing index.html with --base-path.'.
 		console warn: '    You can also specify a page to be served by default,'.
 		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.'].
 		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
 initialize
@@ -279,7 +275,7 @@ handlePUTRequest: aRequest respondTo: aResponse
 
 
 	stream on: 'error' do: [:error |
 	stream on: 'error' do: [:error |
 		console warn: 'Error creating WriteStream for file ', file.
 		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.
 		console warn: '    The exact error is: ', error.
 		self respondNotCreatedTo: aResponse].
 		self respondNotCreatedTo: aResponse].
 
 
@@ -352,7 +348,7 @@ respondInternalErrorTo: aResponse
 respondNotCreatedTo: aResponse
 respondNotCreatedTo: aResponse
 	aResponse
 	aResponse
 		writeHead: 400 options: #{'Content-Type' -> 'text/plain'};
 		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.
 		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.packages["Kernel-Objects"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 
 smalltalk.addClass('ProtoObject', globals.nil, [], 'Kernel-Objects');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "=",
 selector: "=",
@@ -15248,7 +15248,7 @@ globals.String.klass);
 
 
 
 
 smalltalk.addClass('Set', globals.Collection, ['defaultBucket', 'slowBucketStores', 'fastBuckets', 'size'], 'Kernel-Collections');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "=",
 selector: "=",
@@ -17732,7 +17732,7 @@ return smalltalk.withContext(function($ctx1) {
 return self["@jsObject"] === aJSObject;
 return self["@jsObject"] === aJSObject;
 return self}, function($ctx1) {$ctx1.fill(self,"compareJSObjectWith:",{aJSObject:aJSObject},globals.JSObjectProxy)})},
 return self}, function($ctx1) {$ctx1.fill(self,"compareJSObjectWith:",{aJSObject:aJSObject},globals.JSObjectProxy)})},
 args: ["aJSObject"],
 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: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -19137,7 +19137,7 @@ globals.Setting.klass);
 
 
 
 
 smalltalk.addClass('SmalltalkImage', globals.Object, [], 'Kernel-Infrastructure');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "addGlobalJsVariable:",
 selector: "addGlobalJsVariable:",
@@ -34551,28 +34551,20 @@ selector: "visitDynamicDictionaryNode:",
 protocol: 'visiting',
 protocol: 'visiting',
 fn: function (aNode){
 fn: function (aNode){
 var self=this;
 var self=this;
-var associations,hashedCollection;
+var keyValueList;
 function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
 function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
 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){
 _st(_st(aNode)._nodes())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
 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)})}));
 }, 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"],
 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"]
 referencedClasses: ["OrderedCollection", "HashedCollection"]
 }),
 }),
 globals.ASTInterpreter);
 globals.ASTInterpreter);
@@ -38878,7 +38870,7 @@ smalltalk.addPackage('AmberCli');
 smalltalk.packages["AmberCli"].transport = {"type":"amd","amdNamespace":"amber_cli"};
 smalltalk.packages["AmberCli"].transport = {"type":"amd","amdNamespace":"amber_cli"};
 
 
 smalltalk.addClass('AmberCli', globals.Object, [], 'AmberCli');
 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.addMethod(
 smalltalk.method({
 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');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "base64Decode:",
 selector: "base64Decode:",
@@ -39128,9 +39120,8 @@ protocol: 'initialization',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$5,$4,$2,$6;
+var $1;
 $1=_st(self["@fs"])._existsSync_(self._withBasePath_("index.html"));
 $1=_st(self["@fs"])._existsSync_(self._withBasePath_("index.html"));
-$ctx1.sendIdx["existsSync:"]=1;
 if(! smalltalk.assert($1)){
 if(! smalltalk.assert($1)){
 _st(console)._warn_("Warning: project directory does not contain index.html.");
 _st(console)._warn_("Warning: project directory does not contain index.html.");
 $ctx1.sendIdx["warn:"]=1;
 $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,");
 _st(console)._warn_("    You can also specify a page to be served by default,");
 $ctx1.sendIdx["warn:"]=3;
 $ctx1.sendIdx["warn:"]=3;
 _st(console)._warn_("    for all paths that do not map to a file, with --fallback-page.");
 _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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"checkDirectoryLayout",{},globals.FileServer)})},
 args: [],
 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: []
 referencedClasses: []
 }),
 }),
 globals.FileServer);
 globals.FileServer);
@@ -39269,7 +39244,7 @@ $3="Error creating WriteStream for file ".__comma(file);
 $ctx2.sendIdx[","]=2;
 $ctx2.sendIdx[","]=2;
 _st($2)._warn_($3);
 _st($2)._warn_($3);
 $ctx2.sendIdx["warn:"]=1;
 $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;
 $ctx2.sendIdx["warn:"]=2;
 _st(console)._warn_("    The exact error is: ".__comma(error));
 _st(console)._warn_("    The exact error is: ".__comma(error));
 return self._respondNotCreatedTo_(aResponse);
 return self._respondNotCreatedTo_(aResponse);
@@ -39295,7 +39270,7 @@ return _st(stream)._end();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"handlePUTRequest:respondTo:",{aRequest:aRequest,aResponse:aResponse,file:file,stream:stream},globals.FileServer)})},
 args: ["aRequest", "aResponse"],
 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"],
 messageSends: ["ifFalse:", "isAuthenticated:", "respondAuthenticationRequiredTo:", ",", "url", "createWriteStream:", "on:do:", "warn:", "respondNotCreatedTo:", "respondCreatedTo:", "setEncoding:", "write:", "ifTrue:", "writable", "end"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -39673,11 +39648,11 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
 _st(aResponse)._writeHead_options_((400),globals.HashedCollection._newFromPairs_(["Content-Type","text/plain"]));
 _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();
 $1=_st(aResponse)._end();
 return self}, function($ctx1) {$ctx1.fill(self,"respondNotCreatedTo:",{aResponse:aResponse},globals.FileServer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"respondNotCreatedTo:",{aResponse:aResponse},globals.FileServer)})},
 args: ["aResponse"],
 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"],
 messageSends: ["writeHead:options:", "write:", "end"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -40212,7 +40187,7 @@ globals.FileServer.klass);
 
 
 
 
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "addVariableNamed:to:",
 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();
 globals.AmberCli._main();
 });
 });
 requirejs("amber_vm/_init");
 requirejs("amber_vm/_init");

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

@@ -112,11 +112,11 @@ function print_usage() {
 		'',
 		'',
 		'   *.js',
 		'   *.js',
 		'     Files are linked (concatenated) in listed order.',
 		'     Files are linked (concatenated) in listed order.',
-		'     If not found we look in $AMBER/js/',
+		'     If not found we look in $AMBER/src/',
 		'',
 		'',
 		'   *.st',
 		'   *.st',
 		'     Files are compiled into .js files before concatenation.',
 		'     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',
 		'     NOTE: Each .st file is currently considered to be a fileout of a single class',
 		'     category of the same name as the file!',
 		'     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) {
 	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'));
 		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:
  * Check if the file given as parameter exists in any of the following directories:
  *  1. current local directory
  *  1. current local directory
  *  2. configuration.jsLibraryDirs
  *  2. configuration.jsLibraryDirs
- *  3. $AMBER/js/
+ *  3. $AMBER/src/
  *  3. $AMBER/support/
  *  3. $AMBER/support/
  *
  *
  * @param filename name of a file without '.js' prefix
  * @param filename name of a file without '.js' prefix
@@ -468,7 +468,8 @@ function compose_js_files(configuration) {
 	return new Promise(function(resolve, reject) {
 	return new Promise(function(resolve, reject) {
 		var programFile = configuration.program;
 		var programFile = configuration.program;
 		if (undefined === programFile) {
 		if (undefined === programFile) {
-			reject(configuration);
+			resolve(configuration);
+            return;
 		}
 		}
 		if (undefined !== configuration.output_dir) {
 		if (undefined !== configuration.output_dir) {
 			programFile = path.join(configuration.output_dir, programFile);
 			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
 	sed -e 's@/amber.git.*"@/amber.git#'"$VER"'"@' package.json.bak >package.json
 	rm package.json.bak
 	rm package.json.bak
 	git add package.json
 	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 add cli/support/amber-cli.js
 	git commit -a -m "Release version $VER"
 	git commit -a -m "Release version $VER"
 	git tag -a "$VER" -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
 sed -e 's@/amber.git.*"@/amber.git"@' package.json.bak >package.json
 rm package.json.bak
 rm package.json.bak
 git add package.json
 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 add cli/support/amber-cli.js
 git commit -a -m "Working on $VERF"
 git commit -a -m "Working on $VERF"
 git push --tags
 git push --tags

+ 2 - 2
cli/support/setversion.sh

@@ -4,7 +4,7 @@ VERSION=$1
 cd `dirname "$0"`/../..
 cd `dirname "$0"`/../..
 AMBER_BASE=`pwd`
 AMBER_BASE=`pwd`
 
 
-cd $AMBER_BASE/st
+cd $AMBER_BASE/src
 # replace version number
 # replace version number
 cp Kernel-Infrastructure.st Kernel-Infrastructure.st.bak
 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
 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
 # compile Kernel-Infrastructure
 cd $AMBER_BASE
 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)
 # set version in all json files (bower, npm)
 for F in *.json; do
 for F in *.json; do
   cp $F $F.bak
   cp $F $F.bak

+ 47 - 10
css/helios.css

@@ -15,8 +15,11 @@ html[xmlns] .clearfix {
 * html .clearfix {
 * html .clearfix {
   height: 1%;
   height: 1%;
 }
 }
+body.navigation .CodeMirror pre {
+  cursor: pointer !important;
+}
 .cm-s-helios.CodeMirror {
 .cm-s-helios.CodeMirror {
-  font-family: Menlo, Monaco, Consolas, Inconsolata, "Lucida Console", Courier, monospace;
+  font-family: Consolas, "Liberation Mono", Courier, monospace;
   line-height: 16px;
   line-height: 16px;
   font-size: 13px;
   font-size: 13px;
 }
 }
@@ -533,6 +536,7 @@ body[id="helios"] .key_helper .command strong {
 body[id="helios"] .key_helper #binding-helper-main {
 body[id="helios"] .key_helper #binding-helper-main {
   display: block;
   display: block;
   padding: 5px;
   padding: 5px;
+  background: #eee;
 }
 }
 body[id="helios"] .key_helper .label {
 body[id="helios"] .key_helper .label {
   padding: 1px 4px;
   padding: 1px 4px;
@@ -622,16 +626,13 @@ body[id="helios"] #helper {
 }
 }
 body[id="helios"] #overlay {
 body[id="helios"] #overlay {
   z-index: 2000;
   z-index: 2000;
-  background: rgba(112, 66, 20, 0.1);
+  background: transparent;
   position: fixed;
   position: fixed;
   top: 0;
   top: 0;
   left: 0;
   left: 0;
   right: 0;
   right: 0;
   bottom: 0;
   bottom: 0;
 }
 }
-body[id="helios"] #overlay.light {
-  background: rgba(50, 50, 50, 0.1);
-}
 body[id="helios"] .confirmation,
 body[id="helios"] .confirmation,
 body[id="helios"] .dialog {
 body[id="helios"] .dialog {
   z-index: 2001;
   z-index: 2001;
@@ -647,10 +648,14 @@ body[id="helios"] .dialog {
   left: 50%;
   left: 50%;
   margin-left: -135px;
   margin-left: -135px;
   box-shadow: 0 0 6px #333;
   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"] .confirmation .hl_widget .form-actions,
 body[id="helios"] .dialog .hl_widget .form-actions {
 body[id="helios"] .dialog .hl_widget .form-actions {
@@ -686,6 +691,11 @@ body[id="helios"] .dialog textarea {
   display: block;
   display: block;
   width: 235px;
   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"] .confirmation .progress,
 body[id="helios"] .dialog .progress {
 body[id="helios"] .dialog .progress {
   height: 5px;
   height: 5px;
@@ -724,6 +734,10 @@ body[id="helios"] .button {
   margin: 0;
   margin: 0;
   margin-left: 10px;
   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: -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;
   font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
 }
 }
 body[id="helios"] .button.default {
 body[id="helios"] .button.default {
@@ -732,6 +746,9 @@ body[id="helios"] .button.default {
   border-bottom: 1px solid #4B4B58;
   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: -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: -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);
   -moz-box-shadow: 0 0 3px rgba(69, 113, 184, 0.8);
   -webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
   -webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
   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;
   padding: 1px 4px;
 }
 }
 body[id="helios"] .doc .head {
 body[id="helios"] .doc .head {
-  background: #08C;
+  background: #666;
   padding: 10px;
   padding: 10px;
   font-size: 22px;
   font-size: 22px;
   color: white;
   color: white;
 }
 }
+body[id="helios"] .focused .doc .head {
+  background: #08c;
+}
 body[id="helios"] .doc .button {
 body[id="helios"] .doc .button {
   float: right;
   float: right;
 }
 }
@@ -803,3 +823,20 @@ body[id="helios"] .transcript textarea {
   padding: 0;
   padding: 0;
   border: 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%;
 	height: 1%;
 }
 }
 
 
+body.navigation .CodeMirror pre {
+	cursor: pointer !important;
+}
+
 .cm-s-helios {
 .cm-s-helios {
 	&.CodeMirror {
 	&.CodeMirror {
-		font-family: Menlo, Monaco, Consolas, Inconsolata, "Lucida Console", Courier, monospace;
+		font-family: Consolas, "Liberation Mono", Courier, monospace;
 		line-height: 16px;
 		line-height: 16px;
 		font-size: 13px;
 		font-size: 13px;
 	}
 	}
@@ -613,6 +617,7 @@ body[id="helios"] {
 		#binding-helper-main {
 		#binding-helper-main {
 			display: block;
 			display: block;
 			padding: 5px;
 			padding: 5px;
+			background: #eee;
 		}
 		}
 
 
 		.label {
 		.label {
@@ -721,16 +726,12 @@ body[id="helios"] {
 
 
 	#overlay {
 	#overlay {
 		z-index: 2000;
 		z-index: 2000;
-		background: rgba(112, 66, 20, 0.1);
+		background: transparent;
 		position: fixed;
 		position: fixed;
 		top: 0;
 		top: 0;
 		left: 0;
 		left: 0;
 		right: 0;
 		right: 0;
 		bottom: 0;
 		bottom: 0;
-
-		&.light {
-			background: rgba(50, 50, 50, 0.1);
-		}
 	}
 	}
 
 
 	.confirmation, .dialog {
 	.confirmation, .dialog {
@@ -747,10 +748,14 @@ body[id="helios"] {
 		left: 50%;
 		left: 50%;
 		margin-left: -135px;
 		margin-left: -135px;
 		box-shadow: 0 0 6px #333;
 		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 {
 		.hl_widget {
 
 
@@ -789,6 +794,11 @@ body[id="helios"] {
 			width: 235px;
 			width: 235px;
 		}
 		}
 
 
+		input[type="text"] {
+			margin: 5px 0;
+			width: 390px;
+		}
+
 		.progress {
 		.progress {
 			height: 5px;
 			height: 5px;
 
 
@@ -828,6 +838,10 @@ body[id="helios"] {
 		margin: 0;
 		margin: 0;
 		margin-left: 10px;
 		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: -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;
 		font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
 	}
 	}
 
 
@@ -837,6 +851,9 @@ body[id="helios"] {
 		border-bottom: 1px solid #4B4B58;
 		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: -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: -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);
 		-moz-box-shadow: 0 0 3px rgba(69, 113, 184, 0.8);
 		-webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
 		-webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
 		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;
 		padding: 1px 4px;
 	}
 	}
 	.doc .head {
 	.doc .head {
-		background: #08C;
+		background: #666;
 		padding: 10px;
 		padding: 10px;
 		font-size: 22px;
 		font-size: 22px;
 		color: white;
 		color: white;
 	}
 	}
 
 
+	.focused .doc .head {
+		background: #08c;
+	}
+
 	.doc .button {
 	.doc .button {
 		float: right;
 		float: right;
 	}
 	}
@@ -918,4 +939,28 @@ body[id="helios"] {
 		padding: 0;
 		padding: 0;
 		border: 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
            library_dirs: ['dir1', '/usr/local/js'], // optional
            verbose: true
            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
          jsGlobals: ['global1', 'global2'],     // optional
          main_class: 'HelloWorld',              // optional
          main_class: 'HelloWorld',              // optional
          output_name: '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);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isAssignmentNode",
 selector: "isAssignmentNode",
@@ -147,6 +194,21 @@ referencedClasses: []
 }),
 }),
 globals.Node);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isNode",
 selector: "isNode",
@@ -287,6 +349,48 @@ referencedClasses: []
 }),
 }),
 globals.Node);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "nextChild",
 selector: "nextChild",
@@ -1742,6 +1846,21 @@ referencedClasses: []
 }),
 }),
 globals.SendNode);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isSendNode",
 selector: "isSendNode",
@@ -1757,6 +1876,24 @@ referencedClasses: []
 }),
 }),
 globals.SendNode);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "nodes",
 selector: "nodes",
@@ -2410,6 +2547,21 @@ referencedClasses: []
 }),
 }),
 globals.VariableNode);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isVariableNode",
 selector: "isVariableNode",
@@ -2425,6 +2577,24 @@ referencedClasses: []
 }),
 }),
 globals.VariableNode);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({

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

@@ -16,10 +16,38 @@ addNode: aNode
 	aNode parent: self
 	aNode parent: self
 !
 !
 
 
+allNodes
+	| allNodes |
+	
+	allNodes := self nodes asSet.
+	self nodes do: [ :each | 
+		allNodes addAll: each allNodes ].
+	
+	^ allNodes
+!
+
 method
 method
 	^ self parent ifNotNil: [ :node | node 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
 nextChild
 	"Answer the next node after aNode.
 	"Answer the next node after aNode.
 	Recurse into the possible children of the receiver to answer the next node to be evaluated"
 	Recurse into the possible children of the receiver to answer the next node to be evaluated"
@@ -122,6 +150,11 @@ postCopy
 
 
 !Node methodsFor: 'testing'!
 !Node methodsFor: 'testing'!
 
 
+inPosition: aPoint
+	^ (self positionStart <= aPoint and: [
+		self positionEnd >= aPoint ])
+!
+
 isAssignmentNode
 isAssignmentNode
 	^ false
 	^ false
 !
 !
@@ -150,6 +183,12 @@ isLastChild
 	^ self parent nodes last = self
 	^ self parent nodes last = self
 !
 !
 
 
+isNavigationNode
+	"Answer true if the node can be navigated to"
+	
+	^ false
+!
+
 isNode
 isNode
 	^ true
 	^ true
 !
 !
@@ -530,6 +569,10 @@ index: anInteger
 	index := anInteger
 	index := anInteger
 !
 !
 
 
+navigationLink
+	^ self selector
+!
+
 nodes
 nodes
 	self receiver ifNil: [ ^ self arguments copy ].
 	self receiver ifNil: [ ^ self arguments copy ].
 	
 	
@@ -582,6 +625,10 @@ isCascadeSendNode
 	^ self parent isCascadeNode
 	^ self parent isCascadeNode
 !
 !
 
 
+isNavigationNode
+	^ true
+!
+
 isSendNode
 isSendNode
 	^ true
 	^ true
 !
 !
@@ -740,6 +787,10 @@ binding
 
 
 binding: aScopeVar
 binding: aScopeVar
 	binding := aScopeVar
 	binding := aScopeVar
+!
+
+navigationLink
+	^ self value
 ! !
 ! !
 
 
 !VariableNode methodsFor: 'testing'!
 !VariableNode methodsFor: 'testing'!
@@ -752,6 +803,10 @@ isImmutable
 	^ self binding isImmutable
 	^ self binding isImmutable
 !
 !
 
 
+isNavigationNode
+	^ true
+!
+
 isVariableNode
 isVariableNode
 	^ true
 	^ 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');
 smalltalk.addClass('DoIt', globals.Object, [], 'Compiler-Core');
 globals.DoIt.comment="`DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.";
 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');
 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 commentStamp!
 `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
 `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
 Object subclass: #NodeVisitor
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Compiler-Core'!
 	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.addClass('CodeGeneratorTest', globals.ASTParsingTest, ['receiver'], 'Compiler-Tests');
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({

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

@@ -102,6 +102,31 @@ testPC
 		currentNode) isJSStatementNode
 		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
 ASTParsingTest subclass: #CodeGeneratorTest
 	instanceVariableNames: 'receiver'
 	instanceVariableNames: 'receiver'
 	package: 'Compiler-Tests'!
 	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.addPackage('Examples');
 smalltalk.packages["Examples"].transport = {"type":"amd","amdNamespace":"amber_core"};
 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.";
 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');
 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`.";
 globals.HLDebuggerAnnouncement.comment="I am the root class of debugger announcements, and hold onto the debugged `context`.";
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -360,6 +348,9 @@ smalltalk.addClass('HLFocusRequested', globals.HLAnnouncement, [], 'Helios-Annou
 smalltalk.addClass('HLClassesFocusRequested', globals.HLFocusRequested, [], 'Helios-Announcements');
 smalltalk.addClass('HLClassesFocusRequested', globals.HLFocusRequested, [], 'Helios-Announcements');
 
 
 
 
+smalltalk.addClass('HLDocumentationFocusRequested', globals.HLFocusRequested, [], 'Helios-Announcements');
+
+
 smalltalk.addClass('HLMethodsFocusRequested', 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!
 !HLDoItExecuted commentStamp!
 I am emitted by a `HLCodeWidget` after a DoIt has been executed.!
 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
 HLAnnouncement subclass: #HLDebuggerAnnouncement
 	instanceVariableNames: 'context'
 	instanceVariableNames: 'context'
 	package: 'Helios-Announcements'!
 	package: 'Helios-Announcements'!
@@ -188,6 +170,10 @@ HLFocusRequested subclass: #HLClassesFocusRequested
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!
 	package: 'Helios-Announcements'!
 
 
+HLFocusRequested subclass: #HLDocumentationFocusRequested
+	instanceVariableNames: ''
+	package: 'Helios-Announcements'!
+
 HLFocusRequested subclass: #HLMethodsFocusRequested
 HLFocusRequested subclass: #HLMethodsFocusRequested
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!
 	package: 'Helios-Announcements'!

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

@@ -707,6 +707,23 @@ referencedClasses: ["HLClassesFocusRequested"]
 }),
 }),
 globals.HLBrowserModel);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "focusOnMethods",
 selector: "focusOnMethods",
@@ -1848,7 +1865,7 @@ return self._renderItemLabel_level_on_(aClass,anInteger,html);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
 $5=_st($4)._onClick_((function(){
 $5=_st($4)._onClick_((function(){
 return smalltalk.withContext(function($ctx3) {
 return smalltalk.withContext(function($ctx3) {
-return self._activateListItem_(_st(li)._asJQuery());
+return self._reactivateListItem_(_st(li)._asJQuery());
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
 return $5;
 return $5;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 }, 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)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"renderItem:level:on:",{aClass:aClass,anInteger:anInteger,html:html,li:li},globals.HLClassesListWidget)})},
 args: ["aClass", "anInteger", "html"],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLClassesListWidget);
 globals.HLClassesListWidget);
@@ -1945,6 +1962,22 @@ referencedClasses: []
 }),
 }),
 globals.HLClassesListWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "selectItem:",
 selector: "selectItem:",
@@ -2256,17 +2289,20 @@ fn: function (){
 var self=this;
 var self=this;
 function $HLClassSelected(){return globals.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 function $HLClassSelected(){return globals.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 function $HLEditComment(){return globals.HLEditComment||(typeof HLEditComment=="undefined"?nil:HLEditComment)}
 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) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 var $1,$2;
 $1=_st(self._model())._announcer();
 $1=_st(self._model())._announcer();
 _st($1)._on_send_to_($HLClassSelected(),"onClassSelected:",self);
 _st($1)._on_send_to_($HLClassSelected(),"onClassSelected:",self);
 $ctx1.sendIdx["on:send:to:"]=1;
 $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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"observeModel",{},globals.HLDocumentationWidget)})},
 args: [],
 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"],
 messageSends: ["on:send:to:", "announcer", "model"],
-referencedClasses: ["HLClassSelected", "HLEditComment"]
+referencedClasses: ["HLClassSelected", "HLEditComment", "HLDocumentationFocusRequested"]
 }),
 }),
 globals.HLDocumentationWidget);
 globals.HLDocumentationWidget);
 
 
@@ -2294,15 +2330,24 @@ protocol: 'reactions',
 fn: function (anAnnouncement){
 fn: function (anAnnouncement){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 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();
 self._refresh();
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"onClassCommentChanged:",{anAnnouncement:anAnnouncement},globals.HLDocumentationWidget)})},
 return self}, function($ctx1) {$ctx1.fill(self,"onClassCommentChanged:",{anAnnouncement:anAnnouncement},globals.HLDocumentationWidget)})},
 args: ["anAnnouncement"],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLDocumentationWidget);
 globals.HLDocumentationWidget);
@@ -2323,6 +2368,22 @@ referencedClasses: []
 }),
 }),
 globals.HLDocumentationWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "onEditDocumentation",
 selector: "onEditDocumentation",
@@ -3133,6 +3194,22 @@ referencedClasses: []
 }),
 }),
 globals.HLMethodsListWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "selectItem:",
 selector: "selectItem:",
@@ -3261,22 +3338,6 @@ globals.HLMethodsListWidget.klass);
 
 
 smalltalk.addClass('HLPackagesListWidget', globals.HLToolListWidget, [], 'Helios-Browser');
 smalltalk.addClass('HLPackagesListWidget', globals.HLToolListWidget, [], 'Helios-Browser');
 globals.HLPackagesListWidget.comment="I render a list of the system packages.";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "cssClassForItem:",
 selector: "cssClassForItem:",
@@ -3515,6 +3576,22 @@ referencedClasses: []
 }),
 }),
 globals.HLPackagesListWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "selectItem:",
 selector: "selectItem:",
@@ -3808,6 +3885,22 @@ referencedClasses: []
 }),
 }),
 globals.HLProtocolsListWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "selectItem:",
 selector: "selectItem:",

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

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

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

@@ -49,6 +49,26 @@ label
 	^ 'Classes'
 	^ '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
 HLBrowserGoToCommand subclass: #HLGoToMethodsCommand
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Helios-Commands-Browser'!
 	package: 'Helios-Commands-Browser'!

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

@@ -768,6 +768,58 @@ referencedClasses: []
 globals.HLOpenBrowserCommand.klass);
 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.addClass('HLOpenWorkspaceCommand', globals.HLOpenCommand, [], 'Helios-Commands-Core');
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({

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

@@ -253,6 +253,26 @@ label
 	^ 'Browser'
 	^ '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
 HLOpenCommand subclass: #HLOpenWorkspaceCommand
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Helios-Commands-Core'!
 	package: 'Helios-Commands-Core'!

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

@@ -157,6 +157,28 @@ referencedClasses: []
 }),
 }),
 globals.HLCommitPackageCommand);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "execute",
 selector: "execute",
@@ -164,15 +186,35 @@ protocol: 'executing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-_st(self._model())._commitPackage();
+self._commitPackage();
 return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLCommitPackageCommand)})},
 return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLCommitPackageCommand)})},
 args: [],
 args: [],
-source: "execute\x0a\x09self model commitPackage",
-messageSends: ["commitPackage", "model"],
+source: "execute\x0a\x09self commitPackage",
+messageSends: ["commitPackage"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.HLCommitPackageCommand);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isActive",
 selector: "isActive",
@@ -182,12 +224,29 @@ var self=this;
 return true;
 return true;
 },
 },
 args: [],
 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: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.HLCommitPackageCommand);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -277,12 +336,12 @@ fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-$1=_st(_st(self._model())._selectedClass())._name();
+$1=_st(_st(_st(self._model())._selectedClass())._theNonMetaClass())._name();
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"defaultInput",{},globals.HLCopyClassCommand)})},
 }, function($ctx1) {$ctx1.fill(self,"defaultInput",{},globals.HLCopyClassCommand)})},
 args: [],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLCopyClassCommand);
 globals.HLCopyClassCommand);

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

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

File diff suppressed because it is too large
+ 558 - 164
src/Helios-Core.js


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

@@ -39,7 +39,8 @@ systemAnnouncer
 withChangesDo: aBlock
 withChangesDo: aBlock
 	[ 
 	[ 
 		self announcer announce: (HLAboutToChange new
 		self announcer announce: (HLAboutToChange new
-			actionBlock: aBlock).
+			actionBlock: aBlock;
+			yourself).
 		aBlock value.
 		aBlock value.
 	]
 	]
 		on: HLChangeForbidden 
 		on: HLChangeForbidden 
@@ -60,6 +61,36 @@ isToolModel
 	^ false
 	^ 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
 HLModel subclass: #HLToolModel
 	instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
 	instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
 	package: 'Helios-Core'!
 	package: 'Helios-Core'!
@@ -92,6 +123,34 @@ availableProtocols
 	^ self environment availableProtocolsFor: self selectedClass
 	^ 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
 packageToCommit
 	"Answer the package to commit depending on the context:
 	"Answer the package to commit depending on the context:
 	- if a Method is selected, answer its package
 	- if a Method is selected, answer its package
@@ -200,8 +259,11 @@ saveSourceCode
 
 
 !HLToolModel methodsFor: 'commands actions'!
 !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
 copyClassTo: aClassName
@@ -574,6 +636,10 @@ I provide common methods, additional behavior to widgets useful for Helios, like
 
 
 !HLWidget methodsFor: 'accessing'!
 !HLWidget methodsFor: 'accessing'!
 
 
+cssClass
+	^ 'hl_widget'
+!
+
 manager
 manager
 	^ HLManager current
 	^ HLManager current
 !
 !
@@ -592,12 +658,23 @@ confirm: aString ifTrue: aBlock
 	self manager 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
 execute: aCommand
 	HLManager current keyBinder
 	HLManager current keyBinder
 		activate;
 		activate;
 		applyBinding: aCommand asBinding
 		applyBinding: aCommand asBinding
 !
 !
 
 
+inform: aString
+	self manager inform: aString
+!
+
 openAsTab
 openAsTab
 	HLManager current addTab: (HLTabWidget on: self labelled: self class tabLabel)
 	HLManager current addTab: (HLTabWidget on: self labelled: self class tabLabel)
 !
 !
@@ -645,7 +722,9 @@ renderContentOn: html
 !
 !
 
 
 renderOn: html
 renderOn: html
-	wrapper := html div.
+	wrapper := html div
+		class: self cssClass;
+		yourself.
     [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
     [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
 ! !
 ! !
 
 
@@ -729,7 +808,7 @@ renderContentOn: html
 
 
 renderOn: html
 renderOn: html
     wrapper := html div 
     wrapper := html div 
-    	class: 'hl_widget';
+    	class: self cssClass;
 		yourself.
 		yourself.
 		
 		
        wrapper with: [ self renderContentOn: html ].
        wrapper with: [ self renderContentOn: html ].
@@ -850,11 +929,19 @@ focus
 		self selectedItem ifNil: [ self activateFirstListItem ] ]
 		self selectedItem ifNil: [ self activateFirstListItem ] ]
 !
 !
 
 
+reactivateListItem: aListItem
+	self activateListItem: aListItem.
+	self reselectItem: self selectedItem
+!
+
 refresh
 refresh
 	super refresh.
 	super refresh.
 	self selectedItem ifNotNil: [self ensureVisible: (self findListItemFor: self selectedItem)].
 	self selectedItem ifNotNil: [self ensureVisible: (self findListItemFor: self selectedItem)].
 !
 !
 
 
+reselectItem: anObject
+!
+
 selectItem: anObject
 selectItem: anObject
 	self selectedItem: anObject
 	self selectedItem: anObject
 ! !
 ! !
@@ -871,7 +958,11 @@ setupKeyBindings
 	(HLRepeatedKeyDownHandler on: self)
 	(HLRepeatedKeyDownHandler on: self)
 		whileKeyDown: 38 do: [ self activatePreviousListItem ];
 		whileKeyDown: 38 do: [ self activatePreviousListItem ];
 		whileKeyDown: 40 do: [ self activateNextListItem ];
 		whileKeyDown: 40 do: [ self activateNextListItem ];
-		rebindKeys
+		rebindKeys.
+		
+	self wrapper asJQuery keydown: [ :e |
+        e which = 13 ifTrue: [ 
+        	self reselectItem: self selectedItem ] ]
 ! !
 ! !
 
 
 !HLListWidget methodsFor: 'rendering'!
 !HLListWidget methodsFor: 'rendering'!
@@ -902,7 +993,7 @@ renderItem: anObject on: html
             		(html tag: 'i') class: (self cssClassForItem: anObject).
             		(html tag: 'i') class: (self cssClassForItem: anObject).
   					self renderItemLabel: anObject on: html ];
   					self renderItemLabel: anObject on: html ];
 				onClick: [
 				onClick: [
-                  	self activateListItem: li asJQuery ] ]
+                  	self reactivateListItem: li asJQuery ] ]
 !
 !
 
 
 renderItemLabel: anObject on: html
 renderItemLabel: anObject on: html
@@ -1024,6 +1115,10 @@ observeModel
 observeSystem
 observeSystem
 !
 !
 
 
+reactivateListItem: anItem
+	self model withChangesDo: [ super reactivateListItem: anItem ]
+!
+
 unregister
 unregister
 	super unregister.
 	super unregister.
 	
 	
@@ -1058,7 +1153,7 @@ renderMenuOn: html
 			html a
 			html a
 				class: 'btn dropdown-toggle';
 				class: 'btn dropdown-toggle';
 				at: 'data-toggle' put: 'dropdown';
 				at: 'data-toggle' put: 'dropdown';
-				with: [ (html tag: 'i') class: 'icon-cog' ].
+				with: [ (html tag: 'i') class: 'icon-chevron-down' ].
 		html ul 
 		html ul 
 			class: 'dropdown-menu pull-right';
 			class: 'dropdown-menu pull-right';
 			with: [ 
 			with: [ 
@@ -1178,16 +1273,30 @@ addToHistory: aTab
 !
 !
 
 
 confirm: aString ifFalse: aBlock
 confirm: aString ifFalse: aBlock
-	HLConfirmationWidget new
-		confirmationString: aString;
-		cancelBlock: aBlock;
-		show
+	self 
+		confirm: aString
+		ifTrue: []
+		ifFalse: aBlock
 !
 !
 
 
 confirm: aString ifTrue: aBlock
 confirm: aString ifTrue: aBlock
+	self 
+		confirm: aString
+		ifTrue: aBlock
+		ifFalse: []
+!
+
+confirm: aString ifTrue: aBlock ifFalse: anotherBlock
 	HLConfirmationWidget new
 	HLConfirmationWidget new
 		confirmationString: aString;
 		confirmationString: aString;
 		actionBlock: aBlock;
 		actionBlock: aBlock;
+		cancelBlock: anotherBlock;
+		show
+!
+
+inform: aString
+	HLInformationWidget new
+		informationString: aString;
 		show
 		show
 !
 !
 
 
@@ -1245,7 +1354,9 @@ defaultEnvironment
 !HLManager methodsFor: 'initialization'!
 !HLManager methodsFor: 'initialization'!
 
 
 setup
 setup
-	self registerServices.
+	self 
+		registerServices;
+		setupEvents.
     self keyBinder 
     self keyBinder 
 		setupEvents;
 		setupEvents;
 		setupHelper
 		setupHelper
@@ -1258,16 +1369,24 @@ registerServices
 		registerInspector;
 		registerInspector;
 		registerErrorHandler;
 		registerErrorHandler;
 		registerProgressHandler;
 		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'!
 !HLManager methodsFor: 'rendering'!
 
 
-refresh
-	'.navbar' asJQuery remove.
-	self appendToJQuery: 'body' asJQuery
-!
-
 renderAddOn: html
 renderAddOn: html
     html li 
     html li 
     	class: 'dropdown';
     	class: 'dropdown';
@@ -1330,6 +1449,11 @@ registerErrorHandler
 	ErrorHandler register: HLErrorHandler new
 	ErrorHandler register: HLErrorHandler new
 !
 !
 
 
+registerFinder
+	self environment registerFinder: HLFinder new.
+	Finder register: HLFinder new
+!
+
 registerInspector
 registerInspector
 	self environment registerInspector: HLInspector.
 	self environment registerInspector: HLInspector.
 	Inspector register: HLInspector
 	Inspector register: HLInspector
@@ -1374,28 +1498,13 @@ HLWidget subclass: #HLModalWidget
 !HLModalWidget commentStamp!
 !HLModalWidget commentStamp!
 I implement an abstract modal widget.!
 I implement an abstract modal widget.!
 
 
-!HLModalWidget methodsFor: 'accessing'!
-
-cssClass
-	^ ''
-! !
-
 !HLModalWidget methodsFor: 'actions'!
 !HLModalWidget methodsFor: 'actions'!
 
 
-cancel
-	self remove
-!
-
-confirm
-	"Override in subclasses"
-	self remove
-!
-
 remove
 remove
 	'.dialog' asJQuery removeClass: 'active'.
 	'.dialog' asJQuery removeClass: 'active'.
 	[ 
 	[ 
 		'#overlay' asJQuery remove.
 		'#overlay' asJQuery remove.
-		'.dialog' asJQuery remove
+		wrapper asJQuery remove
 	] valueWithTimeout: 300
 	] valueWithTimeout: 300
 !
 !
 
 
@@ -1416,27 +1525,13 @@ hasButtons
 !
 !
 
 
 renderButtonsOn: html
 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
 renderContentOn: html
 	| confirmButton |
 	| confirmButton |
 	
 	
 	html div id: 'overlay'.
 	html div id: 'overlay'.
+	
 	html div 
 	html div 
 		class: 'dialog ', self cssClass;
 		class: 'dialog ', self cssClass;
 		with: [
 		with: [
@@ -1457,12 +1552,14 @@ setupKeyBindings
 ! !
 ! !
 
 
 HLModalWidget subclass: #HLConfirmationWidget
 HLModalWidget subclass: #HLConfirmationWidget
-	instanceVariableNames: 'confirmationString actionBlock cancelBlock'
+	instanceVariableNames: 'cancelButtonLabel confirmButtonLabel confirmationString actionBlock cancelBlock'
 	package: 'Helios-Core'!
 	package: 'Helios-Core'!
 !HLConfirmationWidget commentStamp!
 !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'!
 !HLConfirmationWidget methodsFor: 'accessing'!
 
 
@@ -1482,6 +1579,22 @@ cancelBlock: aBlock
 	cancelBlock := aBlock
 	cancelBlock := aBlock
 !
 !
 
 
+cancelButtonLabel
+	^ cancelButtonLabel ifNil: [ 'Cancel' ]
+!
+
+cancelButtonLabel: aString
+	^ cancelButtonLabel := aString
+!
+
+confirmButtonLabel
+	^ confirmButtonLabel ifNil: [ 'Confirm' ]
+!
+
+confirmButtonLabel: aString
+	^ confirmButtonLabel := aString
+!
+
 confirmationString
 confirmationString
 	^ confirmationString ifNil: [ 'Confirm' ]
 	^ confirmationString ifNil: [ 'Confirm' ]
 !
 !
@@ -1494,30 +1607,60 @@ confirmationString: aString
 
 
 cancel
 cancel
 	self cancelBlock value.
 	self cancelBlock value.
-	super cancel
+	self remove
 !
 !
 
 
 confirm
 confirm
-	super confirm.
+	self remove.
 	self actionBlock value
 	self actionBlock value
 ! !
 ! !
 
 
 !HLConfirmationWidget methodsFor: 'rendering'!
 !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
 renderMainOn: html
-	html span with: self confirmationString
+	html span 
+		class: 'head'; 
+		with: self confirmationString
 ! !
 ! !
 
 
 HLConfirmationWidget subclass: #HLRequestWidget
 HLConfirmationWidget subclass: #HLRequestWidget
-	instanceVariableNames: 'input value'
+	instanceVariableNames: 'input multiline value'
 	package: 'Helios-Core'!
 	package: 'Helios-Core'!
 !HLRequestWidget commentStamp!
 !HLRequestWidget commentStamp!
 I display a modal window requesting user input.
 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'!
 !HLRequestWidget methodsFor: 'accessing'!
 
 
+beMultiline
+	multiline := true
+!
+
+beSingleline
+	multiline := false
+!
+
 cssClass
 cssClass
 	^ 'large'
 	^ 'large'
 !
 !
@@ -1533,8 +1676,10 @@ value: aString
 !HLRequestWidget methodsFor: 'actions'!
 !HLRequestWidget methodsFor: 'actions'!
 
 
 confirm
 confirm
-	super confirm.
-	self actionBlock value: input asJQuery val
+	| val |
+	val := input asJQuery val.
+	self remove.
+	self actionBlock value: val
 ! !
 ! !
 
 
 !HLRequestWidget methodsFor: 'private'!
 !HLRequestWidget methodsFor: 'private'!
@@ -1546,12 +1691,72 @@ giveFocusToButton: aButton
 
 
 renderMainOn: html
 renderMainOn: html
 	super 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 
 	input asJQuery 
 		val: self value;
 		val: self value;
 		focus
 		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
 HLModalWidget subclass: #HLProgressWidget
 	instanceVariableNames: 'progressBars visible'
 	instanceVariableNames: 'progressBars visible'
 	package: 'Helios-Core'!
 	package: 'Helios-Core'!
@@ -1838,27 +2043,3 @@ default
 	^ default ifNil: [ default := self new ]
 	^ 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "codeWidget",
 selector: "codeWidget",
-protocol: 'accessing',
+protocol: 'widgets',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 function $HLDebuggerCodeWidget(){return globals.HLDebuggerCodeWidget||(typeof HLDebuggerCodeWidget=="undefined"?nil:HLDebuggerCodeWidget)}
 function $HLDebuggerCodeWidget(){return globals.HLDebuggerCodeWidget||(typeof HLDebuggerCodeWidget=="undefined"?nil:HLDebuggerCodeWidget)}
@@ -144,6 +144,24 @@ referencedClasses: ["HLDebuggerCodeWidget", "HLDebuggerCodeModel"]
 }),
 }),
 globals.HLDebugger);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "focus",
 selector: "focus",
@@ -162,17 +180,17 @@ globals.HLDebugger);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "initializeFromMethodContext:",
-protocol: 'accessing',
-fn: function (aMethodContext){
+selector: "initializeFromError:",
+protocol: 'initialization',
+fn: function (anError){
 var self=this;
 var self=this;
 function $HLDebuggerModel(){return globals.HLDebuggerModel||(typeof HLDebuggerModel=="undefined"?nil:HLDebuggerModel)}
 function $HLDebuggerModel(){return globals.HLDebuggerModel||(typeof HLDebuggerModel=="undefined"?nil:HLDebuggerModel)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-self["@model"]=_st($HLDebuggerModel())._on_(aMethodContext);
+self["@model"]=_st($HLDebuggerModel())._on_(anError);
 self._observeModel();
 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"],
 messageSends: ["on:", "observeModel"],
 referencedClasses: ["HLDebuggerModel"]
 referencedClasses: ["HLDebuggerModel"]
 }),
 }),
@@ -181,7 +199,7 @@ globals.HLDebugger);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "inspectorWidget",
 selector: "inspectorWidget",
-protocol: 'accessing',
+protocol: 'widgets',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 function $HLInspectorWidget(){return globals.HLInspectorWidget||(typeof HLInspectorWidget=="undefined"?nil:HLInspectorWidget)}
 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)}
 function $HLVerticalSplitter(){return globals.HLVerticalSplitter||(typeof HLVerticalSplitter=="undefined"?nil:HLVerticalSplitter)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
+self._renderHeadOn_(html);
 $2=_st($HLHorizontalSplitter())._with_with_(self._stackListWidget(),_st($HLVerticalSplitter())._with_with_(self._codeWidget(),self._inspectorWidget()));
 $2=_st($HLHorizontalSplitter())._with_with_(self._stackListWidget(),_st($HLVerticalSplitter())._with_with_(self._codeWidget(),self._inspectorWidget()));
 $ctx1.sendIdx["with:with:"]=1;
 $ctx1.sendIdx["with:with:"]=1;
 $1=_st($HLContainer())._with_($2);
 $1=_st($HLContainer())._with_($2);
@@ -305,16 +324,39 @@ _st(html)._with_($1);
 $ctx1.sendIdx["with:"]=1;
 $ctx1.sendIdx["with:"]=1;
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLDebugger)})},
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLDebugger)})},
 args: ["html"],
 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"]
 referencedClasses: ["HLContainer", "HLHorizontalSplitter", "HLVerticalSplitter"]
 }),
 }),
 globals.HLDebugger);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "stackListWidget",
 selector: "stackListWidget",
-protocol: 'accessing',
+protocol: 'widgets',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 function $HLStackListWidget(){return globals.HLStackListWidget||(typeof HLStackListWidget=="undefined"?nil:HLStackListWidget)}
 function $HLStackListWidget(){return globals.HLStackListWidget||(typeof HLStackListWidget=="undefined"?nil:HLStackListWidget)}
@@ -362,19 +404,19 @@ smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "on:",
 selector: "on:",
 protocol: 'instance creation',
 protocol: 'instance creation',
-fn: function (aMethodContext){
+fn: function (anError){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
 var $2,$3,$1;
 $2=self._new();
 $2=self._new();
-_st($2)._initializeFromMethodContext_(aMethodContext);
+_st($2)._initializeFromError_(anError);
 $3=_st($2)._yourself();
 $3=_st($2)._yourself();
 $1=$3;
 $1=$3;
 return $1;
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLDebugger.klass);
 globals.HLDebugger.klass);
@@ -449,15 +491,23 @@ selector: "doIt:",
 protocol: 'actions',
 protocol: 'actions',
 fn: function (aString){
 fn: function (aString){
 var self=this;
 var self=this;
+function $ErrorHandler(){return globals.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 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;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLDebuggerCodeModel)})},
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLDebuggerCodeModel)})},
 args: ["aString"],
 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);
 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.";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -719,6 +769,38 @@ referencedClasses: ["HLDebuggerContextSelected"]
 }),
 }),
 globals.HLDebuggerModel);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "evaluate:",
 selector: "evaluate:",
@@ -804,6 +886,32 @@ referencedClasses: ["AIContext"]
 }),
 }),
 globals.HLDebuggerModel);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "interpreter",
 selector: "interpreter",
@@ -948,19 +1056,19 @@ smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "on:",
 selector: "on:",
 protocol: 'instance creation',
 protocol: 'instance creation',
-fn: function (aMethodContext){
+fn: function (anError){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
 var $2,$3,$1;
 $2=self._new();
 $2=self._new();
-_st($2)._initializeFromContext_(aMethodContext);
+_st($2)._initializeFromError_(anError);
 $3=_st($2)._yourself();
 $3=_st($2)._yourself();
 $1=$3;
 $1=$3;
 return $1;
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLDebuggerModel.klass);
 globals.HLDebuggerModel.klass);
@@ -969,27 +1077,68 @@ globals.HLDebuggerModel.klass);
 smalltalk.addClass('HLErrorHandler', globals.Object, [], 'Helios-Debugger');
 smalltalk.addClass('HLErrorHandler', globals.Object, [], 'Helios-Debugger');
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 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',
 protocol: 'error handling',
 fn: function (anError){
 fn: function (anError){
 var self=this;
 var self=this;
 function $HLDebugger(){return globals.HLDebugger||(typeof HLDebugger=="undefined"?nil:HLDebugger)}
 function $HLDebugger(){return globals.HLDebugger||(typeof HLDebugger=="undefined"?nil:HLDebugger)}
 function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
 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) { 
 return smalltalk.withContext(function($ctx1) { 
-self._onErrorHandled();
 _st((function(){
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
 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){
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(error){
 return smalltalk.withContext(function($ctx2) {
 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)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"handleError:",{anError:anError},globals.HLErrorHandler)})},
 args: ["anError"],
 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);
 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'!
 !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
 	^ model ifNil: [ model := HLDebuggerModel new ]
 	^ model ifNil: [ model := HLDebuggerModel new ]
-!
-
-stackListWidget
-	^ stackListWidget ifNil: [ 
-		stackListWidget := (HLStackListWidget on: self model)
-			next: self codeWidget;
-			yourself ]
 ! !
 ! !
 
 
 !HLDebugger methodsFor: 'actions'!
 !HLDebugger methodsFor: 'actions'!
@@ -104,6 +82,13 @@ unregister
 	self inspectorWidget unregister
 	self inspectorWidget unregister
 ! !
 ! !
 
 
+!HLDebugger methodsFor: 'initialization'!
+
+initializeFromError: anError
+	model := HLDebuggerModel on: anError.
+	self observeModel
+! !
+
 !HLDebugger methodsFor: 'keybindings'!
 !HLDebugger methodsFor: 'keybindings'!
 
 
 registerBindingsOn: aBindingGroup
 registerBindingsOn: aBindingGroup
@@ -121,11 +106,41 @@ onContextSelected: anAnnouncement
 !HLDebugger methodsFor: 'rendering'!
 !HLDebugger methodsFor: 'rendering'!
 
 
 renderContentOn: html
 renderContentOn: html
+	self renderHeadOn: html.
 	html with: (HLContainer with: (HLHorizontalSplitter
 	html with: (HLContainer with: (HLHorizontalSplitter
 		with: self stackListWidget
 		with: self stackListWidget
 		with: (HLVerticalSplitter
 		with: (HLVerticalSplitter
 			with: self codeWidget
 			with: self codeWidget
 			with: self inspectorWidget)))
 			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'!
 !HLDebugger class methodsFor: 'accessing'!
@@ -140,9 +155,9 @@ tabLabel
 
 
 !HLDebugger class methodsFor: 'instance creation'!
 !HLDebugger class methodsFor: 'instance creation'!
 
 
-on: aMethodContext
+on: anError
 	^ self new
 	^ self new
-		initializeFromMethodContext: aMethodContext;
+		initializeFromError: anError;
 		yourself
 		yourself
 ! !
 ! !
 
 
@@ -163,7 +178,11 @@ debuggerModel: anObject
 !HLDebuggerCodeModel methodsFor: 'actions'!
 !HLDebuggerCodeModel methodsFor: 'actions'!
 
 
 doIt: aString
 doIt: aString
-	^ self debuggerModel evaluate: aString
+	^ self 
+		try: [ self debuggerModel evaluate: aString ]
+		catch: [ :e | 
+			ErrorHandler handleError: e.
+			nil ]
 ! !
 ! !
 
 
 HLBrowserCodeWidget subclass: #HLDebuggerCodeWidget
 HLBrowserCodeWidget subclass: #HLDebuggerCodeWidget
@@ -239,7 +258,7 @@ onContextSelected
 ! !
 ! !
 
 
 HLToolModel subclass: #HLDebuggerModel
 HLToolModel subclass: #HLDebuggerModel
-	instanceVariableNames: 'rootContext currentContext contexts'
+	instanceVariableNames: 'rootContext currentContext contexts error'
 	package: 'Helios-Debugger'!
 	package: 'Helios-Debugger'!
 !HLDebuggerModel commentStamp!
 !HLDebuggerModel commentStamp!
 I am a model for debugging Amber code in Helios.
 I am a model for debugging Amber code in Helios.
@@ -266,6 +285,14 @@ currentContext: aContext
 			yourself) ]
 			yourself) ]
 !
 !
 
 
+error
+	^ error
+!
+
+error: anError
+	error := anError
+!
+
 interpreter
 interpreter
 	^ self currentContext interpreter
 	^ self currentContext interpreter
 !
 !
@@ -337,6 +364,14 @@ initializeContexts
 initializeFromContext: aMethodContext
 initializeFromContext: aMethodContext
 	rootContext := (AIContext fromMethodContext: aMethodContext).
 	rootContext := (AIContext fromMethodContext: aMethodContext).
 	self initializeContexts
 	self initializeContexts
+!
+
+initializeFromError: anError
+	error := anError.
+	console log: error.
+	console log: error context.
+	rootContext := (AIContext fromMethodContext: error context).
+	self initializeContexts
 ! !
 ! !
 
 
 !HLDebuggerModel methodsFor: 'private'!
 !HLDebuggerModel methodsFor: 'private'!
@@ -352,9 +387,9 @@ flushInnerContexts
 
 
 !HLDebuggerModel class methodsFor: 'instance creation'!
 !HLDebuggerModel class methodsFor: 'instance creation'!
 
 
-on: aMethodContext
+on: anError
 	^ self new
 	^ self new
-		initializeFromContext: aMethodContext;
+		initializeFromError: anError;
 		yourself
 		yourself
 ! !
 ! !
 
 
@@ -364,14 +399,26 @@ Object subclass: #HLErrorHandler
 
 
 !HLErrorHandler methodsFor: 'error handling'!
 !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 
 		on: Error 
-		do: [ :error | ErrorHandler new handleError: error ]
+		do: [ :error | ConsoleErrorHandler new handleError: error ]
+!
+
+handleError: anError
+	self confirmDebugError: anError
 !
 !
 
 
 onErrorHandled
 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');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "class:",
 selector: "class:",
@@ -716,7 +716,7 @@ globals.HLMethodGenerator);
 
 
 
 
 smalltalk.addClass('HLAccessorsGenerator', globals.HLMethodGenerator, [], 'Helios-Helpers');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "accessorProtocolForObject",
 selector: "accessorProtocolForObject",
@@ -846,7 +846,7 @@ globals.HLAccessorsGenerator);
 
 
 
 
 smalltalk.addClass('HLInitializeGenerator', globals.HLMethodGenerator, [], 'Helios-Helpers');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "generate",
 selector: "generate",
@@ -982,7 +982,7 @@ globals.HLInitializeGenerator);
 
 
 
 
 smalltalk.addClass('HLMethodSourceCode', globals.Object, ['selector', 'sourceCode'], 'Helios-Helpers');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "selector",
 selector: "selector",
@@ -1048,4 +1048,168 @@ referencedClasses: []
 globals.HLMethodSourceCode);
 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!
 !HLMethodGenerator commentStamp!
 I am the abstract super class of the method generators.
 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'!
 !HLMethodGenerator methodsFor: 'accessing'!
 
 
@@ -307,7 +307,7 @@ HLMethodGenerator subclass: #HLAccessorsGenerator
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Helios-Helpers'!
 	package: 'Helios-Helpers'!
 !HLAccessorsGenerator commentStamp!
 !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'!
 !HLAccessorsGenerator methodsFor: 'double-dispatch'!
 
 
@@ -360,16 +360,14 @@ HLMethodGenerator subclass: #HLInitializeGenerator
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Helios-Helpers'!
 	package: 'Helios-Helpers'!
 !HLInitializeGenerator commentStamp!
 !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
     ^ HLInitializeGenerator new
         class: aClass;
         class: aClass;
         generate;
         generate;
-        output
-
-I am a disposable object!
+        output!
 
 
 !HLInitializeGenerator methodsFor: 'double-dispatch'!
 !HLInitializeGenerator methodsFor: 'double-dispatch'!
 
 
@@ -417,7 +415,7 @@ Object subclass: #HLMethodSourceCode
 	instanceVariableNames: 'selector sourceCode'
 	instanceVariableNames: 'selector sourceCode'
 	package: 'Helios-Helpers'!
 	package: 'Helios-Helpers'!
 !HLMethodSourceCode commentStamp!
 !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'!
 !HLMethodSourceCode methodsFor: 'accessing'!
 
 
@@ -437,3 +435,67 @@ sourceCode: aString
 	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.addPackage('Helios-Inspector');
 smalltalk.packages["Helios-Inspector"].transport = {"type":"amd","amdNamespace":"amber_core"};
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "model",
+selector: "inspector",
 protocol: 'accessing',
 protocol: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var $1;
 var $1;
-$1=self["@model"];
+$1=self["@inspector"];
 return $1;
 return $1;
 },
 },
 args: [],
 args: [],
-source: "model\x0a\x0a\x09^ model",
+source: "inspector\x0a\x09^ inspector",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -22,19 +22,37 @@ globals.HLInspectorDisplayWidget);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "model:",
+selector: "inspector:",
 protocol: 'accessing',
 protocol: 'accessing',
-fn: function (aModel){
+fn: function (anInspector){
 var self=this;
 var self=this;
-self["@model"]=aModel;
+self["@inspector"]=anInspector;
 return self},
 return self},
-args: ["aModel"],
-source: "model: aModel\x0a\x0a\x09model := aModel",
+args: ["anInspector"],
+source: "inspector: anInspector\x0a\x09inspector := anInspector",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.HLInspectorDisplayWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "renderContentOn:",
 selector: "renderContentOn:",
@@ -59,51 +77,32 @@ fn: function (){
 var self=this;
 var self=this;
 var selection;
 var selection;
 return smalltalk.withContext(function($ctx1) { 
 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 {
 } else {
-$1="";
+$2="";
 };
 };
-return $1;
+return $2;
 }, function($ctx1) {$ctx1.fill(self,"selectionDisplayString",{selection:selection},globals.HLInspectorDisplayWidget)})},
 }, function($ctx1) {$ctx1.fill(self,"selectionDisplayString",{selection:selection},globals.HLInspectorDisplayWidget)})},
 args: [],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLInspectorDisplayWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "code",
 selector: "code",
@@ -129,45 +128,6 @@ referencedClasses: ["HLCodeModel"]
 }),
 }),
 globals.HLInspectorModel);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "inspect:on:",
 selector: "inspect:on:",
@@ -427,7 +387,7 @@ referencedClasses: []
 globals.HLInspectorModel.klass);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "announcer",
 selector: "announcer",
@@ -473,34 +433,33 @@ globals.HLInspectorVariablesWidget);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "label",
-protocol: 'accessing',
+selector: "dive",
+protocol: 'actions',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
+function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 return smalltalk.withContext(function($ctx1) { 
 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: [],
 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);
 globals.HLInspectorVariablesWidget);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "model",
+selector: "inspector",
 protocol: 'accessing',
 protocol: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var $1;
 var $1;
-$1=self["@model"];
+$1=self["@inspector"];
 return $1;
 return $1;
 },
 },
 args: [],
 args: [],
-source: "model\x0a    ^ model",
+source: "inspector\x0a\x09^ inspector",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -508,19 +467,55 @@ globals.HLInspectorVariablesWidget);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "model:",
+selector: "inspector:",
 protocol: 'accessing',
 protocol: 'accessing',
-fn: function (aModel){
+fn: function (anInspector){
 var self=this;
 var self=this;
-self["@model"]=aModel;
+self["@inspector"]=anInspector;
 return self},
 return self},
-args: ["aModel"],
-source: "model: aModel\x0a    model := aModel",
+args: ["anInspector"],
+source: "inspector: anInspector\x0a\x09inspector := anInspector",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.HLInspectorVariablesWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "refresh",
 selector: "refresh",
@@ -548,7 +543,6 @@ selector: "renderButtonsOn:",
 protocol: 'rendering',
 protocol: 'rendering',
 fn: function (html){
 fn: function (html){
 var self=this;
 var self=this;
-function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 var $1,$2;
 $1=_st(html)._button();
 $1=_st(html)._button();
@@ -556,14 +550,14 @@ _st($1)._class_("btn");
 _st($1)._with_("Dive");
 _st($1)._with_("Dive");
 $2=_st($1)._onClick_((function(){
 $2=_st($1)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
-return _st(self._announcer())._announce_(_st($HLDiveRequested())._new());
+return self._dive();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 self["@diveButton"]=$2;
 self["@diveButton"]=$2;
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},globals.HLInspectorVariablesWidget)})},
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},globals.HLInspectorVariablesWidget)})},
 args: ["html"],
 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);
 globals.HLInspectorVariablesWidget);
 
 
@@ -576,10 +570,14 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 self._renderHeadOn_(html);
 self._renderHeadOn_(html);
 globals.HLInspectorVariablesWidget.superclass.fn.prototype._renderContentOn_.apply(_st(self), [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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLInspectorVariablesWidget)})},
 args: ["html"],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLInspectorVariablesWidget);
 globals.HLInspectorVariablesWidget);
@@ -682,14 +680,18 @@ fn: function (){
 var self=this;
 var self=this;
 function $HLCodeWidget(){return globals.HLCodeWidget||(typeof HLCodeWidget=="undefined"?nil:HLCodeWidget)}
 function $HLCodeWidget(){return globals.HLCodeWidget||(typeof HLCodeWidget=="undefined"?nil:HLCodeWidget)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$1;
+var $2,$3,$4,$6,$5,$7,$1;
 $2=self["@codeWidget"];
 $2=self["@codeWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLCodeWidget())._new();
 $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"];
 $1=self["@codeWidget"];
 } else {
 } else {
 $1=$2;
 $1=$2;
@@ -697,8 +699,8 @@ $1=$2;
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"codeWidget",{},globals.HLInspectorWidget)})},
 }, function($ctx1) {$ctx1.fill(self,"codeWidget",{},globals.HLInspectorWidget)})},
 args: [],
 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"]
 referencedClasses: ["HLCodeWidget"]
 }),
 }),
 globals.HLInspectorWidget);
 globals.HLInspectorWidget);
@@ -715,7 +717,7 @@ var $2,$3,$4,$1;
 $2=self["@displayWidget"];
 $2=self["@displayWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLInspectorDisplayWidget())._new();
 $3=_st($HLInspectorDisplayWidget())._new();
-_st($3)._model_(self._model());
+_st($3)._inspector_(self);
 $4=_st($3)._yourself();
 $4=_st($3)._yourself();
 self["@displayWidget"]=$4;
 self["@displayWidget"]=$4;
 $1=self["@displayWidget"];
 $1=self["@displayWidget"];
@@ -725,8 +727,8 @@ $1=$2;
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"displayWidget",{},globals.HLInspectorWidget)})},
 }, function($ctx1) {$ctx1.fill(self,"displayWidget",{},globals.HLInspectorWidget)})},
 args: [],
 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"]
 referencedClasses: ["HLInspectorDisplayWidget"]
 }),
 }),
 globals.HLInspectorWidget);
 globals.HLInspectorWidget);
@@ -911,14 +913,11 @@ fn: function (){
 var self=this;
 var self=this;
 function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 function $HLDiveRequested(){return globals.HLDiveRequested||(typeof HLDiveRequested=="undefined"?nil:HLDiveRequested)}
 return smalltalk.withContext(function($ctx1) { 
 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"observeVariablesWidget",{},globals.HLInspectorWidget)})},
 args: [],
 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"]
 referencedClasses: ["HLDiveRequested"]
 }),
 }),
 globals.HLInspectorWidget);
 globals.HLInspectorWidget);
@@ -937,7 +936,7 @@ _st($1)._inspect_(_st(self._model())._selectedInstVarObject());
 $2=_st($1)._openAsTab();
 $2=_st($1)._openAsTab();
 return self}, function($ctx1) {$ctx1.fill(self,"onDive",{},globals.HLInspectorWidget)})},
 return self}, function($ctx1) {$ctx1.fill(self,"onDive",{},globals.HLInspectorWidget)})},
 args: [],
 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"],
 messageSends: ["inspect:", "new", "selectedInstVarObject", "model", "openAsTab"],
 referencedClasses: ["HLInspector"]
 referencedClasses: ["HLInspector"]
 }),
 }),
@@ -1166,7 +1165,7 @@ var $2,$3,$4,$1;
 $2=self["@variablesWidget"];
 $2=self["@variablesWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLInspectorVariablesWidget())._new();
 $3=_st($HLInspectorVariablesWidget())._new();
-_st($3)._model_(self._model());
+_st($3)._inspector_(self);
 $4=_st($3)._yourself();
 $4=_st($3)._yourself();
 self["@variablesWidget"]=$4;
 self["@variablesWidget"]=$4;
 $1=self["@variablesWidget"];
 $1=self["@variablesWidget"];
@@ -1176,8 +1175,8 @@ $1=$2;
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"variablesWidget",{},globals.HLInspectorWidget)})},
 }, function($ctx1) {$ctx1.fill(self,"variablesWidget",{},globals.HLInspectorWidget)})},
 args: [],
 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"]
 referencedClasses: ["HLInspectorVariablesWidget"]
 }),
 }),
 globals.HLInspectorWidget);
 globals.HLInspectorWidget);

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

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

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

@@ -1240,29 +1240,38 @@ protocol: 'events',
 fn: function (event){
 fn: function (event){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1,$4;
+var $3,$2,$6,$5,$4,$1,$7;
 $3=_st(event)._which();
 $3=_st(event)._which();
 $ctx1.sendIdx["which"]=1;
 $ctx1.sendIdx["which"]=1;
 $2=_st($3).__eq(self._escapeKey());
 $2=_st($3).__eq(self._escapeKey());
 $ctx1.sendIdx["="]=1;
 $ctx1.sendIdx["="]=1;
 $1=_st($2)._or_((function(){
 $1=_st($2)._or_((function(){
 return smalltalk.withContext(function($ctx2) {
 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 smalltalk.withContext(function($ctx3) {
-return _st(event)._ctrlKey();
+return _st(_st(event)._which()).__eq(self._activationKey());
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
 }, 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)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$ctx1.sendIdx["or:"]=1;
 if(smalltalk.assert($1)){
 if(smalltalk.assert($1)){
 self._deactivate();
 self._deactivate();
 _st(event)._preventDefault();
 _st(event)._preventDefault();
 return false;
 return false;
 };
 };
-$4=self._handleBindingFor_(event);
-return $4;
+$7=self._handleBindingFor_(event);
+return $7;
 }, function($ctx1) {$ctx1.fill(self,"handleActiveKeyDown:",{event:event},globals.HLKeyBinder)})},
 }, function($ctx1) {$ctx1.fill(self,"handleActiveKeyDown:",{event:event},globals.HLKeyBinder)})},
 args: ["event"],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLKeyBinder);
 globals.HLKeyBinder);
@@ -1583,11 +1592,11 @@ $1=_st(".".__comma(self._cssClass()))._asJQuery();
 $ctx1.sendIdx["asJQuery"]=1;
 $ctx1.sendIdx["asJQuery"]=1;
 _st($1)._remove();
 _st($1)._remove();
 $ctx1.sendIdx["remove"]=1;
 $ctx1.sendIdx["remove"]=1;
-_st("#overlay"._asJQuery())._remove();
+_st(".helper_overlay"._asJQuery())._remove();
 self._showCog();
 self._showCog();
 return self}, function($ctx1) {$ctx1.fill(self,"hide",{},globals.HLKeyBinderHelperWidget)})},
 return self}, function($ctx1) {$ctx1.fill(self,"hide",{},globals.HLKeyBinderHelperWidget)})},
 args: [],
 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"],
 messageSends: ["remove", "asJQuery", ",", "cssClass", "showCog"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -1793,7 +1802,7 @@ $1=_st(html)._div();
 $ctx1.sendIdx["div"]=1;
 $ctx1.sendIdx["div"]=1;
 _st($1)._id_("overlay");
 _st($1)._id_("overlay");
 $ctx1.sendIdx["id:"]=1;
 $ctx1.sendIdx["id:"]=1;
-_st($1)._class_("light");
+_st($1)._class_("helper_overlay");
 $ctx1.sendIdx["class:"]=1;
 $ctx1.sendIdx["class:"]=1;
 $2=_st($1)._onClick_((function(){
 $2=_st($1)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
@@ -1818,7 +1827,7 @@ $ctx1.sendIdx["with:"]=1;
 _st(":focus"._asJQuery())._blur();
 _st(":focus"._asJQuery())._blur();
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLKeyBinderHelperWidget)})},
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLKeyBinderHelperWidget)})},
 args: ["html"],
 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"],
 messageSends: ["id:", "div", "class:", "onClick:", "deactivate", "cssClass", "with:", "renderLabelOn:", "mainId", "renderSelectedBindingOn:", "renderCloseOn:", "blur", "asJQuery"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),

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

@@ -429,13 +429,14 @@ defaultBindings
 
 
 handleActiveKeyDown: event
 handleActiveKeyDown: event
 
 
-	"ESC or ctrl+g deactivate the keyBinder"
+	"ESC, ctrl+g ctrl+space deactivate the keyBinder"
 	(event which = self escapeKey or: [
 	(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"
     "Handle the keybinding"
     ^ self handleBindingFor: event
     ^ self handleBindingFor: event
@@ -542,7 +543,7 @@ deactivate
 
 
 hide
 hide
 	('.', self cssClass) asJQuery remove.
 	('.', self cssClass) asJQuery remove.
-	'#overlay' asJQuery remove.
+	'.helper_overlay' asJQuery remove.
 	self showCog
 	self showCog
 !
 !
 
 
@@ -607,7 +608,7 @@ renderCog
 renderContentOn: html
 renderContentOn: html
 	html div 
 	html div 
 		id: 'overlay';
 		id: 'overlay';
-		class: 'light';
+		class: 'helper_overlay';
 		onClick: [ self deactivate ].
 		onClick: [ self deactivate ].
 	
 	
 	html div class: self cssClass; with: [
 	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.addPackage('Helios-Layout');
 smalltalk.packages["Helios-Layout"].transport = {"type":"amd","amdNamespace":"amber_core"};
 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.packages["Helios-Transcript"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 
 smalltalk.addClass('HLTranscript', globals.HLWidget, ['textarea'], 'Helios-Transcript');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "clear",
 selector: "clear",
@@ -120,7 +120,7 @@ globals.HLTranscript);
 
 
 
 
 smalltalk.addClass('HLTranscriptHandler', globals.Object, [], 'Helios-Transcript');
 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'];
 globals.HLTranscriptHandler.klass.iVarNames = ['transcripts'];
 smalltalk.addMethod(
 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.
     Transcript clear.
 
 
-See the `Transcript` class.!
+See the `Transcript` service class.!
 
 
 !HLTranscript methodsFor: 'actions'!
 !HLTranscript methodsFor: 'actions'!
 
 
@@ -61,7 +61,7 @@ I handle transcript events, dispatching them to all instances of `HLTranscript`.
 
 
 ## API
 ## 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'!
 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);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "defaultReceiver",
 selector: "defaultReceiver",
@@ -52,15 +68,23 @@ selector: "doIt:",
 protocol: 'actions',
 protocol: 'actions',
 fn: function (aString){
 fn: function (aString){
 var self=this;
 var self=this;
+function $ErrorHandler(){return globals.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 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;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLCodeModel)})},
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLCodeModel)})},
 args: ["aString"],
 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);
 globals.HLCodeModel);
 
 
@@ -200,6 +224,38 @@ referencedClasses: []
 }),
 }),
 globals.HLCodeWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "canHaveFocus",
 selector: "canHaveFocus",
@@ -238,18 +294,31 @@ protocol: 'actions',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1;
+var $1,$2,$3;
 $1=self._editor();
 $1=self._editor();
 $ctx1.sendIdx["editor"]=1;
 $ctx1.sendIdx["editor"]=1;
 _st($1)._at_put_("amberCodeWidget",self);
 _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 smalltalk.withContext(function($ctx2) {
 return self._onChange();
 return self._onChange();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"configureEditor",{},globals.HLCodeWidget)})},
 args: [],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLCodeWidget);
 globals.HLCodeWidget);
@@ -343,27 +412,20 @@ protocol: 'actions',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var result;
 var result;
-function $HLDoItRequested(){return globals.HLDoItRequested||(typeof HLDoItRequested=="undefined"?nil:HLDoItRequested)}
 function $HLDoItExecuted(){return globals.HLDoItExecuted||(typeof HLDoItExecuted=="undefined"?nil:HLDoItExecuted)}
 function $HLDoItExecuted(){return globals.HLDoItExecuted||(typeof HLDoItExecuted=="undefined"?nil:HLDoItExecuted)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$3,$4;
-$2=self._model();
+var $1,$2;
+$1=self._model();
 $ctx1.sendIdx["model"]=1;
 $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"]));
 _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)})},
 }, function($ctx1) {$ctx1.fill(self,"doIt",{result:result},globals.HLCodeWidget)})},
 args: [],
 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);
 globals.HLCodeWidget);
 
 
@@ -460,20 +522,13 @@ selector: "inspectIt",
 protocol: 'actions',
 protocol: 'actions',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
-var newInspector;
-function $HLInspectItRequested(){return globals.HLInspectItRequested||(typeof HLInspectItRequested=="undefined"?nil:HLInspectItRequested)}
 return smalltalk.withContext(function($ctx1) { 
 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());
 _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: [],
 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);
 globals.HLCodeWidget);
 
 
@@ -544,6 +599,40 @@ referencedClasses: []
 }),
 }),
 globals.HLCodeWidget);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "onChange",
 selector: "onChange",
@@ -562,17 +651,33 @@ globals.HLCodeWidget);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "onDoIt",
+selector: "onCtrlClickAt:",
 protocol: 'reactions',
 protocol: 'reactions',
-fn: function (){
+fn: function (aPoint){
 var self=this;
 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) { 
 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);
 globals.HLCodeWidget);
 
 
@@ -686,18 +791,14 @@ selector: "printIt",
 protocol: 'actions',
 protocol: 'actions',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
-var result;
-function $HLPrintItRequested(){return globals.HLPrintItRequested||(typeof HLPrintItRequested=="undefined"?nil:HLPrintItRequested)}
 return smalltalk.withContext(function($ctx1) { 
 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();
 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: [],
 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);
 globals.HLCodeWidget);
 
 
@@ -742,7 +843,7 @@ protocol: 'rendering',
 fn: function (html){
 fn: function (html){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 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();
 $1=_st(html)._button();
 $ctx1.sendIdx["button"]=1;
 $ctx1.sendIdx["button"]=1;
 _st($1)._class_("button");
 _st($1)._class_("button");
@@ -766,16 +867,27 @@ return self._printIt();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 $ctx1.sendIdx["onClick:"]=2;
 $ctx1.sendIdx["onClick:"]=2;
 $5=_st(html)._button();
 $5=_st(html)._button();
+$ctx1.sendIdx["button"]=3;
 _st($5)._class_("button");
 _st($5)._class_("button");
+$ctx1.sendIdx["class:"]=3;
 _st($5)._with_("InspectIt");
 _st($5)._with_("InspectIt");
+$ctx1.sendIdx["with:"]=3;
 $6=_st($5)._onClick_((function(){
 $6=_st($5)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
 return self._inspectIt();
 return self._inspectIt();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},globals.HLCodeWidget)})},
 args: ["html"],
 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: []
 referencedClasses: []
 }),
 }),
 globals.HLCodeWidget);
 globals.HLCodeWidget);
@@ -1102,11 +1214,11 @@ protocol: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var $1;
 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;
 return $1;
 },
 },
 args: [],
 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: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -1137,11 +1249,11 @@ protocol: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var $1;
 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;
 return $1;
 },
 },
 args: [],
 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: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -1176,7 +1288,7 @@ fn: function (){
 var self=this;
 var self=this;
 function $CodeMirror(){return globals.CodeMirror||(typeof CodeMirror=="undefined"?nil:CodeMirror)}
 function $CodeMirror(){return globals.CodeMirror||(typeof CodeMirror=="undefined"?nil:CodeMirror)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5;
+var $1,$2,$3,$4,$5,$6;
 $1=_st($CodeMirror())._basicAt_("commands");
 $1=_st($CodeMirror())._basicAt_("commands");
 _st($1)._at_put_("doIt",(function(cm){
 _st($1)._at_put_("doIt",(function(cm){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
@@ -1199,14 +1311,21 @@ $ctx2.sendIdx["amberCodeWidget"]=3;
 return _st($4)._printIt();
 return _st($4)._printIt();
 }, function($ctx2) {$ctx2.fillBlock({cm:cm},$ctx1,3)})}));
 }, function($ctx2) {$ctx2.fillBlock({cm:cm},$ctx1,3)})}));
 $ctx1.sendIdx["at:put:"]=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 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)})}));
 }, 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"setupCommands",{},globals.HLCodeWidget.klass)})},
 args: [],
 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"]
 referencedClasses: ["CodeMirror"]
 }),
 }),
 globals.HLCodeWidget.klass);
 globals.HLCodeWidget.klass);

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

@@ -27,9 +27,24 @@ receiver: anObject
 
 
 !HLCodeModel methodsFor: 'actions'!
 !HLCodeModel methodsFor: 'actions'!
 
 
+browse: anObject
+	anObject browse
+!
+
 doIt: aString
 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
 inspect: anObject
@@ -133,20 +148,37 @@ selectionStart: anInteger
 
 
 !HLCodeWidget methodsFor: 'actions'!
 !HLCodeWidget methodsFor: 'actions'!
 
 
+browseIt
+	| result |
+	
+	result := [ self doIt ] on: Error do: [ :exception | 
+		^ ErrorHandler handleError: exception ].
+		
+	self model browse: result
+!
+
 clear
 clear
 	self contents: ''
 	self contents: ''
 !
 !
 
 
 configureEditor
 configureEditor
 	self editor at: 'amberCodeWidget' put: self.
 	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
 doIt
 	| result |
 	| 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).
 	self model announcer announce: (HLDoItExecuted on: model).
 
 
 	^ result
 	^ result
@@ -161,12 +193,18 @@ focus
 !
 !
 
 
 inspectIt
 inspectIt
-	| newInspector |
-       
-	self model announcer announce: (HLInspectItRequested on: model).
 	self model inspect: self doIt
 	self model inspect: self doIt
 !
 !
 
 
+navigateTo: aString
+	Finder findString: aString
+!
+
+navigateToReference: aString
+	(HLReferences openAsTab)
+		search: aString
+!
+
 print: aString
 print: aString
 	| start stop currentLine |
 	| start stop currentLine |
     currentLine := (editor getCursor: false) line.
     currentLine := (editor getCursor: false) line.
@@ -188,12 +226,7 @@ print: aString
 !
 !
 
 
 printIt
 printIt
-	| result |
-
-	result := self doIt.       
-	self model announcer announce: (HLPrintItRequested on: model).
-	self print: result printString.
-	
+	self print: self doIt printString.
 	self focus.
 	self focus.
 !
 !
 
 
@@ -233,9 +266,18 @@ onChange
 	self updateState
 	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
 onInspectIt
@@ -266,7 +308,11 @@ renderButtonsOn: html
 	html button 
 	html button 
 		class: 'button';
 		class: 'button';
 		with: 'InspectIt';
 		with: 'InspectIt';
-		onClick: [ self inspectIt ]
+		onClick: [ self inspectIt ].
+	html button 
+		class: 'button';
+		with: 'BrowseIt';
+		onClick: [ self browseIt ]
 !
 !
 
 
 renderContentOn: html
 renderContentOn: html
@@ -323,6 +369,7 @@ macKeyMap
 		'Cmd-A'					-> 'selectAll'. 
 		'Cmd-A'					-> 'selectAll'. 
 		'Cmd-Alt-F'				-> 'replace'. 
 		'Cmd-Alt-F'				-> 'replace'. 
 		'Cmd-D'					-> 'doIt'. 
 		'Cmd-D'					-> 'doIt'. 
+		'Cmd-B'					-> 'browseIt'. 
 		'Cmd-Down'				-> 'goDocEnd'. 
 		'Cmd-Down'				-> 'goDocEnd'. 
 		'Cmd-End'				-> 'goDocEnd'. 
 		'Cmd-End'				-> 'goDocEnd'. 
 		'Cmd-F'					-> 'find'.
 		'Cmd-F'					-> 'find'.
@@ -353,6 +400,7 @@ pcKeyMap
 		'Ctrl-A' -> 		'selectAll'. 
 		'Ctrl-A' -> 		'selectAll'. 
 		'Ctrl-Backspace' -> 'delWordBefore'. 
 		'Ctrl-Backspace' -> 'delWordBefore'. 
 		'Ctrl-D' -> 		'doIt'. 
 		'Ctrl-D' -> 		'doIt'. 
+		'Ctrl-B' -> 		'browseIt'. 
 		'Ctrl-Delete' -> 		'delWordAfter'. 
 		'Ctrl-Delete' -> 		'delWordAfter'. 
 		'Ctrl-Down' -> 		'goDocEnd'.
 		'Ctrl-Down' -> 		'goDocEnd'.
 		'Ctrl-End' -> 		'goDocEnd'. 
 		'Ctrl-End' -> 		'goDocEnd'. 
@@ -431,7 +479,8 @@ setupCommands
 		at: 'doIt' put: [ :cm | cm amberCodeWidget doIt ];
 		at: 'doIt' put: [ :cm | cm amberCodeWidget doIt ];
 		at: 'inspectIt' put: [ :cm | cm amberCodeWidget inspectIt ];
 		at: 'inspectIt' put: [ :cm | cm amberCodeWidget inspectIt ];
 		at: 'printIt' put: [ :cm | cm amberCodeWidget printIt ];
 		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
 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.addPackage('IDE');
 smalltalk.packages["IDE"].transport = {"type":"amd","amdNamespace":"amber_core"};
 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');
 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' ].";
 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(
 smalltalk.addMethod(
@@ -220,19 +324,47 @@ selector: "on:do:",
 protocol: 'subscribing',
 protocol: 'subscribing',
 fn: function (aClass,aBlock){
 fn: function (aClass,aBlock){
 var self=this;
 var self=this;
-function $AnnouncementSubscription(){return globals.AnnouncementSubscription||(typeof AnnouncementSubscription=="undefined"?nil:AnnouncementSubscription)}
 return smalltalk.withContext(function($ctx1) { 
 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"on:do:",{aClass:aClass,aBlock:aBlock},globals.Announcer)})},
 args: ["aClass", "aBlock"],
 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);
 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 ]
 		(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
 Object subclass: #Announcer
 	instanceVariableNames: 'registry subscriptions'
 	instanceVariableNames: 'registry subscriptions'
 	package: 'Kernel-Announcements'!
 	package: 'Kernel-Announcements'!
@@ -98,8 +132,15 @@ initialize
 !Announcer methodsFor: 'subscribing'!
 !Announcer methodsFor: 'subscribing'!
 
 
 on: aClass do: aBlock
 on: aClass do: aBlock
+	self on: aClass do: aBlock for: nil
+!
+
+on: aClass do: aBlock for: aReceiver
 	subscriptions add: (AnnouncementSubscription new
 	subscriptions add: (AnnouncementSubscription new
-		valuable: aBlock;
+		valuable: (AnnouncementValuable new
+			valuable: aBlock;
+			receiver: aReceiver;
+			yourself);
 		announcementClass: aClass;
 		announcementClass: aClass;
 		yourself)
 		yourself)
 !
 !

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

@@ -1124,6 +1124,23 @@ referencedClasses: []
 }),
 }),
 globals.Class);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "category",
 selector: "category",

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

@@ -412,6 +412,12 @@ subclasses
 	<return self.subclasses._copy()>
 	<return self.subclasses._copy()>
 ! !
 ! !
 
 
+!Class methodsFor: 'browsing'!
+
+browse
+	Finder findClass: self
+! !
+
 !Class methodsFor: 'class creation'!
 !Class methodsFor: 'class creation'!
 
 
 subclass: aString instanceVariableNames: anotherString
 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');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "=",
 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);
 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
 	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.";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "ajaxPutAt:data:",
+selector: "ajaxPutAt:data:onSuccess:onError:",
 protocol: 'private',
 protocol: 'private',
-fn: function (aURL,aString){
+fn: function (aURL,aString,aBlock,anotherBlock){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 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: []
 referencedClasses: []
 }),
 }),
 globals.PackageHandler);
 globals.PackageHandler);
@@ -1512,30 +1502,52 @@ selector: "commit:",
 protocol: 'committing',
 protocol: 'committing',
 fn: function (aPackage){
 fn: function (aPackage){
 var self=this;
 var self=this;
+function $PackageCommitError(){return globals.PackageCommitError||(typeof PackageCommitError=="undefined"?nil:PackageCommitError)}
 return smalltalk.withContext(function($ctx1) { 
 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 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)})},
 return self}, function($ctx1) {$ctx1.fill(self,"commit:",{aPackage:aPackage},globals.PackageHandler)})},
 args: ["aPackage"],
 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: []
 referencedClasses: []
 }),
 }),
 globals.PackageHandler);
 globals.PackageHandler);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "commitJsFileFor:",
+selector: "commitJsFileFor:onSuccess:onError:",
 protocol: 'committing',
 protocol: 'committing',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
@@ -1543,11 +1555,11 @@ $2=_st(_st(self._commitPathJsFor_(aPackage)).__comma("/")).__comma(_st(aPackage)
 $ctx1.sendIdx[","]=2;
 $ctx1.sendIdx[","]=2;
 $1=_st($2).__comma(".js");
 $1=_st($2).__comma(".js");
 $ctx1.sendIdx[","]=1;
 $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: []
 referencedClasses: []
 }),
 }),
 globals.PackageHandler);
 globals.PackageHandler);
@@ -1586,9 +1598,9 @@ globals.PackageHandler);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "commitStFileFor:",
+selector: "commitStFileFor:onSuccess:onError:",
 protocol: 'committing',
 protocol: 'committing',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
@@ -1596,11 +1608,11 @@ $2=_st(_st(self._commitPathStFor_(aPackage)).__comma("/")).__comma(_st(aPackage)
 $ctx1.sendIdx[","]=2;
 $ctx1.sendIdx[","]=2;
 $1=_st($2).__comma(".st");
 $1=_st($2).__comma(".st");
 $ctx1.sendIdx[","]=1;
 $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: []
 referencedClasses: []
 }),
 }),
 globals.PackageHandler);
 globals.PackageHandler);
@@ -1677,6 +1689,29 @@ referencedClasses: []
 }),
 }),
 globals.PackageHandler);
 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');
 smalltalk.addClass('AmdPackageHandler', globals.PackageHandler, [], 'Kernel-ImportExport');
@@ -1924,6 +1959,22 @@ referencedClasses: []
 }),
 }),
 globals.PackageTransport);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "definition",
 selector: "definition",

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

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

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

@@ -391,16 +391,16 @@ globals.Environment);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "commitPackage:",
+selector: "commitPackage:onSuccess:onError:",
 protocol: 'actions',
 protocol: 'actions',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 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: []
 referencedClasses: []
 }),
 }),
 globals.Environment);
 globals.Environment);
@@ -731,6 +731,23 @@ referencedClasses: ["ErrorHandler"]
 }),
 }),
 globals.Environment);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "registerInspector:",
 selector: "registerInspector:",
@@ -2209,6 +2226,64 @@ referencedClasses: []
 globals.ErrorHandler.klass);
 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');
 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.";
 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');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "addGlobalJsVariable:",
 selector: "addGlobalJsVariable:",

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

@@ -135,8 +135,10 @@ systemAnnouncer
 
 
 !Environment methodsFor: 'actions'!
 !Environment methodsFor: 'actions'!
 
 
-commitPackage: aPackage
-	aPackage commit
+commitPackage: aPackage onSuccess: aBlock onError: anotherBlock
+	aPackage transport
+		commitOnSuccess: aBlock
+		onError: anotherBlock
 !
 !
 
 
 copyClass: aClass to: aClassName
 copyClass: aClass to: aClassName
@@ -273,6 +275,10 @@ registerErrorHandler: anErrorHandler
 	ErrorHandler register: anErrorHandler
 	ErrorHandler register: anErrorHandler
 !
 !
 
 
+registerFinder: aFinder
+	Finder register: aFinder
+!
+
 registerInspector: anInspector
 registerInspector: anInspector
 	Inspector register: anInspector
 	Inspector register: anInspector
 !
 !
@@ -840,6 +846,31 @@ handleError: anError
 	self current 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
 Service subclass: #Inspector
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Kernel-Infrastructure'!
 	package: 'Kernel-Infrastructure'!
@@ -965,7 +996,7 @@ Object subclass: #SmalltalkImage
 	package: 'Kernel-Infrastructure'!
 	package: 'Kernel-Infrastructure'!
 !SmalltalkImage commentStamp!
 !SmalltalkImage commentStamp!
 I represent the Smalltalk system, wrapping
 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
 ## API
 
 
@@ -990,7 +1021,7 @@ Packages can be accessed using the following methods:
 ## Parsing
 ## Parsing
 
 
 The `#parse:` method is used to parse Amber source code.
 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'!
 !SmalltalkImage methodsFor: 'accessing'!
 
 

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

@@ -481,6 +481,23 @@ referencedClasses: []
 }),
 }),
 globals.CompiledMethod);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "category",
 selector: "category",

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

@@ -276,6 +276,12 @@ source: aString
 	self basicAt: 'source' put: aString
 	self basicAt: 'source' put: aString
 ! !
 ! !
 
 
+!CompiledMethod methodsFor: 'browsing'!
+
+browse
+	Finder findMethod: self
+! !
+
 !CompiledMethod methodsFor: 'defaults'!
 !CompiledMethod methodsFor: 'defaults'!
 
 
 defaultProtocol
 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.packages["Kernel-Objects"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 
 smalltalk.addClass('ProtoObject', globals.nil, [], 'Kernel-Objects');
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "=",
 selector: "=",
@@ -530,6 +530,23 @@ referencedClasses: []
 }),
 }),
 globals.Object);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "copy",
 selector: "copy",
@@ -3559,10 +3576,64 @@ referencedClasses: ["Point"]
 }),
 }),
 globals.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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "=",
 selector: "=",
-protocol: 'arithmetic',
+protocol: 'comparing',
 fn: function (aPoint){
 fn: function (aPoint){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3591,6 +3662,60 @@ referencedClasses: []
 }),
 }),
 globals.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).__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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asPoint",
 selector: "asPoint",
@@ -3606,6 +3731,31 @@ referencedClasses: []
 }),
 }),
 globals.Point);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "printOn:",
 selector: "printOn:",

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

@@ -182,6 +182,12 @@ value
 	<return self.valueOf()>
 	<return self.valueOf()>
 ! !
 ! !
 
 
+!Object methodsFor: 'browsing'!
+
+browse
+	Finder findClass: self class
+! !
+
 !Object methodsFor: 'converting'!
 !Object methodsFor: 'converting'!
 
 
 -> anObject
 -> anObject
@@ -1170,11 +1176,33 @@ y: aNumber
 
 
 / aPoint
 / aPoint
 	^ Point x: self x / aPoint asPoint x y: self y / aPoint asPoint y
 	^ 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
 	^ aPoint class = self class and: [
 	^ aPoint class = self class and: [
 		(aPoint x = self x) & (aPoint y = self y) ]
 		(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'!
 !Point methodsFor: 'converting'!
@@ -1200,6 +1228,14 @@ printOn: aStream
 
 
 !Point methodsFor: 'transforming'!
 !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
 translateBy: delta
 	"Answer a Point translated by delta (an instance of Point)."
 	"Answer a Point translated by delta (an instance of Point)."
 	^ (delta x + x) @ (delta y + y)
 	^ (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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "testOnDo",
 selector: "testOnDo",
-protocol: 'not yet classified',
+protocol: 'tests',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var counter,announcer;
 var counter,announcer;
@@ -77,10 +77,54 @@ referencedClasses: ["Announcer", "SystemAnnouncement"]
 }),
 }),
 globals.AnnouncerTest);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "testOnDoOnce",
 selector: "testOnDoOnce",
-protocol: 'not yet classified',
+protocol: 'tests',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 var counter,announcer;
 var counter,announcer;
@@ -8020,6 +8064,78 @@ referencedClasses: ["Point"]
 }),
 }),
 globals.PointTest);
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "testEgality",
 selector: "testEgality",

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

@@ -26,7 +26,7 @@ TestCase subclass: #AnnouncerTest
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	package: 'Kernel-Tests'!
 	package: 'Kernel-Tests'!
 
 
-!AnnouncerTest methodsFor: 'not yet classified'!
+!AnnouncerTest methodsFor: 'tests'!
 
 
 testOnDo
 testOnDo
 	| counter announcer |
 	| counter announcer |
@@ -42,6 +42,25 @@ testOnDo
 	self assert: counter equals: 2.
 	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
 testOnDoOnce
 	| counter announcer |
 	| counter announcer |
 	
 	
@@ -2324,6 +2343,20 @@ testAt
 	self assert: 3@4 equals: (Point x: 3 y: 4)
 	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
 testEgality
 	self assert: (3@4 = (3@4)).
 	self assert: (3@4 = (3@4)).
 	self deny: 3@5 = (3@6)
 	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    }.";
 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.addMethod(
 smalltalk.method({
 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!' ]";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -2217,7 +2217,7 @@ referencedClasses: []
 globals.HTMLCanvas.klass);
 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>`";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -2465,7 +2465,7 @@ referencedClasses: []
 globals.HTMLSnippet.klass);
 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'`";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -3673,7 +3673,7 @@ referencedClasses: []
 globals.TagBrush.klass);
 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";
 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.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -3741,7 +3741,7 @@ globals.Widget.klass);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "appendToBrush:",
 selector: "appendToBrush:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aTagBrush){
 fn: function (aTagBrush){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3757,7 +3757,7 @@ globals.BlockClosure);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "appendToJQuery:",
 selector: "appendToJQuery:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aJQuery){
 fn: function (aJQuery){
 var self=this;
 var self=this;
 function $HTMLCanvas(){return globals.HTMLCanvas||(typeof HTMLCanvas=="undefined"?nil:HTMLCanvas)}
 function $HTMLCanvas(){return globals.HTMLCanvas||(typeof HTMLCanvas=="undefined"?nil:HTMLCanvas)}
@@ -3774,7 +3774,7 @@ globals.BlockClosure);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asSnippet",
 selector: "asSnippet",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 function $HTMLSnippet(){return globals.HTMLSnippet||(typeof HTMLSnippet=="undefined"?nil:HTMLSnippet)}
 function $HTMLSnippet(){return globals.HTMLSnippet||(typeof HTMLSnippet=="undefined"?nil:HTMLSnippet)}
@@ -3793,7 +3793,7 @@ globals.CharacterArray);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJQuery",
 selector: "asJQuery",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3809,7 +3809,7 @@ globals.JSObjectProxy);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJQueryInContext:",
 selector: "asJQueryInContext:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aContext){
 fn: function (aContext){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3825,7 +3825,7 @@ globals.JSObjectProxy);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "appendToBrush:",
 selector: "appendToBrush:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aTagBrush){
 fn: function (aTagBrush){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3841,7 +3841,7 @@ globals.Object);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "appendToJQuery:",
 selector: "appendToJQuery:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aJQuery){
 fn: function (aJQuery){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3857,7 +3857,7 @@ globals.Object);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "appendToBrush:",
 selector: "appendToBrush:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aTagBrush){
 fn: function (aTagBrush){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3873,7 +3873,7 @@ globals.String);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "appendToJQuery:",
 selector: "appendToJQuery:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aJQuery){
 fn: function (aJQuery){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3889,7 +3889,7 @@ globals.String);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJQuery",
 selector: "asJQuery",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
@@ -3905,7 +3905,7 @@ globals.String);
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJQueryInContext:",
 selector: "asJQueryInContext:",
-protocol: '*Canvas',
+protocol: '*Web',
 fn: function (aContext){
 fn: function (aContext){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 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
 Object subclass: #BrowserInterface
 	instanceVariableNames: ''
 	instanceVariableNames: ''
-	package: 'Canvas'!
+	package: 'Web'!
 !BrowserInterface commentStamp!
 !BrowserInterface commentStamp!
 I am platform interface class that tries to use window and jQuery; that is, one for browser environment.
 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
 Object subclass: #HTMLCanvas
 	instanceVariableNames: 'root'
 	instanceVariableNames: 'root'
-	package: 'Canvas'!
+	package: 'Web'!
 !HTMLCanvas commentStamp!
 !HTMLCanvas commentStamp!
 I am a canvas for building HTML.
 I am a canvas for building HTML.
 
 
@@ -565,7 +565,7 @@ onJQuery: aJQuery
 
 
 Object subclass: #HTMLSnippet
 Object subclass: #HTMLSnippet
 	instanceVariableNames: 'snippets'
 	instanceVariableNames: 'snippets'
-	package: 'Canvas'!
+	package: 'Web'!
 !HTMLSnippet commentStamp!
 !HTMLSnippet commentStamp!
 My sole instance is the registry of html snippets.
 My sole instance is the registry of html snippets.
 `HTMLSnippet current` is the public singleton instance.
 `HTMLSnippet current` is the public singleton instance.
@@ -696,7 +696,7 @@ new
 
 
 Object subclass: #TagBrush
 Object subclass: #TagBrush
 	instanceVariableNames: 'canvas element'
 	instanceVariableNames: 'canvas element'
-	package: 'Canvas'!
+	package: 'Web'!
 !TagBrush commentStamp!
 !TagBrush commentStamp!
 I am a brush for building a single DOM element (which I hold onto).
 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
 InterfacingObject subclass: #Widget
 	instanceVariableNames: ''
 	instanceVariableNames: ''
-	package: 'Canvas'!
+	package: 'Web'!
 !Widget commentStamp!
 !Widget commentStamp!
 I am a presenter building HTML. Subclasses are typically reusable components.
 I am a presenter building HTML. Subclasses are typically reusable components.
 
 
@@ -1097,7 +1097,7 @@ heliosClass
 	^ 'widget'
 	^ 'widget'
 ! !
 ! !
 
 
-!BlockClosure methodsFor: '*Canvas'!
+!BlockClosure methodsFor: '*Web'!
 
 
 appendToBrush: aTagBrush
 appendToBrush: aTagBrush
 	aTagBrush appendBlock: self
 	aTagBrush appendBlock: self
@@ -1107,13 +1107,13 @@ appendToJQuery: aJQuery
 	self value: (HTMLCanvas onJQuery: aJQuery)
 	self value: (HTMLCanvas onJQuery: aJQuery)
 ! !
 ! !
 
 
-!CharacterArray methodsFor: '*Canvas'!
+!CharacterArray methodsFor: '*Web'!
 
 
 asSnippet
 asSnippet
 	^ HTMLSnippet current snippetAt: self asString
 	^ HTMLSnippet current snippetAt: self asString
 ! !
 ! !
 
 
-!JSObjectProxy methodsFor: '*Canvas'!
+!JSObjectProxy methodsFor: '*Web'!
 
 
 asJQuery
 asJQuery
 	<return jQuery(self['@jsObject'])>
 	<return jQuery(self['@jsObject'])>
@@ -1123,7 +1123,7 @@ asJQueryInContext: aContext
 	<return jQuery(self['@jsObject'], aContext)>
 	<return jQuery(self['@jsObject'], aContext)>
 ! !
 ! !
 
 
-!Object methodsFor: '*Canvas'!
+!Object methodsFor: '*Web'!
 
 
 appendToBrush: aTagBrush
 appendToBrush: aTagBrush
 	aTagBrush append: self asString
 	aTagBrush append: self asString
@@ -1133,7 +1133,7 @@ appendToJQuery: aJQuery
 	aJQuery append: self asString
 	aJQuery append: self asString
 ! !
 ! !
 
 
-!String methodsFor: '*Canvas'!
+!String methodsFor: '*Web'!
 
 
 appendToBrush: aTagBrush
 appendToBrush: aTagBrush
 	aTagBrush appendString: self
 	aTagBrush appendString: self

+ 5 - 5
support/amber.js

@@ -3,11 +3,11 @@
     either defines 'require', thus passing config, if loaded prior require.js;
     either defines 'require', thus passing config, if loaded prior require.js;
     or calls require.config, if loaded post require.js).
     or calls require.config, if loaded post require.js).
   Usage example:
   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:
   For detailed explanation of amber loading, see:
   https://github.com/amber-smalltalk/amber/wiki/How-to-load-amber
   https://github.com/amber-smalltalk/amber/wiki/How-to-load-amber
@@ -62,7 +62,7 @@ require = function (require) {
             'amber_vm': amber_home + '/support',
             'amber_vm': amber_home + '/support',
             'amber_css': amber_home + '/css',
             'amber_css': amber_home + '/css',
             'amber_lib': library_home,
             'amber_lib': library_home,
-            'amber_core': amber_home + '/js',
+            'amber_core': amber_home + '/src',
             'amber_helios/html': amber_home,
             'amber_helios/html': amber_home,
             'jquery': library_home + '/jquery/jquery.min',
             'jquery': library_home + '/jquery/jquery.min',
             'jquery-ui': library_home + '/jquery-ui/ui/minified/jquery-ui.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-Exceptions',
     'amber_core/Kernel-Transcript',
     'amber_core/Kernel-Transcript',
     'amber_core/Kernel-Announcements',
     'amber_core/Kernel-Announcements',
-    'amber_core/Canvas'
+    'amber_core/Web'
 ], function (smalltalk) { return smalltalk; });
 ], function (smalltalk) { return smalltalk; });

Some files were not shown because too many files changed in this diff