Преглед изворни кода

Merge branch 'master' into moka

Conflicts:
	index.html
Nicolas Petton пре 10 година
родитељ
комит
f714515953
91 измењених фајлова са 2658 додато и 2658 уклоњено
  1. 12 3
      API-CHANGES.txt
  2. 21 6
      CHANGELOG
  3. 5 1
      README.md
  4. 1 2
      cli/index.html
  5. 99 880
      cli/js/AmberCli.js
  6. 17 5
      cli/st/AmberCli.st
  7. 167 93
      cli/support/amber-cli.js
  8. 27 27
      cli/support/amberc.js
  9. 6 0
      cli/support/release-worker.sh
  10. 3 3
      css/amber.css
  11. 240 224
      css/helios.css
  12. 129 113
      css/helios.less
  13. 1 2
      helios.html
  14. 1 5
      index.html
  15. 0 0
      js/Benchfib.st
  16. 90 40
      js/Canvas.js
  17. 27 15
      js/Canvas.st
  18. 17 19
      js/Compiler-AST.js
  19. 6 6
      js/Compiler-AST.st
  20. 0 0
      js/Compiler-Core.st
  21. 0 0
      js/Compiler-Exceptions.st
  22. 82 76
      js/Compiler-IR.js
  23. 12 10
      js/Compiler-IR.st
  24. 1 2
      js/Compiler-Inlining.js
  25. 0 0
      js/Compiler-Inlining.st
  26. 20 31
      js/Compiler-Interpreter.js
  27. 10 14
      js/Compiler-Interpreter.st
  28. 3 6
      js/Compiler-Semantic.js
  29. 0 0
      js/Compiler-Semantic.st
  30. 30 22
      js/Compiler-Tests.js
  31. 6 2
      js/Compiler-Tests.st
  32. 0 0
      js/Examples.st
  33. 38 0
      js/Helios-Announcements.js
  34. 22 0
      js/Helios-Announcements.st
  35. 120 26
      js/Helios-Browser.js
  36. 32 5
      js/Helios-Browser.st
  37. 0 0
      js/Helios-Commands-Browser.st
  38. 2 2
      js/Helios-Commands-Core.js
  39. 1 1
      js/Helios-Commands-Core.st
  40. 28 28
      js/Helios-Commands-Tools.js
  41. 14 14
      js/Helios-Commands-Tools.st
  42. 37 21
      js/Helios-Core.js
  43. 11 1
      js/Helios-Core.st
  44. 13 19
      js/Helios-Debugger.js
  45. 0 0
      js/Helios-Debugger.st
  46. 0 0
      js/Helios-Exceptions.st
  47. 3 6
      js/Helios-Helpers.js
  48. 0 0
      js/Helios-Helpers.st
  49. 5 37
      js/Helios-Inspector.js
  50. 1 24
      js/Helios-Inspector.st
  51. 52 24
      js/Helios-KeyBindings.js
  52. 15 3
      js/Helios-KeyBindings.st
  53. 10 28
      js/Helios-Layout.js
  54. 0 0
      js/Helios-Layout.st
  55. 1 2
      js/Helios-References.js
  56. 0 0
      js/Helios-References.st
  57. 0 0
      js/Helios-Transcript.st
  58. 0 0
      js/Helios-Workspace-Tests.st
  59. 57 164
      js/Helios-Workspace.js
  60. 60 52
      js/Helios-Workspace.st
  61. 87 99
      js/IDE.js
  62. 33 33
      js/IDE.st
  63. 0 0
      js/Kernel-Announcements.st
  64. 70 2
      js/Kernel-Classes.js
  65. 16 0
      js/Kernel-Classes.st
  66. 15 21
      js/Kernel-Collections.js
  67. 1 1
      js/Kernel-Collections.st
  68. 0 0
      js/Kernel-Exceptions.st
  69. 45 37
      js/Kernel-ImportExport.js
  70. 12 5
      js/Kernel-ImportExport.st
  71. 313 17
      js/Kernel-Infrastructure.js
  72. 91 2
      js/Kernel-Infrastructure.st
  73. 37 10
      js/Kernel-Methods.js
  74. 15 16
      js/Kernel-Methods.st
  75. 5 10
      js/Kernel-Objects.js
  76. 0 0
      js/Kernel-Objects.st
  77. 105 230
      js/Kernel-Tests.js
  78. 9 10
      js/Kernel-Tests.st
  79. 0 0
      js/Kernel-Transcript.st
  80. 2 4
      js/SUnit-Tests.js
  81. 0 0
      js/SUnit-Tests.st
  82. 2 4
      js/SUnit.js
  83. 0 0
      js/SUnit.st
  84. 2 4
      js/Spaces.js
  85. 0 0
      js/Spaces.st
  86. 3 3
      package.json
  87. 3 3
      support/amber.js
  88. 3 4
      support/boot.js
  89. 37 7
      support/helpers.js
  90. 189 64
      support/parser.js
  91. 8 8
      support/parser.pegjs

+ 12 - 3
API-CHANGES.txt

@@ -1,4 +1,4 @@
-0.12.3 (wip):
+0.12.3:
 
 * Package Import-Export renamed to Kernel-ImportExport
 * A dozen of methods moved from Object to ProtoObject
@@ -28,8 +28,17 @@
 + Set >> removeAll
 + AssociativeCollection class
 + BucketStore class
-+ SmalltalkImage >> globals
-+ SmalltalkImage >> vm
++ SmalltalkImage >>
+  + globals
+  + vm
+  + settings
++ Setting class
++ String >>
+  + asSetting
+  + asSettingIfAbsent:
+  + settingValue
+  + settingValueIfAbsent:
+  + settingValue:
 + Smalltalk global variable
 
 - CompiledMethod >>

+ 21 - 6
CHANGELOG

@@ -1,17 +1,32 @@
-??th ??? 20?? - Release 0.12.3
+??nd ??? 2014 - Release 0.12.4
+===================================
+
+Highlights:
+
+* Fixed backward compatibility for pre-0.12.3 loader syntax.
+* `namespace/_source` is not needed to map and is recommended
+  not to use; `.st` files are by default committed to the `.js` location.
+
+Commits: https://github.com/amber-smalltalk/amber/compare/0.12.3...0.12.4
+Issues:  https://github.com/amber-smalltalk/amber/issues?milestone=12&state=closed
+
+For the most important API related changes see the file API-CHANGES.txt.
+
+
+22nd Jan 2014 - Release 0.12.3
 ===================================
 
 Highlights:
 
 * JQuery updated to ~1.10.2; jquery-ui updated to match
-* You can create subclasses of `nil`
-* Amber loads in IE8
-* You can load amber.js asynchronously (it must
-  have id 'amber-path-mapper' in that case)
+* Subclasses of `nil` can be created
+* Several fixes for IE8
+* amber.js can be loaded asynchronously (it must
+  have an id 'amber-path-mapper' in that case)
 * CodeMirror updated to ~3.20.0
 
 Commits: https://github.com/amber-smalltalk/amber/compare/0.12.2...0.12.3
-Issues:  https://github.com/amber-smalltalk/amber/issues?milestone=__&state=closed
+Issues:  https://github.com/amber-smalltalk/amber/issues?milestone=11&state=closed
 
 For the most important API related changes see the file API-CHANGES.txt.
 

+ 5 - 1
README.md

@@ -26,8 +26,12 @@ Amber is shipped as a [npm](http://npmjs.org) package for its CLI tools and as a
     # Install the CLI tool `amber`
     npm install -g amber
     
+    # Initialize your project as bower package
+    cd /path/to/myproject
+    bower init
+
     # Load amber via bower in your project
-    bower install amber
+    bower install amber --save
     
     # Serve amber on localhost:4000
     amber serve

+ 1 - 2
cli/index.html

@@ -22,8 +22,7 @@
         ["amber/devel",
             "amber_cli/AmberCli" ],
         function (smalltalk) {
-            smalltalk.vm.defaultAmdNamespace = 'amber_cli';
-            smalltalk.vm.initialize();
+            smalltalk.initialize({'transport.defaultAmdNamespace': 'amber_cli'});
             smalltalk.globals.Browser._openOn_(smalltalk.AmberCli);
         }
     );

Разлика између датотеке није приказан због своје велике величине
+ 99 - 880
cli/js/AmberCli.js


+ 17 - 5
cli/st/AmberCli.st

@@ -250,12 +250,14 @@ writeData: data toFileNamed: aFilename
 
 handleGETRequest: aRequest respondTo: aResponse
 	| uri filename |
-	uri := (url parse: aRequest url) pathname.
-	filename := path join: self basePath with: uri.
+	uri := url parse: aRequest url.
+	filename := path join: self basePath with: uri pathname.
 	fs exists: filename do: [:aBoolean |
 		aBoolean
 			ifFalse: [self respondNotFoundTo: aResponse]
-			ifTrue: [self respondFileNamed: filename to: aResponse]]
+			ifTrue: [(fs statSync: filename) isDirectory
+				ifTrue: [self respondDirectoryNamed: filename from: uri to: aResponse]
+				ifFalse: [self respondFileNamed: filename to: aResponse]]]
 !
 
 handleOPTIONSRequest: aRequest respondTo: aResponse
@@ -314,12 +316,16 @@ respondCreatedTo: aResponse
 		end.
 !
 
+respondDirectoryNamed: aDirname from: aUrl to: aResponse
+	(aUrl pathname endsWith: '/')
+		ifTrue: [self respondFileNamed: aDirname, 'index.html' to: aResponse]
+		ifFalse: [self respondRedirect: aUrl pathname, '/', (aUrl search ifNil: ['']) to: aResponse]
+!
+
 respondFileNamed: aFilename to: aResponse
 	| type filename |
 
 	filename := aFilename.
-	(fs statSync: aFilename) isDirectory ifTrue: [
-		filename := filename, 'index.html'].
 
 	fs readFile: filename do: [:ex :file |
 		ex notNil 
@@ -367,6 +373,12 @@ respondOKTo: aResponse
 	aResponse
 		writeHead: 200 options: #{'Content-Type' -> 'text/plain'. 'Access-Control-Allow-Origin' -> '*'};
 		end.
+!
+
+respondRedirect: aString to: aResponse
+	aResponse
+		writeHead: 303 options: #{'Location' -> aString};
+		end.
 ! !
 
 !FileServer methodsFor: 'starting'!

Разлика између датотеке није приказан због своје велике величине
+ 167 - 93
cli/support/amber-cli.js


+ 27 - 27
cli/support/amberc.js

@@ -43,8 +43,8 @@ function createConcatenator () {
 		},
 		finish: function (realWork) {
 			this.add(
-				'define("amber_vm/_init", ["amber_vm/smalltalk","' + this.ids.join('","') + '"], function (smalltalk) {',
-				'smalltalk.initialize();',
+				'define("amber_vm/_init", ["amber_vm/smalltalk", "amber_vm/globals", "' + this.ids.join('","') + '"], function (vm, globals) {',
+				'vm.initialize();',
 				realWork,
 				'});',
 				'requirejs("amber_vm/_init");'
@@ -62,10 +62,10 @@ var path = require('path'),
 	Promise = require('es6-promise').Promise;
 
 /**
- * AmberC constructor function.
+ * AmberCompiler constructor function.
  * amber_dir: points to the location of an amber installation
  */
-function AmberC(amber_dir) {
+function AmberCompiler(amber_dir) {
 	if (undefined === amber_dir || !fs.existsSync(amber_dir)) {
 		throw new Error('amber_dir needs to be a valid directory');
 	}
@@ -110,7 +110,7 @@ var createDefaultConfiguration = function() {
  * If check_configuration_ok() returns successfully
  * the configuration is used to trigger the following compilation steps.
  */
-AmberC.prototype.main = function(configuration, finished_callback) {
+AmberCompiler.prototype.main = function(configuration, finished_callback) {
 	console.time('Compile Time');
 
 	if (configuration.amd_namespace.length === 0) {
@@ -128,7 +128,8 @@ AmberC.prototype.main = function(configuration, finished_callback) {
 	}
 
 	// the evaluated compiler will be stored in this variable (see create_compiler)
-	configuration.smalltalk = {};
+	configuration.vm = {};
+	configuration.globals = {};
 	configuration.kernel_libraries = this.kernel_libraries;
 	configuration.compiler_libraries = this.compiler_libraries;
 	configuration.amber_dir = this.amber_dir;
@@ -161,11 +162,11 @@ AmberC.prototype.main = function(configuration, finished_callback) {
 function check_configuration(configuration) {
 	return new Promise(function(resolve, reject) {
 		if (undefined === configuration) {
-			reject(Error('AmberC.check_configuration_ok(): missing configuration object'));
+			reject(Error('AmberCompiler.check_configuration_ok(): missing configuration object'));
 		}
 
 		if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.length) {
-			reject(Error('AmberC.check_configuration_ok(): no files to compile/link specified in configuration object'));
+			reject(Error('AmberCompiler.check_configuration_ok(): no files to compile/link specified in configuration object'));
 		}
 
 		resolve(configuration);
@@ -279,7 +280,7 @@ function resolve_kernel(configuration) {
 	)
 	.then(function(data) {
 		// boot.js and Kernel files need to be used first
-		// otherwise the global smalltalk object is undefined
+		// otherwise the global objects 'vm' and 'globals' are undefined
 		configuration.libraries = data.concat(configuration.libraries);
 		return configuration;
 	});
@@ -288,7 +289,7 @@ function resolve_kernel(configuration) {
 
 /**
  * Resolve .js files needed by compiler, read and eval() them.
- * The finished Compiler gets stored in configuration.smalltalk.
+ * The finished Compiler gets stored in configuration.{vm,globals}.
  * Returns a Promise object which resolves into the configuration object.
  */
 function create_compiler(configuration) {
@@ -327,18 +328,18 @@ function create_compiler(configuration) {
 				builder.addId(match[1]);
 			}
 		});
-		// store the generated smalltalk env in configuration.smalltalk
-		builder.finish('configuration.smalltalk = smalltalk;');
+		// store the generated smalltalk env in configuration.{vm,globals}
+		builder.finish('configuration.vm = vm; configuration.globals = globals;');
 		builder.add('})();');
 
 		eval(builder.toString());
 
 		console.log('Compiler loaded');
 
-		configuration.smalltalk.ErrorHandler._register_(configuration.smalltalk.RethrowErrorHandler._new());
+		configuration.globals.ErrorHandler._register_(configuration.globals.RethrowErrorHandler._new());
 
 		if(0 !== configuration.jsGlobals.length) {
-			var jsGlobalVariables = configuration.smalltalk.globalJsVariables;
+			var jsGlobalVariables = configuration.vm.globalJsVariables;
 			jsGlobalVariables.push.apply(jsGlobalVariables, configuration.jsGlobals);
 		}
 
@@ -358,12 +359,12 @@ function compile(configuration) {
 		configuration.compile.map(function(stFile) {
 			return new Promise(function(resolve, reject) {
 				if (/\.st/.test(stFile)) {
-					console.ambercLog('Importing: ' + stFile);
+					console.ambercLog('Reading: ' + stFile);
 					fs.readFile(stFile, 'utf8', function(err, data) {
 						if (!err)
 							resolve(data);
 						else
-							reject(Error('Could not import: ' + stFile));
+							reject(Error('Could not read: ' + stFile));
 					});
 				}
 			});
@@ -375,12 +376,12 @@ function compile(configuration) {
 		return Promise.all(
 			fileContents.map(function(code) {
 				return new Promise(function(resolve, reject) {
-					var importer = configuration.smalltalk.Importer._new();
+					var importer = configuration.globals.Importer._new();
 					try {
 						importer._import_(code._stream());
 						resolve(true);
 					} catch (ex) {
-						reject(Error("Import error in section:\n" +
+						reject(Error("Compiler error in section:\n" +
 							importer._lastSection() + "\n\n" +
 							"while processing chunk:\n" +
 							importer._lastChunk() + "\n\n" +
@@ -413,11 +414,11 @@ function category_export(configuration) {
 				var jsFile = category + configuration.suffix_used + '.js';
 				jsFile = path.join(jsFilePath, jsFile);
 				configuration.compiled.push(jsFile);
-				var smalltalk = configuration.smalltalk;
-				var packageObject = smalltalk.Package._named_(category);
+				var smalltalkGlobals = configuration.globals;
+				var packageObject = smalltalkGlobals.Package._named_(category);
 				packageObject._transport()._namespace_(configuration.amd_namespace);
-				fs.writeFile(jsFile, smalltalk.String._streamContents_(function (stream) {
-					smalltalk.AmdExporter._new()._exportPackage_on_(packageObject, stream);
+				fs.writeFile(jsFile, smalltalkGlobals.String._streamContents_(function (stream) {
+					smalltalkGlobals.AmdExporter._new()._exportPackage_on_(packageObject, stream);
 				}), function(err) {
 					if (err)
 						reject(err);
@@ -467,8 +468,7 @@ function compose_js_files(configuration) {
 	return new Promise(function(resolve, reject) {
 		var programFile = configuration.program;
 		if (undefined === programFile) {
-			resolve(configuration);
-			return;
+			reject(configuration);
 		}
 		if (undefined !== configuration.output_dir) {
 			programFile = path.join(configuration.output_dir, programFile);
@@ -524,12 +524,12 @@ function compose_js_files(configuration) {
 
 		if (undefined !== configuration.main) {
 			console.log('Adding call to: %s>>main', configuration.main);
-			mainFunctionOrFile += 'smalltalk.' + configuration.main + '._main();';
+			mainFunctionOrFile += 'globals.' + configuration.main + '._main();';
 		}
 
 		if (undefined !== configuration.mainfile && fs.existsSync(configuration.mainfile)) {
 			console.log('Adding main file: ' + configuration.mainfile);
-			mainFunctionOrFile += '\n' + fs.readFileSync(configuration.mainfile);
+			mainFunctionOrFile += '\nvar smalltalk = vm; // backward compatibility\n' + fs.readFileSync(configuration.mainfile);
 		}
 
 		builder.finish(mainFunctionOrFile);
@@ -545,5 +545,5 @@ function compose_js_files(configuration) {
 }
 
 
-module.exports.Compiler = AmberC;
+module.exports.Compiler = AmberCompiler;
 module.exports.createDefaultConfiguration = createDefaultConfiguration;

+ 6 - 0
cli/support/release-worker.sh

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

+ 3 - 3
css/amber.css

@@ -241,7 +241,7 @@ body.amberBody {
 .amberTool textarea,
 .amberTool input {
     border: 0 none;
-    font-family:  "DejaVu Sans", Helvetica, sans;
+    font-family:  "DejaVu Sans", Helvetica, sans-serif;
     line-height: 1.3em;
     font-size: 11px;
     position: relative;
@@ -250,7 +250,7 @@ body.amberBody {
 
 .amberTool .CodeMirror {
     border: 0 none;
-    font-family:  "DejaVu Sans", Helvetica, sans;
+    font-family:  "DejaVu Sans", Helvetica, sans-serif;
     font-size: 11px;
     line-height: 1.3em;
     height: 100%;
@@ -262,7 +262,7 @@ body.amberBody {
 }
 
 .amberTool .CodeMirror-scroll pre {
-    font-family: "DejaVu Sans", Helvetica, sans;
+    font-family: "DejaVu Sans", Helvetica, sans-serif;
 }
 
 .amberTool .amber_clear {

+ 240 - 224
css/helios.css

@@ -1,8 +1,3 @@
-body {
-  font-size: 11px;
-  font-family: "Lucida Grande", helvetica, arial, sans;
-  background: #eee;
-}
 .clearfix:after {
   content: ".";
   display: block;
@@ -20,70 +15,76 @@ html[xmlns] .clearfix {
 * html .clearfix {
   height: 1%;
 }
-#helios a {
+.cm-s-helios.CodeMirror {
+  font-family: Menlo, Monaco, Consolas, Inconsolata, "Lucida Console", Courier, monospace;
+  line-height: 16px;
+  font-size: 13px;
+}
+.cm-s-helios .CodeMirror-gutter.stops {
+  width: 20px;
+}
+.cm-s-helios .highlighted.CodeMirror-linebackground {
+  background-color: #ffffaa;
+}
+.cm-s-helios .CodeMirror-gutter-elt .stop {
+  width: 16px;
+  height: 16px;
+  background: url('../images/arrowRight.png');
+  margin-left: 2px;
+}
+body[id="helios"] {
+  font-size: 11px;
+  font-family: "Lucida Grande", "Segoe UI", helvetica, arial, sans-serif;
+  background: #eee;
+}
+body[id="helios"] a {
   cursor: pointer;
 }
-#helios i {
+body[id="helios"] i {
   opacity: 1;
 }
-#helios [class^="icon-"],
-#helios [class*=" icon-"] {
+body[id="helios"] [class^="icon-"],
+body[id="helios"] [class*=" icon-"] {
   margin-top: 0;
 }
-#helios .CodeMirror {
+body[id="helios"] .CodeMirror {
   position: absolute;
-  overflow: hidden;
   height: 100%;
   width: 100%;
 }
-#helios .CodeMirror-hints {
+body[id="helios"] .CodeMirror-hints {
   border-radius: 0;
-  font-family: Menlo, Monaco, "Lucida Console", Courier, monospace;
+  font-family: "Lucida Grande", "Segoe UI", helvetica, arial, sans-serif;
   font-size: 11px;
   line-height: 1em;
   padding: 0;
   max-height: 120px;
 }
-#helios .CodeMirror-hint {
+body[id="helios"] .CodeMirror-hint {
   border-radius: 0;
   padding: 0 10px;
 }
-#helios .CodeMirror pre,
-#helios .CodeMirror .CodeMirror-gutter-elt {
-  font-family: Menlo, Monaco, "Lucida Console", "Ubuntu Mono", Courier, monospace;
-  line-height: 16px;
-  font-size: 13px;
-}
-#helios .CodeMirror-gutter.stops {
-  width: 20px;
-}
-#helios .CodeMirror .highlighted.CodeMirror-linebackground {
-  background-color: #ffffaa;
-}
-#helios .CodeMirror .CodeMirror-gutter-elt .stop {
-  width: 16px;
-  height: 16px;
-  background: url('../images/arrowRight.png');
-  margin-left: 2px;
-}
-#helios .state {
+body[id="helios"] .state {
   position: absolute;
   right: 15px;
   top: 10px;
   width: 16px;
   height: 16px;
 }
-#helios .state.modified {
+body[id="helios"] .state.modified {
   background: transparent url('../images/modified.png') 50% 50% no-repeat;
 }
-#helios .editor {
+body[id="helios"] .editor {
   position: absolute;
   top: 0;
   bottom: 23px;
   left: 0;
   right: 0;
 }
-#helios .buttons_bar {
+body[id="helios"] .hl_widget:focus {
+  outline: 0 none;
+}
+body[id="helios"] .buttons_bar {
   position: absolute;
   bottom: 0;
   right: 0;
@@ -95,29 +96,29 @@ html[xmlns] .clearfix {
   border-top: 1px solid #999;
   text-align: right;
 }
-#helios .buttons_bar .button {
+body[id="helios"] .buttons_bar .button {
   height: 17px;
   font-size: 12px;
   min-width: 0;
 }
-#helios .btn,
-#helios .btn-group > .btn,
-#helios .btn-group > .dropdown-menu {
+body[id="helios"] .btn,
+body[id="helios"] .btn-group > .btn,
+body[id="helios"] .btn-group > .dropdown-menu {
   padding: 2px 8px;
 }
-#helios .navbar-fixed-top {
+body[id="helios"] .navbar-fixed-top {
   font-size: 11px;
   line-height: 16px;
 }
-#helios .navbar-fixed-top a span,
-#helios .dialog .nav a span {
+body[id="helios"] .navbar-fixed-top a span,
+body[id="helios"] .dialog .nav a span {
   padding: 1px;
   padding-left: 18px;
   background-position: center left;
   background-repeat: no-repeat;
   background-position: 0px -1px;
 }
-#helios .navbar-fixed-top i.close {
+body[id="helios"] .navbar-fixed-top i.close {
   width: 14px;
   height: 16px;
   margin-left: 4px;
@@ -126,31 +127,31 @@ html[xmlns] .clearfix {
   background-position: center left;
   margin-top: 2px;
 }
-#helios .navbar-fixed-top a span.references,
-#helios .dialog .nav a span.references {
+body[id="helios"] .navbar-fixed-top a span.references,
+body[id="helios"] .dialog .nav a span.references {
   background-image: url('../images/references.png');
 }
-#helios .navbar-fixed-top a span.browser,
-#helios .dialog .nav a span.browser {
+body[id="helios"] .navbar-fixed-top a span.browser,
+body[id="helios"] .dialog .nav a span.browser {
   background-image: url('../images/browser.png');
 }
-#helios .navbar-fixed-top a span.sunit,
-#helios .dialog .nav a span.sunit {
+body[id="helios"] .navbar-fixed-top a span.sunit,
+body[id="helios"] .dialog .nav a span.sunit {
   background-image: url('../images/sunit.png');
 }
-#helios .navbar-fixed-top a span.workspace,
-#helios .dialog .nav a span.workspace {
+body[id="helios"] .navbar-fixed-top a span.workspace,
+body[id="helios"] .dialog .nav a span.workspace {
   background-image: url('../images/workspace.png');
 }
-#helios .navbar-fixed-top a span.debugger,
-#helios .dialog .nav a span.debugger {
+body[id="helios"] .navbar-fixed-top a span.debugger,
+body[id="helios"] .dialog .nav a span.debugger {
   background-image: url('../images/debugger.png');
 }
-#helios .navbar-fixed-top a span.inspector,
-#helios .dialog .nav a span.inspector {
+body[id="helios"] .navbar-fixed-top a span.inspector,
+body[id="helios"] .dialog .nav a span.inspector {
   background-image: url('../images/inspector.png');
 }
-#helios .navbar-fixed-top .navbar-inner {
+body[id="helios"] .navbar-fixed-top .navbar-inner {
   min-height: 20px;
   background-color: #dbdbdb;
   border-bottom: 1px solid #666;
@@ -160,22 +161,22 @@ html[xmlns] .clearfix {
   background-image: -owebkit-linear-gradient(top, #dfdfdf, #d0d0d0);
   box-shadow: 0 0 0;
 }
-#helios .navbar .nav > li {
+body[id="helios"] .navbar .nav > li {
   line-height: 16px;
 }
-#helios .navbar .nav > li > a {
+body[id="helios"] .navbar .nav > li > a {
   line-height: 22px;
   padding: 0px 8px;
   font-size: 11px;
   color: #444;
   text-shadow: 0 1px 0 #ddd;
 }
-#helios .nav > li > a:hover {
+body[id="helios"] .nav > li > a:hover {
   background: transparent;
 }
-#helios .navbar .nav > .active > a,
-#helios .navbar .nav > .active > a:hover,
-#helios .navbar .nav > .active > a:focus {
+body[id="helios"] .navbar .nav > .active > a,
+body[id="helios"] .navbar .nav > .active > a:hover,
+body[id="helios"] .navbar .nav > .active > a:focus {
   background-color: #bababa;
   background-image: linear-gradient(left, #777777 0%, #bababa 2px, transparent 2px), linear-gradient(right, #777777 0%, #bababa 2px, transparent 2px);
   background-image: -webkit-linear-gradient(left, #777777 0%, #bababa 2px, transparent 2px), -webkit-linear-gradient(right, #777777 0%, #bababa 2px, transparent 2px);
@@ -184,16 +185,16 @@ html[xmlns] .clearfix {
   text-shadow: #ddd 0px 1px 0px;
   color: #222;
 }
-#helios .navbar-fixed-top i {
+body[id="helios"] .navbar-fixed-top i {
   opacity: 0.4;
   margin-right: 5px;
   height: 12px;
   margin-top: 0;
 }
-#helios .navbar-fixed-top .active i {
+body[id="helios"] .navbar-fixed-top .active i {
   opacity: 0.6;
 }
-#helios .nav-pills.nav-stacked > li > a {
+body[id="helios"] .nav-pills.nav-stacked > li > a {
   border-radius: 0;
   -webkit-border-radius: 0;
   -moz-border-radius: 0;
@@ -203,56 +204,56 @@ html[xmlns] .clearfix {
   color: #111;
   white-space: nowrap;
 }
-#helios [class^="icon-"],
-#helios [class*=" icon-"] {
+body[id="helios"] [class^="icon-"],
+body[id="helios"] [class*=" icon-"] {
   margin-right: 2px;
 }
-#helios .dropdown-menu {
+body[id="helios"] .dropdown-menu {
   border-radius: 0;
   padding: 0;
   margin: 3px;
 }
-#helios .nav-pills > .active > a {
+body[id="helios"] .nav-pills > .active > a {
   background-color: #ddd;
   color: #fff;
   text-shadow: 0 0 0;
 }
-#helios .focused .nav-pills {
+body[id="helios"] .focused .nav-pills {
   background-color: #f3f7fb;
 }
-#helios .focused .nav-pills > .active > a,
-#helios .nav-pills > .active > a:hover,
-#helios .dropdown-menu li > a:hover,
-#helios .dropdown-menu li > a:focus,
-#helios .dropdown-submenu:hover > a,
-#helios .dropdown-menu .active > a,
-#helios .dropdown-menu .active > a:hover,
-#helios .CodeMirror-hint-active {
+body[id="helios"] .focused .nav-pills > .active > a,
+body[id="helios"] .nav-pills > .active > a:hover,
+body[id="helios"] .dropdown-menu li > a:hover,
+body[id="helios"] .dropdown-menu li > a:focus,
+body[id="helios"] .dropdown-submenu:hover > a,
+body[id="helios"] .dropdown-menu .active > a,
+body[id="helios"] .dropdown-menu .active > a:hover,
+body[id="helios"] .CodeMirror-hint-active {
   background: rgba(95, 159, 228, 0.62);
   color: #fff;
   text-shadow: 0 0 0;
 }
-#helios .tool_container {
+body[id="helios"] .tool_container {
   position: absolute;
   top: 23px;
   bottom: 0;
   left: 0;
   right: 0;
 }
-#helios .transcript textarea {
+body[id="helios"] .transcript textarea {
   width: 100%;
   height: 100%;
   margin: 0;
   padding: 0;
   border: 0;
 }
-#helios .tool_container .panes {
+body[id="helios"] .tool_container .panes {
   position: relative;
   height: 100%;
   width: 100%;
   overflow: hidden;
 }
-#helios .tool_container .panes .pane {
+body[id="helios"] .tool_container .panes .pane {
   position: absolute;
   overflow: auto;
   top: 0;
@@ -261,44 +262,44 @@ html[xmlns] .clearfix {
   bottom: 0;
   background: #fefefe;
 }
-#helios .tool_container .multi_pane {
+body[id="helios"] .tool_container .multi_pane {
   position: relative;
   height: 100%;
   width: auto;
   overflow-x: auto;
 }
-#helios .tool_container .multi_pane .pane {
+body[id="helios"] .tool_container .multi_pane .pane {
   height: 100%;
   max-width: 300px;
   border-right: 1px solid #888;
 }
-#helios .tool_container .panes .pane > div {
+body[id="helios"] .tool_container .panes .pane > div {
   height: 100%;
   position: relative;
 }
-#helios .tool_container .panes.horizontal > .pane {
+body[id="helios"] .tool_container .panes.horizontal > .pane {
   min-height: 50px;
 }
-#helios .tool_container .panes.horizontal > .pane {
+body[id="helios"] .tool_container .panes.horizontal > .pane {
   top: 50%;
 }
-#helios .tool_container .panes.horizontal > .pane:first-child {
+body[id="helios"] .tool_container .panes.horizontal > .pane:first-child {
   top: 0;
   bottom: 50%;
 }
-#helios .tool_container .panes.vertical > .pane {
+body[id="helios"] .tool_container .panes.vertical > .pane {
   left: 50%;
 }
-#helios .tool_container .panes.vertical > .pane:first-child {
+body[id="helios"] .tool_container .panes.vertical > .pane:first-child {
   left: 0;
   right: 50%;
 }
-#helios .tool_container .splitter {
+body[id="helios"] .tool_container .splitter {
   position: absolute;
   border-width: 0;
   z-index: 10;
 }
-#helios .tool_container .splitter.vertical {
+body[id="helios"] .tool_container .splitter.vertical {
   width: 5px;
   left: 50%;
   margin-left: -1px;
@@ -307,7 +308,7 @@ html[xmlns] .clearfix {
   float: left;
   cursor: ew-resize;
 }
-#helios .tool_container .splitter.horizontal {
+body[id="helios"] .tool_container .splitter.horizontal {
   top: 50%;
   height: 5px;
   margin-top: -1px;
@@ -315,7 +316,7 @@ html[xmlns] .clearfix {
   border-top: 1px solid #888;
   cursor: ns-resize;
 }
-#helios .tool_container .panes .pane .nav-pills {
+body[id="helios"] .tool_container .panes .pane .nav-pills {
   position: absolute;
   overflow-y: auto;
   top: 17px;
@@ -323,7 +324,7 @@ html[xmlns] .clearfix {
   width: 100%;
   margin: 0;
 }
-#helios .tool_container .pane .nav-pills i {
+body[id="helios"] .tool_container .pane .nav-pills i {
   display: inline-block;
   width: 16px;
   height: 16px;
@@ -333,58 +334,58 @@ html[xmlns] .clearfix {
   line-height: 14px;
   vertical-align: text-top;
 }
-#helios .tool_container .pane .nav-pills i.announcement {
+body[id="helios"] .tool_container .pane .nav-pills i.announcement {
   background-image: url('../images/announcement.png');
 }
-#helios .tool_container .pane .nav-pills i.class {
+body[id="helios"] .tool_container .pane .nav-pills i.class {
   background-image: url('../images/class.png');
 }
-#helios .tool_container .pane .nav-pills i.collection {
+body[id="helios"] .tool_container .pane .nav-pills i.collection {
   background-image: url('../images/collection.png');
 }
-#helios .tool_container .pane .nav-pills i.test {
+body[id="helios"] .tool_container .pane .nav-pills i.test {
   background-image: url('../images/test.png');
 }
-#helios .tool_container .pane .nav-pills i.exception {
+body[id="helios"] .tool_container .pane .nav-pills i.exception {
   background-image: url('../images/exception.png');
 }
-#helios .tool_container .pane .nav-pills i.widget {
+body[id="helios"] .tool_container .pane .nav-pills i.widget {
   background-image: url('../images/widget.png');
 }
-#helios .tool_container .pane .nav-pills i.magnitude {
+body[id="helios"] .tool_container .pane .nav-pills i.magnitude {
   background-image: url('../images/magnitude.png');
 }
-#helios .tool_container .pane .nav-pills i.package {
+body[id="helios"] .tool_container .pane .nav-pills i.package {
   background-image: url('../images/package.png');
 }
-#helios .tool_container .pane .nav-pills i.private {
+body[id="helios"] .tool_container .pane .nav-pills i.private {
   background-image: url('../images/private.png');
 }
-#helios .tool_container .pane .nav-pills i.extension {
+body[id="helios"] .tool_container .pane .nav-pills i.extension {
   background-image: url('../images/extension.png');
 }
-#helios .tool_container .pane .nav-pills i.initialization {
+body[id="helios"] .tool_container .pane .nav-pills i.initialization {
   background-image: url('../images/initialization.png');
 }
-#helios .tool_container .pane .nav-pills i.package {
+body[id="helios"] .tool_container .pane .nav-pills i.package {
   background-image: url('../images/package.png');
 }
-#helios .tool_container .pane .nav-pills i.override {
+body[id="helios"] .tool_container .pane .nav-pills i.override {
   background-image: url('../images/override.png ');
 }
-#helios .tool_container .pane .nav-pills i.overridden {
+body[id="helios"] .tool_container .pane .nav-pills i.overridden {
   background-image: url('../images/overridden.png');
 }
-#helios .tool_container .pane .nav-pills i.override-overridden {
+body[id="helios"] .tool_container .pane .nav-pills i.override-overridden {
   background-image: url('../images/override-overridden.png');
 }
-#helios .tool_container .pane .nav-pills i.warning {
+body[id="helios"] .tool_container .pane .nav-pills i.warning {
   background-image: url('../images/warning.gif');
 }
-#helios .tool_container .pane .nav-pills i.uncommented {
+body[id="helios"] .tool_container .pane .nav-pills i.uncommented {
   background-image: url('../images/uncommented.png');
 }
-#helios .tool_container .list-label {
+body[id="helios"] .tool_container .list-label {
   font-size: 11px;
   border-radius: 0;
   border-bottom: 1px solid #999;
@@ -402,32 +403,32 @@ html[xmlns] .clearfix {
   height: 15px;
   text-shadow: 0 1px 0 #eee;
 }
-#helios .tool_container .list-label .btn-group.cog {
+body[id="helios"] .tool_container .list-label .btn-group.cog {
   position: absolute;
   top: 0;
   right: 0;
   padding: 0;
   margin: 0;
 }
-#helios .tool_container .list-label .btn-group.open .dropdown-toggle {
+body[id="helios"] .tool_container .list-label .btn-group.open .dropdown-toggle {
   box-shadow: 0 0 0;
   border: 0;
 }
-#helios .tool_container .list-label .btn-group > .dropdown-menu {
+body[id="helios"] .tool_container .list-label .btn-group > .dropdown-menu {
   padding: 0;
   font-size: 11px;
 }
-#helios .tool_container .list-label .btn-group.cog i {
+body[id="helios"] .tool_container .list-label .btn-group.cog i {
   margin-top: 1px;
 }
-#helios .tool_container .list-label .cog .btn.dropdown-toggle {
+body[id="helios"] .tool_container .list-label .cog .btn.dropdown-toggle {
   padding: 0;
   margin: 0;
   line-height: 12px;
   border: 0;
   background: transparent;
 }
-#helios .tool_container .panes .pane .pane_actions {
+body[id="helios"] .tool_container .panes .pane .pane_actions {
   position: absolute;
   overflow: hidden;
   width: 100%;
@@ -436,8 +437,8 @@ html[xmlns] .clearfix {
   padding: 0;
   margin: 0;
 }
-#helios .tool_container .pane_actions,
-#helios .tool_container .buttons_bar {
+body[id="helios"] .tool_container .pane_actions,
+body[id="helios"] .tool_container .buttons_bar {
   background: #dadada;
   border-top: 1px solid #666;
   background-image: -webkit-linear-gradient(top, #dadada, #bdbdbd);
@@ -445,17 +446,17 @@ html[xmlns] .clearfix {
   background-image: -o-linear-gradient(top, #dadada, #bdbdbd);
   background-image: linear-gradient(top, #dadada, #bdbdbd);
 }
-#helios .tool_container .panes .pane .pane_actions .info {
+body[id="helios"] .tool_container .panes .pane .pane_actions .info {
   padding: 10px 5px 5px;
   font-weight: bold;
   color: #666;
   line-height: 20px;
 }
-#helios .tool_container .panes .pane .pane_actions .btn-group {
+body[id="helios"] .tool_container .panes .pane .pane_actions .btn-group {
   display: inline;
   margin-left: 5px;
 }
-#helios .tool_container .panes .pane .pane_actions label {
+body[id="helios"] .tool_container .panes .pane .pane_actions label {
   display: inline-block;
   padding-left: 30px;
   font-size: 11px;
@@ -464,13 +465,13 @@ html[xmlns] .clearfix {
   text-shadow: #ddd 0px 1px 0px;
   color: #222;
 }
-#helios .tool_container .panes .pane .pane_actions label input {
+body[id="helios"] .tool_container .panes .pane .pane_actions label input {
   float: none;
   vertical-align: top;
   margin-top: 2px;
   margin-right: 5px;
 }
-#helios .tool_container .panes .pane .pane_actions .btn {
+body[id="helios"] .tool_container .panes .pane .pane_actions .btn {
   background: transparent;
   border: 0;
   font-size: 11px;
@@ -482,13 +483,13 @@ html[xmlns] .clearfix {
   vertical-align: top;
   /* min-width: 50px; */
 }
-#helios .tool_container .panes .pane .pane_actions .btn:hover {
+body[id="helios"] .tool_container .panes .pane .pane_actions .btn:hover {
   background-color: #bbb;
 }
-#helios .tool_container .panes .pane .pane_actions .btn-group .btn:hover {
+body[id="helios"] .tool_container .panes .pane .pane_actions .btn-group .btn:hover {
   background-color: transparent;
 }
-#helios .tool_container .panes .pane .pane_actions .btn-group .btn.active {
+body[id="helios"] .tool_container .panes .pane .pane_actions .btn-group .btn.active {
   text-shadow: #ddd 0px 1px 0px;
   color: #222;
   background: #bbb;
@@ -497,64 +498,81 @@ html[xmlns] .clearfix {
   background-image: -moz-linear-gradient(left, #777777 0%, #bababa 2px, transparent 2px), -moz-linear-gradient(right, #777777 0%, #bababa 2px, transparent 2px);
   background-image: -o-linear-gradient(left, #777777 0%, #bababa 2px, transparent 2px), -o-linear-gradient(right, #777777 0%, #bababa 2px, transparent 2px);
 }
-#helios .tool_container .panes .pane .class_side .nav-pills {
+body[id="helios"] .tool_container .panes .pane .class_side .nav-pills {
   font-weight: bold;
   background: #ffffdd;
 }
-#helios .key_helper {
-  z-index: 20;
+body[id="helios"] .key_helper {
+  z-index: 2001;
   position: fixed;
-  bottom: 0px;
-  background: #fff;
-  background-image: linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-  background-image: -moz-linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-  background-image: -o-linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-  background-image: -webkit-linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-  width: 100%;
-  border-top: 1px solid #aaa;
+  top: 120px;
+  left: 50%;
+  width: 400px;
+  max-height: 300px;
+  margin-left: -200px;
+  background: white;
+  box-shadow: 0 0 6px #aaa;
+  border: 1px solid #aaa;
   font-size: 11px;
-  height: 22px;
+  transition: all .5s;
+  -webkit-transition: all .5s;
+  -moz-transition: all .5s;
+  -o-transition: all .5s;
+  -ms-transition: all .5s;
 }
-#helios .key_helper .command {
-  padding: 0 2px;
+body[id="helios"] .key_helper .command {
+  padding: 0;
+  display: inline-block;
+  width: 50%;
 }
-#helios .key_helper #binding-helper-main {
-  display: inline;
+body[id="helios"] .key_helper .command strong {
+  display: inline-block;
+  min-width: 1.4em;
+  text-align: left;
 }
-#helios .key_helper .label {
+body[id="helios"] .key_helper #binding-helper-main {
+  display: block;
+  padding: 5px;
+}
+body[id="helios"] .key_helper .label {
   padding: 1px 4px;
   font-family: Menlo, Monaco, "Lucida Console", Courier, monospace;
   background: transparent;
-  color: #08C;
+  color: #0E4561;
   text-shadow: none;
   border: 0 none;
 }
-#helios .key_helper .action {
-  padding: 0 5px;
-  color: #666;
+body[id="helios"] .key_helper .action {
+  padding: 0 0.5em 0 5px;
+  color: inherit;
+  font-weight: bold;
 }
-#helios .key_helper .selected {
-  background-image: linear-gradient(top, #cccccc, #aaaaaa);
-  background-image: -moz-linear-gradient(top, #cccccc, #aaaaaa);
-  background-image: -o-linear-gradient(top, #cccccc, #aaaaaa);
-  background-image: -webkit-linear-gradient(top, #cccccc, #aaaaaa);
-  height: 30px;
+body[id="helios"] .key_helper .selected {
+  background-image: linear-gradient(top, #cccccc, #bbbbbb);
+  background-image: -moz-linear-gradient(top, #cccccc, #bbbbbb);
+  background-image: -o-linear-gradient(top, #cccccc, #bbbbbb);
+  background-image: -webkit-linear-gradient(top, #cccccc, #bbbbbb);
+  height: 28px;
   padding: 0 8px;
-  color: #333;
   font-weight: bold;
+  font-size: 18px;
+  line-height: 28px;
   text-shadow: 0 1px 0 #fff;
-  display: inline-block;
-  border-right: 1px solid #aaa;
+  display: block;
+  border-bottom: 1px solid #aaa;
 }
-#helios .key_helper .close {
+body[id="helios"] .key_helper .close {
   font-size: 14px;
-  line-height: 26px;
+  line-height: 28px;
   opacity: 0.6;
+  position: absolute;
+  top: 0;
+  right: 4px;
 }
-#helios .key_helper .close:hover {
+body[id="helios"] .key_helper .close:hover {
   opacity: 0.8;
 }
-#helios .key_helper input {
+body[id="helios"] .key_helper input {
   outline: none;
   font-size: 11px;
   padding: 2px 8px;
@@ -565,17 +583,12 @@ html[xmlns] .clearfix {
   margin: 2px 4px;
   line-height: 1em;
 }
-#helios .key_helper .error .help-inline,
-#helios .key_helper .error input {
+body[id="helios"] .key_helper .error .help-inline,
+body[id="helios"] .key_helper .error input {
   color: #B91010;
   font-weight: bold;
 }
-#helios .key_helper .typeahead.dropdown-menu {
-  position: fixed !important;
-  top: auto !important;
-  bottom: 30px !important;
-}
-#helios .key_helper #cog-helper {
+body[id="helios"] .key_helper #cog-helper {
   position: fixed;
   bottom: 2px;
   right: 2px;
@@ -587,10 +600,10 @@ html[xmlns] .clearfix {
   -o-transition: all .5s;
   -ms-transition: all .5s;
 }
-#helios .key_helper #cog-helper:hover {
+body[id="helios"] .key_helper #cog-helper:hover {
   opacity: 1;
 }
-#helios #helper {
+body[id="helios"] #helper {
   z-index: 300;
   top: 50%;
   position: absolute;
@@ -607,17 +620,20 @@ html[xmlns] .clearfix {
   background: rgba(0, 0, 0, 0.6);
   border-radius: 40px;
 }
-#helios #overlay {
+body[id="helios"] #overlay {
   z-index: 2000;
-  background: transparent;
+  background: rgba(112, 66, 20, 0.1);
   position: fixed;
   top: 0;
   left: 0;
   right: 0;
   bottom: 0;
 }
-#helios .confirmation,
-#helios .dialog {
+body[id="helios"] #overlay.light {
+  background: rgba(50, 50, 50, 0.1);
+}
+body[id="helios"] .confirmation,
+body[id="helios"] .dialog {
   z-index: 2001;
   background: rgba(243, 243, 243, 0.9);
   background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0) 5px, transparent 6px);
@@ -636,71 +652,67 @@ html[xmlns] .clearfix {
   -moz-transition: top .5s;
   -o-transition: top .5s;
 }
-#helios .confirmation .hl_widget:focus,
-#helios .dialog .hl_widget:focus {
-  outline: 0 none;
-}
-#helios .confirmation .hl_widget .form-actions,
-#helios .dialog .hl_widget .form-actions {
+body[id="helios"] .confirmation .hl_widget .form-actions,
+body[id="helios"] .dialog .hl_widget .form-actions {
   padding: 0;
   border: 0;
 }
-#helios .confirmation .nav,
-#helios .dialog .nav {
+body[id="helios"] .confirmation .nav,
+body[id="helios"] .dialog .nav {
   border: 1px solid #999;
 }
-#helios .confirmation .nav span,
-#helios .dialog .nav span {
+body[id="helios"] .confirmation .nav span,
+body[id="helios"] .dialog .nav span {
   font-size: 11px;
   font-weight: normal;
 }
-#helios .confirmation .title,
-#helios .dialog .title {
+body[id="helios"] .confirmation .title,
+body[id="helios"] .dialog .title {
   font-size: 16px;
   margin-bottom: 15px;
 }
-#helios .confirmation .large,
-#helios .dialog .large {
+body[id="helios"] .confirmation.large,
+body[id="helios"] .dialog.large {
   width: 400px;
   margin-left: -220px;
 }
-#helios .confirmation .large textarea,
-#helios .dialog .large textarea {
+body[id="helios"] .confirmation.large textarea,
+body[id="helios"] .dialog.large textarea {
   width: 385px;
   height: 200px;
 }
-#helios .confirmation textarea,
-#helios .dialog textarea {
+body[id="helios"] .confirmation textarea,
+body[id="helios"] .dialog textarea {
   display: block;
   width: 235px;
 }
-#helios .confirmation .progress,
-#helios .dialog .progress {
+body[id="helios"] .confirmation .progress,
+body[id="helios"] .dialog .progress {
   height: 5px;
 }
-#helios .confirmation .progress .bar,
-#helios .dialog .progress .bar {
+body[id="helios"] .confirmation .progress .bar,
+body[id="helios"] .dialog .progress .bar {
   background-color: #e9eaf5;
   background-image: -webkit-linear-gradient(top, #b1bdd5, #8999b8);
   background-image: -moz-linear-gradient(top, #b1bdd5, #8999b8);
   background-image: -o-linear-gradient(top, #b1bdd5, #8999b8);
   background-image: linear-gradient(top, #b1bdd5, #8999b8);
 }
-#helios .confirmation span,
-#helios .dialog span {
+body[id="helios"] .confirmation span,
+body[id="helios"] .dialog span {
   font-size: 13px;
   font-weight: bold;
 }
-#helios .confirmation .buttons,
-#helios .dialog .buttons {
+body[id="helios"] .confirmation .buttons,
+body[id="helios"] .dialog .buttons {
   text-align: right;
   margin-top: 20px;
 }
-#helios .confirmation.active,
-#helios .dialog.active {
+body[id="helios"] .confirmation.active,
+body[id="helios"] .dialog.active {
   top: 0;
 }
-#helios .button {
+body[id="helios"] .button {
   border-radius: 3px !important;
   background: #ccc;
   border: 1px solid #9B9B9B;
@@ -714,7 +726,7 @@ html[xmlns] .clearfix {
   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;
   font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
 }
-#helios .button.default {
+body[id="helios"] .button.default {
   border-top: 1px solid #535273;
   border: 1px solid #4F4D67;
   border-bottom: 1px solid #4B4B58;
@@ -724,63 +736,67 @@ html[xmlns] .clearfix {
   -webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
   box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
 }
-#helios .button:hover {
+body[id="helios"] .button:hover {
   cursor: pointer;
   border: 1px solid rgba(0, 0, 0, 0.6);
 }
-#helios .button:active {
+body[id="helios"] .button:active {
   -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
   -moz-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
   box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
 }
-#helios .button:focus {
+body[id="helios"] .button:focus {
   outline: 0;
+  border-color: #08C;
+  box-shadow: 0 0 5px #08C;
 }
-#helios .doc {
+body[id="helios"] .doc {
   background: white;
 }
-#helios .doc code .doc pre {
-  font-size: 11px;
+body[id="helios"] .doc code .doc pre,
+body[id="helios"] .doc p,
+body[id="helios"] .doc div {
+  font-size: 13px;
 }
-#helios .doc code {
+body[id="helios"] .doc code {
   padding: 1px 4px;
 }
-#helios .doc .head {
+body[id="helios"] .doc .head {
   background: #08C;
   padding: 10px;
   font-size: 22px;
   color: white;
 }
-#helios .doc .button {
+body[id="helios"] .doc .button {
   float: right;
 }
-#helios .doc .markdown,
-#helios .doc .inheritance {
+body[id="helios"] .doc .markdown,
+body[id="helios"] .doc .inheritance {
   padding: 10px;
 }
-#helios .doc h1 {
+body[id="helios"] .doc h1 {
   font-size: 22px;
   margin: 0 10px;
   border-bottom: 1px solid #666;
 }
-#helios .doc h2 {
+body[id="helios"] .doc h2 {
   font-size: 16px;
 }
-#helios .transcript_container .list-label {
+body[id="helios"] .transcript_container .list-label {
   height: 16px;
   position: absolute;
   top: 0;
   right: 0;
   left: 0;
 }
-#helios .transcript {
+body[id="helios"] .transcript {
   position: absolute;
   top: 17px;
   bottom: 0;
   left: 0;
   right: 0;
 }
-#helios .transcript textarea {
+body[id="helios"] .transcript textarea {
   width: 100%;
   height: 100%;
   margin: 0;

+ 129 - 113
css/helios.less

@@ -1,33 +1,53 @@
-body {
-    font-size: 11px;
-    font-family: "Lucida Grande", helvetica, arial, sans;
-    background: #eee;
-}
-
 .clearfix:after {
-    content: ".";
-    display: block;
-    clear: both;
-    visibility: hidden;
-    line-height: 0;
-    height: 0;
+	content: ".";
+	display: block;
+	clear: both;
+	visibility: hidden;
+	line-height: 0;
+	height: 0;
 }
 
 .clearfix {
-    display: inline-block;
+	display: inline-block;
 }
 
 html[xmlns] .clearfix {
-    display: block;
+	display: block;
 }
 
 * html .clearfix {
-    height: 1%;
+	height: 1%;
+}
+
+.cm-s-helios {
+	&.CodeMirror {
+		font-family: Menlo, Monaco, Consolas, Inconsolata, "Lucida Console", Courier, monospace;
+		line-height: 16px;
+		font-size: 13px;
+	}
+
+	.CodeMirror-gutter.stops {
+		width: 20px;
+	}
+
+	.highlighted.CodeMirror-linebackground {
+		background-color: #ffffaa;
+	}
+
+	.CodeMirror-gutter-elt .stop {
+		width: 16px;
+		height: 16px;
+		background: url('../images/arrowRight.png');
+		margin-left: 2px;
+	}
 }
 
-#helios {
+body[id="helios"] {
+	font-size: 11px;
+	font-family: "Lucida Grande", "Segoe UI", helvetica, arial, sans-serif;
+	background: #eee;
 
-    a {
+	a {
 		cursor: pointer;
 	}
 
@@ -41,14 +61,13 @@ html[xmlns] .clearfix {
 
 	.CodeMirror {
 		position: absolute;
-		overflow: hidden;
 		height: 100%;
 		width: 100%;
 	}
 
 	.CodeMirror-hints {
 		border-radius: 0;
-		font-family: Menlo, Monaco, "Lucida Console", Courier, monospace;
+		font-family: "Lucida Grande", "Segoe UI", helvetica, arial, sans-serif;
 		font-size: 11px;
 		line-height: 1em;
 		padding: 0;
@@ -60,27 +79,6 @@ html[xmlns] .clearfix {
 		padding: 0 10px;
 	}
 
-	.CodeMirror pre, .CodeMirror .CodeMirror-gutter-elt {
-		font-family: Menlo, Monaco, "Lucida Console",  "Ubuntu Mono", Courier, monospace;
-		line-height: 16px;
-		font-size: 13px;
-	}
-
-	.CodeMirror-gutter.stops {
-		width: 20px;
-	}
-
-	.CodeMirror .highlighted.CodeMirror-linebackground {
-		background-color: #ffffaa;
-	}
-
-	.CodeMirror .CodeMirror-gutter-elt .stop {
-		width: 16px;
-		height: 16px;
-		background: url('../images/arrowRight.png');
-		margin-left: 2px;
-	}
-
 	.state {
 		position: absolute;
 		right: 15px;
@@ -101,6 +99,13 @@ html[xmlns] .clearfix {
 		right: 0;
 	}
 
+	.hl_widget {
+
+		&:focus {
+			outline: 0 none;
+		}
+	}
+
 	.buttons_bar {
 		position: absolute;
 		bottom: 0;
@@ -175,7 +180,6 @@ html[xmlns] .clearfix {
 		}
 	}
 
-
 	.navbar-fixed-top .navbar-inner {
 		min-height: 20px;
 		background-color: #dbdbdb;
@@ -187,12 +191,10 @@ html[xmlns] .clearfix {
 		box-shadow: 0 0 0;
 	}
 
-
 	.navbar .nav > li {
 		line-height: 16px;
 	}
 
-
 	.navbar .nav > li > a {
 		line-height: 22px;
 		padding: 0px 8px;
@@ -205,15 +207,15 @@ html[xmlns] .clearfix {
 		background: transparent;
 	}
 
-	.navbar .nav > .active > a, 
-	.navbar .nav > .active > a:hover, 
+	.navbar .nav > .active > a,
+	.navbar .nav > .active > a:hover,
 	.navbar .nav > .active > a:focus {
 		background-color: #bababa;
 		background-image: linear-gradient(left, #777 0%, #bababa 2px, transparent 2px), linear-gradient(right, #777 0%, #bababa 2px, transparent 2px);
 		background-image: -webkit-linear-gradient(left, #777 0%, #bababa 2px, transparent 2px), -webkit-linear-gradient(right, #777 0%, #bababa 2px, transparent 2px);
 		background-image: -moz-linear-gradient(left, #777 0%, #bababa 2px, transparent 2px), -moz-linear-gradient(right, #777 0%, #bababa 2px, transparent 2px);
 		background-image: -o-linear-gradient(left, #777 0%, #bababa 2px, transparent 2px), -o-linear-gradient(right, #777 0%, #bababa 2px, transparent 2px);
-		text-shadow: #ddd 0px 1px 0px; 
+		text-shadow: #ddd 0px 1px 0px;
 		color: #222;
 	}
 
@@ -259,12 +261,12 @@ html[xmlns] .clearfix {
 		background-color: #f3f7fb;
 	}
 
-	.focused .nav-pills > .active > a, 
+	.focused .nav-pills > .active > a,
 	.nav-pills > .active > a:hover,
-	.dropdown-menu li > a:hover, 
-	.dropdown-menu li > a:focus, 
+	.dropdown-menu li > a:hover,
+	.dropdown-menu li > a:focus,
 	.dropdown-submenu:hover > a,
-	.dropdown-menu .active > a, 
+	.dropdown-menu .active > a,
 	.dropdown-menu .active > a:hover,
 	.CodeMirror-hint-active {
 		background: rgba(95, 159, 228, 0.62);
@@ -272,7 +274,6 @@ html[xmlns] .clearfix {
 		text-shadow: 0 0 0;
 	}
 
-
 	.tool_container {
 		position: absolute;
 		top: 23px;
@@ -346,7 +347,6 @@ html[xmlns] .clearfix {
 		right: 50%;
 	}
 
-
 	.tool_container .splitter {
 		position: absolute;
 		border-width: 0;
@@ -372,8 +372,6 @@ html[xmlns] .clearfix {
 		cursor: ns-resize;
 	}
 
-
-
 	.tool_container .panes .pane .nav-pills {
 		position: absolute;
 		overflow-y: auto;
@@ -446,8 +444,6 @@ html[xmlns] .clearfix {
 		background-image: url('../images/uncommented.png');
 	}
 
-
-
 	.tool_container .list-label {
 		font-size: 11px;
 		border-radius: 0;
@@ -497,7 +493,6 @@ html[xmlns] .clearfix {
 		background: transparent;
 	}
 
-
 	.tool_container .panes .pane .pane_actions {
 		position: absolute;
 		overflow: hidden;
@@ -535,7 +530,7 @@ html[xmlns] .clearfix {
 		font-size: 11px;
 		line-height: 16px;
 		vertical-align: top;
-		text-shadow: #ddd 0px 1px 0px; 
+		text-shadow: #ddd 0px 1px 0px;
 		color: #222;
 
 	}
@@ -557,7 +552,7 @@ html[xmlns] .clearfix {
 		border-radius: 0;
 		box-shadow: 0 0 0;
 		vertical-align: top;
-	/* min-width: 50px; */
+		/* min-width: 50px; */
 	}
 
 	.tool_container .panes .pane .pane_actions .btn:hover {
@@ -569,7 +564,7 @@ html[xmlns] .clearfix {
 	}
 
 	.tool_container .panes .pane .pane_actions .btn-group .btn.active {
-		text-shadow: #ddd 0px 1px 0px; 
+		text-shadow: #ddd 0px 1px 0px;
 		color: #222;
 		background: #bbb;
 		background-image: linear-gradient(left, #777 0%, #bababa 2px, transparent 2px), linear-gradient(right, #777 0%, #bababa 2px, transparent 2px);
@@ -584,59 +579,79 @@ html[xmlns] .clearfix {
 	}
 
 	.key_helper {
-		z-index: 20;
+		z-index: 2001;
 		position: fixed;
-		bottom: 0px;
-		background: #fff;
-		background-image: linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-		background-image: -moz-linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-		background-image: -o-linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-		background-image: -webkit-linear-gradient(top, #fafafa, #f0f0f0 50%, #e1e1e1 51%);
-		width: 100%;
-		border-top: 1px solid #aaa;
+		top: 120px;
+		left: 50%;
+		width: 400px;
+		max-height: 300px;
+		margin-left: -200px;
+		background: white;
+		box-shadow: 0 0 6px #aaa;
+		border: 1px solid #aaa;
 		font-size: 11px;
-		height: 22px;
+
+		transition: all .5s;
+		-webkit-transition: all .5s;
+		-moz-transition: all .5s;
+		-o-transition: all .5s;
+		-ms-transition: all .5s;
+
 
 		.command {
-			padding: 0 2px;
+			padding: 0;
+			display: inline-block;
+			width: 50%;
+
+			strong {
+				display: inline-block;
+				min-width: 1.4em;
+				text-align: left;
+			}
 		}
 
 		#binding-helper-main {
-			display: inline;
+			display: block;
+			padding: 5px;
 		}
 
 		.label {
 			padding: 1px 4px;
 			font-family: Menlo, Monaco, "Lucida Console", Courier, monospace;
 			background: transparent;
-			color: #08C;
+			color: #0E4561;
 			text-shadow: none;
 			border: 0 none;
 		}
 
 		.action {
-			padding: 0 5px;
-			color: #666;
+			padding: 0 0.5em 0 5px;
+			color: inherit;
+			font-weight: bold;
 		}
 
 		.selected {
-			background-image: linear-gradient(top, #ccc, #aaa);
-			background-image: -moz-linear-gradient(top, #ccc, #aaa);
-			background-image: -o-linear-gradient(top, #ccc, #aaa);
-			background-image: -webkit-linear-gradient(top, #ccc, #aaa);
-			height: 30px;
+			background-image: linear-gradient(top, #ccc, #bbb);
+			background-image: -moz-linear-gradient(top, #ccc, #bbb);
+			background-image: -o-linear-gradient(top, #ccc, #bbb);
+			background-image: -webkit-linear-gradient(top, #ccc, #bbb);
+			height: 28px;
 			padding: 0 8px;
-			color: #333;
 			font-weight: bold;
+			font-size: 18px;
+			line-height: 28px;
 			text-shadow: 0 1px 0 #fff;
-			display: inline-block;
-			border-right: 1px solid #aaa;
+			display: block;
+			border-bottom: 1px solid #aaa;
 		}
 
 		.close {
 			font-size: 14px;
-			line-height: 26px;
+			line-height: 28px;
 			opacity: 0.6;
+			position: absolute;
+			top: 0;
+			right: 4px;
 		}
 
 		.close:hover {
@@ -661,11 +676,11 @@ html[xmlns] .clearfix {
 			font-weight: bold;
 		}
 
-		.typeahead.dropdown-menu {
-			position: fixed !important;
-			top: auto !important;
-			bottom: 30px !important;
-		}
+		// .typeahead.dropdown-menu {
+		// 	position: fixed !important;
+		// 	top: auto !important;
+		// 	bottom: 30px !important;
+		// }
 
 		#cog-helper {
 			position: fixed;
@@ -700,27 +715,31 @@ html[xmlns] .clearfix {
 		font-weight: bold;
 		text-shadow: 0 -1px 0 #111;
 		padding: 20px;
-		background: rgba(0,0,0, 0.6);
+		background: rgba(0, 0, 0, 0.6);
 		border-radius: 40px;
 	}
 
 	#overlay {
 		z-index: 2000;
-		background: transparent;
+		background: rgba(112, 66, 20, 0.1);
 		position: fixed;
 		top: 0;
 		left: 0;
 		right: 0;
 		bottom: 0;
+
+		&.light {
+			background: rgba(50, 50, 50, 0.1);
+		}
 	}
 
 	.confirmation, .dialog {
 		z-index: 2001;
-		background: rgba(243,243,243,0.9);
-		background-image: -webkit-linear-gradient(top, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0) 5px, transparent 6px);
-		background-image: -moz-linear-gradient(top, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0) 5px, transparent 6px);
-		background-image: -o-linear-gradient(top, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0) 5px, transparent 6px);
-		background-image: linear-gradient(top, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0) 5px, transparent 6px);
+		background: rgba(243, 243, 243, 0.9);
+		background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0) 5px, transparent 6px);
+		background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0) 5px, transparent 6px);
+		background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0) 5px, transparent 6px);
+		background-image: linear-gradient(top, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0) 5px, transparent 6px);
 		padding: 20px;
 		width: 250px;
 		position: fixed;
@@ -734,10 +753,6 @@ html[xmlns] .clearfix {
 		-o-transition: top .5s;
 
 		.hl_widget {
-			
-			&:focus {
-				outline: 0 none;
-			}
 
 			.form-actions {
 				padding: 0;
@@ -759,7 +774,7 @@ html[xmlns] .clearfix {
 			margin-bottom: 15px;
 		}
 
-		.large {
+		&.large {
 			width: 400px;
 			margin-left: -220px;
 
@@ -812,43 +827,44 @@ html[xmlns] .clearfix {
 		text-align: center;
 		margin: 0;
 		margin-left: 10px;
-		background: -webkit-linear-gradient(bottom, rgba(0,0,0,.09) 0%, rgba(0,0,0, 0.02) 50%, rgba(0,0,0,.04) 50.5%, rgba(0,0,0,.04) 100%) #fff;
+		background: -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;
 		font: 13px "Lucida Grande", Lucida, Verdana, sans-serif;
 	}
 
-	.button.default { 
+	.button.default {
 		border-top: 1px solid #535273;
 		border: 1px solid #4F4D67;
-		border-bottom: 1px solid #4B4B58;	 
-		background: -webkit-linear-gradient(bottom, rgba(255,255,255,.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255,255,255,.3) 50.5%, rgba(255,255,255,.45) 95%, rgba(255,255,255,.8) 100%) #b1bdd5;
-		background: -moz-linear-gradient(bottom, rgba(255,255,255,.5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255,255,255,.3) 50.5%, rgba(255,255,255,.45) 95%, rgba(255,255,255,.8) 100%) #b1bdd5;
+		border-bottom: 1px solid #4B4B58;
+		background: -webkit-linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
+		background: -moz-linear-gradient(bottom, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, .3) 50.5%, rgba(255, 255, 255, .45) 95%, rgba(255, 255, 255, .8) 100%) #b1bdd5;
 		-moz-box-shadow: 0 0 3px rgba(69, 113, 184, 0.8);
 		-webkit-box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
 		box-shadow: 0 0 5px rgba(69, 113, 184, 0.44);
 	}
 
-
 	.button:hover {
 		cursor: pointer;
-		border: 1px solid rgba(0,0,0,.6);
+		border: 1px solid rgba(0, 0, 0, .6);
 	}
 
 	.button:active {
-		-webkit-box-shadow: inset 0 0 5px rgba(0,0,0,.5);
-		-moz-box-shadow: inset 0 0 5px rgba(0,0,0,.5);
-		box-shadow: inset 0 0 5px rgba(0,0,0,.5);
+		-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, .5);
+		-moz-box-shadow: inset 0 0 5px rgba(0, 0, 0, .5);
+		box-shadow: inset 0 0 5px rgba(0, 0, 0, .5);
 	}
 
 	.button:focus {
 		outline: 0;
+		border-color: #08C;
+		box-shadow: 0 0 5px #08C;
 	}
 
 	.doc {
 		background: white;
 	}
 
-	.doc code .doc pre {
-		font-size: 11px;
+	.doc code .doc pre, .doc p, .doc div {
+		font-size: 13px;
 	}
 
 	.doc code {

+ 1 - 2
helios.html

@@ -20,8 +20,7 @@
                           return 'Do you want to close Amber? All uncommitted changes will be lost.';
                       };
 
-                      smalltalk.vm.defaultAmdNamespace = "amber_core";
-                      smalltalk.vm.initialize();
+                      smalltalk.initialize({'transport.defaultAmdNamespace': "amber_core"});
 					  smalltalk.globals.HLManager._setup();
                   }
           );

+ 1 - 5
index.html

@@ -15,11 +15,7 @@
     require(
         ["amber/devel", "amber_core/Moka-Core", "amber_core/Moka-Announcements", "amber_core/Moka-Controllers", "amber_core/Moka-Views", "amber_core/Moka-Decorators", "amber_core/Moka-Layouts", "amber_core/Moka-Examples"],
         function (smalltalk) {
-            smalltalk.defaultAmdNamespace = "amber_core";
-            smalltalk.initialize();
-			smalltalk.MKClassesListBuilder._new()._build();
-			smalltalk.MKCounterBuilder._new()._build();
-
+            smalltalk.initialize({'transport.defaultAmdNamespace': "amber_core"});
 
 	    require('amber/helpers').popupHelios();
         }

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


+ 90 - 40
js/Canvas.js

@@ -2334,7 +2334,7 @@ return smalltalk.withContext(function($ctx1) {
 var $2,$1;
 $2=self["@snippets"];
 if(($receiver = $2) == nil || $receiver == null){
-self["@snippets"]=globals.HashedCollection._from_([]);
+self["@snippets"]=globals.HashedCollection._newFromPairs_([]);
 $1=self["@snippets"];
 } else {
 $1=$2;
@@ -2672,6 +2672,24 @@ referencedClasses: []
 }),
 globals.TagBrush);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJQueryInContext:",
+protocol: 'converting',
+fn: function (aContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._element())._asJQueryInContext_(aContext);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asJQueryInContext:",{aContext:aContext},globals.TagBrush)})},
+args: ["aContext"],
+source: "asJQueryInContext: aContext\x0a\x09^ self element asJQueryInContext: aContext",
+messageSends: ["asJQueryInContext:", "element"],
+referencedClasses: []
+}),
+globals.TagBrush);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "at:",
@@ -3720,38 +3738,6 @@ referencedClasses: []
 }),
 globals.Widget.klass);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "appendToBrush:",
-protocol: '*Canvas',
-fn: function (aTagBrush){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(aTagBrush)._append_(self._asString());
-return self}, function($ctx1) {$ctx1.fill(self,"appendToBrush:",{aTagBrush:aTagBrush},globals.Object)})},
-args: ["aTagBrush"],
-source: "appendToBrush: aTagBrush\x0a\x09aTagBrush append: self asString",
-messageSends: ["append:", "asString"],
-referencedClasses: []
-}),
-globals.Object);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "appendToJQuery:",
-protocol: '*Canvas',
-fn: function (aJQuery){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(aJQuery)._append_(self._asString());
-return self}, function($ctx1) {$ctx1.fill(self,"appendToJQuery:",{aJQuery:aJQuery},globals.Object)})},
-args: ["aJQuery"],
-source: "appendToJQuery: aJQuery\x0a\x09aJQuery append: self asString",
-messageSends: ["append:", "asString"],
-referencedClasses: []
-}),
-globals.Object);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToBrush:",
@@ -3804,6 +3790,70 @@ referencedClasses: ["HTMLSnippet"]
 }),
 globals.CharacterArray);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJQuery",
+protocol: '*Canvas',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return jQuery(self['@jsObject']);
+return self}, function($ctx1) {$ctx1.fill(self,"asJQuery",{},globals.JSObjectProxy)})},
+args: [],
+source: "asJQuery\x0a\x09<return jQuery(self['@jsObject'])>",
+messageSends: [],
+referencedClasses: []
+}),
+globals.JSObjectProxy);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJQueryInContext:",
+protocol: '*Canvas',
+fn: function (aContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return jQuery(self['@jsObject'], aContext);
+return self}, function($ctx1) {$ctx1.fill(self,"asJQueryInContext:",{aContext:aContext},globals.JSObjectProxy)})},
+args: ["aContext"],
+source: "asJQueryInContext: aContext\x0a\x09<return jQuery(self['@jsObject'], aContext)>",
+messageSends: [],
+referencedClasses: []
+}),
+globals.JSObjectProxy);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "appendToBrush:",
+protocol: '*Canvas',
+fn: function (aTagBrush){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(aTagBrush)._append_(self._asString());
+return self}, function($ctx1) {$ctx1.fill(self,"appendToBrush:",{aTagBrush:aTagBrush},globals.Object)})},
+args: ["aTagBrush"],
+source: "appendToBrush: aTagBrush\x0a\x09aTagBrush append: self asString",
+messageSends: ["append:", "asString"],
+referencedClasses: []
+}),
+globals.Object);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "appendToJQuery:",
+protocol: '*Canvas',
+fn: function (aJQuery){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(aJQuery)._append_(self._asString());
+return self}, function($ctx1) {$ctx1.fill(self,"appendToJQuery:",{aJQuery:aJQuery},globals.Object)})},
+args: ["aJQuery"],
+source: "appendToJQuery: aJQuery\x0a\x09aJQuery append: self asString",
+messageSends: ["append:", "asString"],
+referencedClasses: []
+}),
+globals.Object);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "appendToBrush:",
@@ -3854,18 +3904,18 @@ globals.String);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "asJQuery",
+selector: "asJQueryInContext:",
 protocol: '*Canvas',
-fn: function (){
+fn: function (aContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return jQuery(self['@jsObject']);
-return self}, function($ctx1) {$ctx1.fill(self,"asJQuery",{},globals.JSObjectProxy)})},
-args: [],
-source: "asJQuery\x0a\x09<return jQuery(self['@jsObject'])>",
+return jQuery(String(self), aContext);
+return self}, function($ctx1) {$ctx1.fill(self,"asJQueryInContext:",{aContext:aContext},globals.String)})},
+args: ["aContext"],
+source: "asJQueryInContext: aContext\x0a\x09<return jQuery(String(self), aContext)>",
 messageSends: [],
 referencedClasses: []
 }),
-globals.JSObjectProxy);
+globals.String);
 
 });

+ 27 - 15
st/Canvas.st → js/Canvas.st

@@ -927,6 +927,10 @@ width: aString
 
 asJQuery
 	^ self element asJQuery
+!
+
+asJQueryInContext: aContext
+	^ self element asJQueryInContext: aContext
 ! !
 
 !TagBrush methodsFor: 'events'!
@@ -1093,16 +1097,6 @@ heliosClass
 	^ 'widget'
 ! !
 
-!Object methodsFor: '*Canvas'!
-
-appendToBrush: aTagBrush
-	aTagBrush append: self asString
-!
-
-appendToJQuery: aJQuery
-	aJQuery append: self asString
-! !
-
 !BlockClosure methodsFor: '*Canvas'!
 
 appendToBrush: aTagBrush
@@ -1119,6 +1113,26 @@ asSnippet
 	^ HTMLSnippet current snippetAt: self asString
 ! !
 
+!JSObjectProxy methodsFor: '*Canvas'!
+
+asJQuery
+	<return jQuery(self['@jsObject'])>
+!
+
+asJQueryInContext: aContext
+	<return jQuery(self['@jsObject'], aContext)>
+! !
+
+!Object methodsFor: '*Canvas'!
+
+appendToBrush: aTagBrush
+	aTagBrush append: self asString
+!
+
+appendToJQuery: aJQuery
+	aJQuery append: self asString
+! !
+
 !String methodsFor: '*Canvas'!
 
 appendToBrush: aTagBrush
@@ -1131,11 +1145,9 @@ appendToJQuery: aJQuery
 
 asJQuery
 	<return jQuery(String(self))>
-! !
-
-!JSObjectProxy methodsFor: '*Canvas'!
+!
 
-asJQuery
-	<return jQuery(self['@jsObject'])>
+asJQueryInContext: aContext
+	<return jQuery(String(self), aContext)>
 ! !
 

+ 17 - 19
js/Compiler-AST.js

@@ -351,9 +351,8 @@ try {
 $1=self._nodes();
 $ctx1.sendIdx["nodes"]=1;
 next=_st($1)._at_ifAbsent_(_st(_st(self._nodes())._indexOf_(aNode)).__plus((1)),(function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[self];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $2=_st(next)._nextChild();
 return $2;
 }
@@ -566,9 +565,8 @@ $1=_st(_st(self._nodes())._detect_ifNone_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(each)._requiresSmalltalkContext();
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})})))._notNil();
+})))._notNil();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"requiresSmalltalkContext",{},globals.Node)})},
 args: [],
@@ -2428,21 +2426,6 @@ referencedClasses: []
 globals.VariableNode);
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "isNode",
-protocol: '*Compiler-AST',
-fn: function (){
-var self=this;
-return false;
-},
-args: [],
-source: "isNode\x0a\x09^ false",
-messageSends: [],
-referencedClasses: []
-}),
-globals.Object);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "ast",
@@ -2468,4 +2451,19 @@ referencedClasses: ["Smalltalk"]
 }),
 globals.CompiledMethod);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isNode",
+protocol: '*Compiler-AST',
+fn: function (){
+var self=this;
+return false;
+},
+args: [],
+source: "isNode\x0a\x09^ false",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Object);
+
 });

+ 6 - 6
st/Compiler-AST.st → js/Compiler-AST.st

@@ -762,12 +762,6 @@ accept: aVisitor
 	^ aVisitor visitVariableNode: self
 ! !
 
-!Object methodsFor: '*Compiler-AST'!
-
-isNode
-	^ false
-! !
-
 !CompiledMethod methodsFor: '*Compiler-AST'!
 
 ast
@@ -776,3 +770,9 @@ ast
 	^ Smalltalk parse: self source
 ! !
 
+!Object methodsFor: '*Compiler-AST'!
+
+isNode
+	^ false
+! !
+

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


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


+ 82 - 76
js/Compiler-IR.js

@@ -295,6 +295,7 @@ var $1,$2,$3,$4,$6,$5,$7,$8,$9;
 $1=_st($IRClosure())._new();
 $ctx1.sendIdx["new"]=1;
 _st($1)._arguments_(_st(aNode)._parameters());
+_st($1)._requiresSmalltalkContext_(_st(aNode)._requiresSmalltalkContext());
 $2=$1;
 $3=_st(aNode)._scope();
 $ctx1.sendIdx["scope"]=1;
@@ -324,8 +325,8 @@ $9=closure;
 return $9;
 }, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode,closure:closure},globals.IRASTTranslator)})},
 args: ["aNode"],
-source: "visitBlockNode: aNode\x0a\x09| closure |\x0a\x09closure := IRClosure new\x0a\x09\x09arguments: aNode parameters;\x0a\x09\x09scope: aNode scope;\x0a\x09\x09yourself.\x0a\x09aNode scope temps do: [ :each |\x0a\x09\x09closure add: (IRTempDeclaration new\x0a\x09\x09\x09name: each name;\x0a\x09\x09\x09scope: aNode scope;\x0a\x09\x09\x09yourself) ].\x0a\x09aNode nodes do: [ :each | closure add: (self visit: each) ].\x0a\x09^ closure",
-messageSends: ["arguments:", "new", "parameters", "scope:", "scope", "yourself", "do:", "temps", "add:", "name:", "name", "nodes", "visit:"],
+source: "visitBlockNode: aNode\x0a\x09| closure |\x0a\x09closure := IRClosure new\x0a\x09\x09arguments: aNode parameters;\x0a\x09\x09requiresSmalltalkContext: aNode requiresSmalltalkContext;\x0a\x09\x09scope: aNode scope;\x0a\x09\x09yourself.\x0a\x09aNode scope temps do: [ :each |\x0a\x09\x09closure add: (IRTempDeclaration new\x0a\x09\x09\x09name: each name;\x0a\x09\x09\x09scope: aNode scope;\x0a\x09\x09\x09yourself) ].\x0a\x09aNode nodes do: [ :each | closure add: (self visit: each) ].\x0a\x09^ closure",
+messageSends: ["arguments:", "new", "parameters", "requiresSmalltalkContext:", "requiresSmalltalkContext", "scope:", "scope", "yourself", "do:", "temps", "add:", "name:", "name", "nodes", "visit:"],
 referencedClasses: ["IRClosure", "IRTempDeclaration"]
 }),
 globals.IRASTTranslator);
@@ -1285,7 +1286,7 @@ globals.IRScopedInstruction);
 
 
 
-smalltalk.addClass('IRClosureInstruction', globals.IRScopedInstruction, ['arguments'], 'Compiler-IR');
+smalltalk.addClass('IRClosureInstruction', globals.IRScopedInstruction, ['arguments', 'requiresSmalltalkContext'], 'Compiler-IR');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "arguments",
@@ -1348,6 +1349,44 @@ referencedClasses: []
 }),
 globals.IRClosureInstruction);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "requiresSmalltalkContext",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@requiresSmalltalkContext"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=false;
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"requiresSmalltalkContext",{},globals.IRClosureInstruction)})},
+args: [],
+source: "requiresSmalltalkContext\x0a\x09^ requiresSmalltalkContext ifNil: [ false ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+globals.IRClosureInstruction);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "requiresSmalltalkContext:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@requiresSmalltalkContext"]=anObject;
+return self},
+args: ["anObject"],
+source: "requiresSmalltalkContext: anObject\x0a\x09requiresSmalltalkContext := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.IRClosureInstruction);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "scope:",
@@ -1567,44 +1606,6 @@ referencedClasses: []
 }),
 globals.IRMethod);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "requiresSmalltalkContext",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@requiresSmalltalkContext"];
-if(($receiver = $2) == nil || $receiver == null){
-$1=false;
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"requiresSmalltalkContext",{},globals.IRMethod)})},
-args: [],
-source: "requiresSmalltalkContext\x0a\x09^ requiresSmalltalkContext ifNil: [ false ]",
-messageSends: ["ifNil:"],
-referencedClasses: []
-}),
-globals.IRMethod);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "requiresSmalltalkContext:",
-protocol: 'accessing',
-fn: function (anObject){
-var self=this;
-self["@requiresSmalltalkContext"]=anObject;
-return self},
-args: ["anObject"],
-source: "requiresSmalltalkContext: anObject\x0a\x09requiresSmalltalkContext := anObject",
-messageSends: [],
-referencedClasses: []
-}),
-globals.IRMethod);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selector",
@@ -2990,7 +2991,7 @@ return smalltalk.withContext(function($ctx1) {
 var $1,$2;
 $1=self._stream();
 $ctx1.sendIdx["stream"]=1;
-_st($1)._nextPutAll_("globals.HashedCollection._from_([");
+_st($1)._nextPutAll_("globals.HashedCollection._newFromPairs_([");
 $ctx1.sendIdx["nextPutAll:"]=1;
 _st(_st(anIRDynamicDictionary)._instructions())._do_separatedBy_((function(each){
 return smalltalk.withContext(function($ctx2) {
@@ -3005,7 +3006,7 @@ $ctx2.sendIdx["nextPutAll:"]=2;
 _st(self._stream())._nextPutAll_("])");
 return self}, function($ctx1) {$ctx1.fill(self,"visitIRDynamicDictionary:",{anIRDynamicDictionary:anIRDynamicDictionary},globals.IRJSTranslator)})},
 args: ["anIRDynamicDictionary"],
-source: "visitIRDynamicDictionary: anIRDynamicDictionary\x0a\x09self stream nextPutAll: 'globals.HashedCollection._from_(['.\x0a\x09\x09anIRDynamicDictionary instructions\x0a\x09\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream nextPutAll: '])'",
+source: "visitIRDynamicDictionary: anIRDynamicDictionary\x0a\x09self stream nextPutAll: 'globals.HashedCollection._newFromPairs_(['.\x0a\x09\x09anIRDynamicDictionary instructions\x0a\x09\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream nextPutAll: '])'",
 messageSends: ["nextPutAll:", "stream", "do:separatedBy:", "instructions", "visit:"],
 referencedClasses: []
 }),
@@ -3472,69 +3473,75 @@ protocol: 'streaming',
 fn: function (anIRClosure,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $4,$3,$2,$1,$5,$9,$8,$7,$6,$13,$12,$11,$10,$14,$15,$22,$21,$20,$19,$18,$17,$16;
-$4=_st(anIRClosure)._scope();
+var $1,$2,$6,$5,$4,$3,$7,$11,$10,$9,$8,$15,$14,$13,$12,$16,$17,$24,$23,$22,$21,$20,$19,$18;
+$1=_st(anIRClosure)._requiresSmalltalkContext();
+if(! smalltalk.assert($1)){
+$2=_st(aBlock)._value();
+$ctx1.sendIdx["value"]=1;
+return $2;
+};
+$6=_st(anIRClosure)._scope();
 $ctx1.sendIdx["scope"]=1;
-$3=_st($4)._alias();
+$5=_st($6)._alias();
 $ctx1.sendIdx["alias"]=1;
-$2="return smalltalk.withContext(function(".__comma($3);
+$4="return smalltalk.withContext(function(".__comma($5);
 $ctx1.sendIdx[","]=2;
-$1=_st($2).__comma(") {");
+$3=_st($4).__comma(") {");
 $ctx1.sendIdx[","]=1;
-self._nextPutAll_($1);
+self._nextPutAll_($3);
 $ctx1.sendIdx["nextPutAll:"]=1;
-$5=self._lf();
+$7=self._lf();
 _st(aBlock)._value();
-$9=_st(anIRClosure)._scope();
+$11=_st(anIRClosure)._scope();
 $ctx1.sendIdx["scope"]=2;
-$8=_st($9)._alias();
+$10=_st($11)._alias();
 $ctx1.sendIdx["alias"]=2;
-$7="}, function(".__comma($8);
+$9="}, function(".__comma($10);
 $ctx1.sendIdx[","]=4;
-$6=_st($7).__comma(") {");
+$8=_st($9).__comma(") {");
 $ctx1.sendIdx[","]=3;
-self._nextPutAll_($6);
+self._nextPutAll_($8);
 $ctx1.sendIdx["nextPutAll:"]=2;
-$13=_st(anIRClosure)._scope();
+$15=_st(anIRClosure)._scope();
 $ctx1.sendIdx["scope"]=3;
-$12=_st($13)._alias();
+$14=_st($15)._alias();
 $ctx1.sendIdx["alias"]=3;
-$11=_st($12).__comma(".fillBlock({");
+$13=_st($14).__comma(".fillBlock({");
 $ctx1.sendIdx[","]=5;
-$10=self._nextPutAll_($11);
+$12=self._nextPutAll_($13);
 $ctx1.sendIdx["nextPutAll:"]=3;
 _st(_st(anIRClosure)._locals())._do_separatedBy_((function(each){
 return smalltalk.withContext(function($ctx2) {
-$14=_st(each)._asVariableName();
+$16=_st(each)._asVariableName();
 $ctx2.sendIdx["asVariableName"]=1;
-self._nextPutAll_($14);
+self._nextPutAll_($16);
 $ctx2.sendIdx["nextPutAll:"]=4;
 self._nextPutAll_(":");
 $ctx2.sendIdx["nextPutAll:"]=5;
-$15=self._nextPutAll_(_st(each)._asVariableName());
+$17=self._nextPutAll_(_st(each)._asVariableName());
 $ctx2.sendIdx["nextPutAll:"]=6;
-return $15;
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}),(function(){
+return $17;
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}),(function(){
 return smalltalk.withContext(function($ctx2) {
 return self._nextPutAll_(",");
 $ctx2.sendIdx["nextPutAll:"]=7;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
 self._nextPutAll_("},");
 $ctx1.sendIdx["nextPutAll:"]=8;
-$22=_st(anIRClosure)._scope();
+$24=_st(anIRClosure)._scope();
 $ctx1.sendIdx["scope"]=4;
-$21=_st($22)._outerScope();
-$20=_st($21)._alias();
-$19=_st($20).__comma(",");
-$18=_st($19).__comma(_st(_st(_st(anIRClosure)._scope())._blockIndex())._asString());
+$23=_st($24)._outerScope();
+$22=_st($23)._alias();
+$21=_st($22).__comma(",");
+$20=_st($21).__comma(_st(_st(_st(anIRClosure)._scope())._blockIndex())._asString());
 $ctx1.sendIdx[","]=7;
-$17=_st($18).__comma(")})");
+$19=_st($20).__comma(")})");
 $ctx1.sendIdx[","]=6;
-$16=self._nextPutAll_($17);
+$18=self._nextPutAll_($19);
 return self}, function($ctx1) {$ctx1.fill(self,"nextPutBlockContextFor:during:",{anIRClosure:anIRClosure,aBlock:aBlock},globals.JSStream)})},
 args: ["anIRClosure", "aBlock"],
-source: "nextPutBlockContextFor: anIRClosure during: aBlock\x0a\x09self\x0a\x09\x09nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {'; lf.\x0a\x09\x0a\x09aBlock value.\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '}, function(', anIRClosure scope alias, ') {';\x0a\x09\x09nextPutAll: anIRClosure scope alias, '.fillBlock({'.\x0a\x09\x0a\x09anIRClosure locals\x0a\x09\x09do: [ :each |\x0a\x09\x09\x09self\x0a\x09\x09\x09\x09nextPutAll: each asVariableName;\x0a\x09\x09\x09\x09nextPutAll: ':';\x0a\x09\x09\x09\x09nextPutAll: each asVariableName ]\x0a\x09\x09separatedBy: [ self nextPutAll: ',' ].\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '},';\x0a\x09\x09nextPutAll: anIRClosure scope outerScope alias, ',', anIRClosure scope blockIndex asString, ')})'",
-messageSends: ["nextPutAll:", ",", "alias", "scope", "lf", "value", "do:separatedBy:", "locals", "asVariableName", "outerScope", "asString", "blockIndex"],
+source: "nextPutBlockContextFor: anIRClosure during: aBlock\x0a\x09anIRClosure requiresSmalltalkContext ifFalse: [ ^ aBlock value ].\x0a\x09self\x0a\x09\x09nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {'; lf.\x0a\x09\x0a\x09aBlock value.\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '}, function(', anIRClosure scope alias, ') {';\x0a\x09\x09nextPutAll: anIRClosure scope alias, '.fillBlock({'.\x0a\x09\x0a\x09anIRClosure locals\x0a\x09\x09do: [ :each |\x0a\x09\x09\x09self\x0a\x09\x09\x09\x09nextPutAll: each asVariableName;\x0a\x09\x09\x09\x09nextPutAll: ':';\x0a\x09\x09\x09\x09nextPutAll: each asVariableName ]\x0a\x09\x09separatedBy: [ self nextPutAll: ',' ].\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '},';\x0a\x09\x09nextPutAll: anIRClosure scope outerScope alias, ',', anIRClosure scope blockIndex asString, ')})'",
+messageSends: ["ifFalse:", "requiresSmalltalkContext", "value", "nextPutAll:", ",", "alias", "scope", "lf", "do:separatedBy:", "locals", "asVariableName", "outerScope", "asString", "blockIndex"],
 referencedClasses: []
 }),
 globals.JSStream);
@@ -4030,9 +4037,8 @@ var $1,$2;
 var $early={};
 try {
 _st(aCollection)._ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[self];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 _st(self["@stream"])._nextPutAll_("var ");
 $ctx1.sendIdx["nextPutAll:"]=1;
 _st(aCollection)._do_separatedBy_((function(each){

+ 12 - 10
st/Compiler-IR.st → js/Compiler-IR.st

@@ -113,6 +113,7 @@ visitBlockNode: aNode
 	| closure |
 	closure := IRClosure new
 		arguments: aNode parameters;
+		requiresSmalltalkContext: aNode requiresSmalltalkContext;
 		scope: aNode scope;
 		yourself.
 	aNode scope temps do: [ :each |
@@ -422,7 +423,7 @@ scope: aScope
 ! !
 
 IRScopedInstruction subclass: #IRClosureInstruction
-	instanceVariableNames: 'arguments'
+	instanceVariableNames: 'arguments requiresSmalltalkContext'
 	package: 'Compiler-IR'!
 
 !IRClosureInstruction methodsFor: 'accessing'!
@@ -441,6 +442,14 @@ locals
 		yourself
 !
 
+requiresSmalltalkContext
+	^ requiresSmalltalkContext ifNil: [ false ]
+!
+
+requiresSmalltalkContext: anObject
+	requiresSmalltalkContext := anObject
+!
+
 scope: aScope
 	super scope: aScope.
 	aScope instruction: self
@@ -505,14 +514,6 @@ method
 	^ self
 !
 
-requiresSmalltalkContext
-	^ requiresSmalltalkContext ifNil: [ false ]
-!
-
-requiresSmalltalkContext: anObject
-	requiresSmalltalkContext := anObject
-!
-
 selector
 	^ selector
 !
@@ -962,7 +963,7 @@ visitIRDynamicArray: anIRDynamicArray
 !
 
 visitIRDynamicDictionary: anIRDynamicDictionary
-	self stream nextPutAll: 'globals.HashedCollection._from_(['.
+	self stream nextPutAll: 'globals.HashedCollection._newFromPairs_(['.
 		anIRDynamicDictionary instructions
 			do: [ :each | self visit: each ]
 			separatedBy: [ self stream nextPutAll: ',' ].
@@ -1106,6 +1107,7 @@ nextPutAssignment
 !
 
 nextPutBlockContextFor: anIRClosure during: aBlock
+	anIRClosure requiresSmalltalkContext ifFalse: [ ^ aBlock value ].
 	self
 		nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {'; lf.
 	

+ 1 - 2
js/Compiler-Inlining.js

@@ -783,8 +783,7 @@ return smalltalk.withContext(function($ctx2) {
 return self._visit_(_st(_st(anIRInlinedReturn)._instructions())._last());
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 _st(self._stream())._nextPutNonLocalReturnWith_((function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"visitIRInlinedNonLocalReturn:",{anIRInlinedReturn:anIRInlinedReturn},globals.IRInliningJSTranslator)})},
 args: ["anIRInlinedReturn"],
 source: "visitIRInlinedNonLocalReturn: anIRInlinedReturn\x0a\x09self stream nextPutStatementWith: [\x0a\x09\x09self visit: anIRInlinedReturn instructions last ].\x0a\x09self stream nextPutNonLocalReturnWith: [ ]",

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


+ 20 - 31
js/Compiler-Interpreter.js

@@ -191,9 +191,8 @@ sequenceNode=$2;
 _st(_st(self["@node"])._parameters())._withIndexDo_((function(each,index){
 return smalltalk.withContext(function($ctx2) {
 return _st(context)._localAt_put_(each,_st(aCollection)._at_ifAbsent_(index,(function(){
-return smalltalk.withContext(function($ctx3) {
 return nil;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})})));
+})));
 }, function($ctx2) {$ctx2.fillBlock({each:each,index:index},$ctx1,1)})}));
 $3=_st(context)._interpreter();
 $ctx1.sendIdx["interpreter"]=1;
@@ -828,9 +827,8 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=_st(self._sendIndexes())._at_ifAbsent_(aString,(function(){
-return smalltalk.withContext(function($ctx2) {
 return (0);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"sendIndexAt:",{aString:aString},globals.AIContext)})},
 args: ["aString"],
@@ -1437,9 +1435,8 @@ try {
 $1=self._stack();
 $ctx1.sendIdx["stack"]=1;
 _st($1)._ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[nil];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $2=_st(self._stack())._last();
 return $2;
 }
@@ -1822,28 +1819,20 @@ selector: "visitDynamicDictionaryNode:",
 protocol: 'visiting',
 fn: function (aNode){
 var self=this;
-var associations,hashedCollection;
+var keyValueList;
 function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
-associations=_st($OrderedCollection())._new();
-$ctx1.sendIdx["new"]=1;
-hashedCollection=_st($HashedCollection())._new();
+keyValueList=_st($OrderedCollection())._new();
 _st(_st(aNode)._nodes())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-return _st(associations)._add_(self._pop());
-$ctx2.sendIdx["add:"]=1;
+return _st(keyValueList)._add_(self._pop());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
-$ctx1.sendIdx["do:"]=1;
-_st(_st(associations)._reversed())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(hashedCollection)._add_(each);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
-self._push_(hashedCollection);
-return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode,associations:associations,hashedCollection:hashedCollection},globals.ASTInterpreter)})},
+self._push_(_st($HashedCollection())._newFromPairs_(_st(keyValueList)._reversed()));
+return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode,keyValueList:keyValueList},globals.ASTInterpreter)})},
 args: ["aNode"],
-source: "visitDynamicDictionaryNode: aNode\x0a\x09| associations hashedCollection |\x0a\x09\x0a\x09associations := OrderedCollection new.\x0a\x09hashedCollection := HashedCollection new.\x0a\x09\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09associations add: self pop ].\x0a\x09\x0a\x09associations reversed do: [ :each |\x0a\x09\x09hashedCollection add: each ].\x0a\x09\x0a\x09self push: hashedCollection",
-messageSends: ["new", "do:", "nodes", "add:", "pop", "reversed", "push:"],
+source: "visitDynamicDictionaryNode: aNode\x0a\x09| keyValueList |\x0a\x09\x0a\x09keyValueList := OrderedCollection new.\x0a\x09\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09keyValueList add: self pop ].\x0a\x09\x0a\x09self push: (HashedCollection newFromPairs: keyValueList reversed)",
+messageSends: ["new", "do:", "nodes", "add:", "pop", "push:", "newFromPairs:", "reversed"],
 referencedClasses: ["OrderedCollection", "HashedCollection"]
 }),
 globals.ASTInterpreter);
@@ -2201,14 +2190,14 @@ selector: "isSteppingNode",
 protocol: '*Compiler-Interpreter',
 fn: function (){
 var self=this;
-return false;
+return true;
 },
 args: [],
-source: "isSteppingNode\x0a\x09^ false",
+source: "isSteppingNode\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-globals.Node);
+globals.AssignmentNode);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -2223,7 +2212,7 @@ source: "isSteppingNode\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-globals.AssignmentNode);
+globals.BlockNode);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -2238,7 +2227,7 @@ source: "isSteppingNode\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-globals.BlockNode);
+globals.DynamicArrayNode);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -2253,7 +2242,7 @@ source: "isSteppingNode\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-globals.DynamicArrayNode);
+globals.DynamicDictionaryNode);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -2268,7 +2257,7 @@ source: "isSteppingNode\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-globals.DynamicDictionaryNode);
+globals.JSStatementNode);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -2276,14 +2265,14 @@ selector: "isSteppingNode",
 protocol: '*Compiler-Interpreter',
 fn: function (){
 var self=this;
-return true;
+return false;
 },
 args: [],
-source: "isSteppingNode\x0a\x09^ true",
+source: "isSteppingNode\x0a\x09^ false",
 messageSends: [],
 referencedClasses: []
 }),
-globals.JSStatementNode);
+globals.Node);
 
 smalltalk.addMethod(
 smalltalk.method({

+ 10 - 14
st/Compiler-Interpreter.st → js/Compiler-Interpreter.st

@@ -619,18 +619,14 @@ visitDynamicArrayNode: aNode
 !
 
 visitDynamicDictionaryNode: aNode
-	| associations hashedCollection |
+	| keyValueList |
 	
-	associations := OrderedCollection new.
-	hashedCollection := HashedCollection new.
+	keyValueList := OrderedCollection new.
 	
 	aNode nodes do: [ :each | 
-		associations add: self pop ].
+		keyValueList add: self pop ].
 	
-	associations reversed do: [ :each |
-		hashedCollection add: each ].
-	
-	self push: hashedCollection
+	self push: (HashedCollection newFromPairs: keyValueList reversed)
 !
 
 visitJSStatementNode: aNode
@@ -754,12 +750,6 @@ visitSendNode: aNode
 		self increaseIndex ]
 ! !
 
-!Node methodsFor: '*Compiler-Interpreter'!
-
-isSteppingNode
-	^ false
-! !
-
 !AssignmentNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode
@@ -790,6 +780,12 @@ isSteppingNode
 	^ true
 ! !
 
+!Node methodsFor: '*Compiler-Interpreter'!
+
+isSteppingNode
+	^ false
+! !
+
 !SendNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode

+ 3 - 6
js/Compiler-Semantic.js

@@ -128,9 +128,8 @@ $ctx2.sendIdx["value"]=2;
 return _st($4)._at_ifAbsent_($5,(function(){
 return smalltalk.withContext(function($ctx3) {
 return _st(self._temps())._at_ifAbsent_(_st(aStringOrNode)._value(),(function(){
-return smalltalk.withContext(function($ctx4) {
 return nil;
-}, function($ctx4) {$ctx4.fillBlock({},$ctx3,3)})}));
+}));
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
 $ctx2.sendIdx["at:ifAbsent:"]=2;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
@@ -559,9 +558,8 @@ var $2,$1;
 $2=globals.MethodLexicalScope.superclass.fn.prototype._bindingFor_.apply(_st(self), [aNode]);
 if(($receiver = $2) == nil || $receiver == null){
 $1=_st(self._iVars())._at_ifAbsent_(_st(aNode)._value(),(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 } else {
 $1=$2;
 };
@@ -786,8 +784,7 @@ fn: function (aScope){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 _st(self._nonLocalReturns())._remove_ifAbsent_(aScope,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeNonLocalReturn:",{aScope:aScope},globals.MethodLexicalScope)})},
 args: ["aScope"],
 source: "removeNonLocalReturn: aScope\x0a\x09self nonLocalReturns remove: aScope ifAbsent: []",

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


+ 30 - 22
js/Compiler-Tests.js

@@ -499,19 +499,36 @@ protocol: 'tests',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2="foo".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$1=globals.HashedCollection._from_([$2,"bar".__minus_gt((2))]);
-self._should_return_("foo\x0a\x09| x |\x0a\x09x := 'foo'->1.\x0a\x09^ #{ x. (true ifTrue: [ x := 'bar'->2 ]) }\x0a",$1);
+self._should_return_("foo\x0a\x09| x |\x0a\x09x := 'foo'.\x0a\x09^ #{ x->1. 'bar'->(true ifTrue: [ 2 ]) }\x0a",globals.HashedCollection._newFromPairs_(["foo",(1),"bar",(2)]));
 return self}, function($ctx1) {$ctx1.fill(self,"testDynamicDictionaryElementsOrdered",{},globals.CodeGeneratorTest)})},
 args: [],
-source: "testDynamicDictionaryElementsOrdered\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := ''foo''->1.\x0a\x09^ #{ x. (true ifTrue: [ x := ''bar''->2 ]) }\x0a' return: #{'foo'->1. 'bar'->2}.",
-messageSends: ["should:return:", "->"],
+source: "testDynamicDictionaryElementsOrdered\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := ''foo''.\x0a\x09^ #{ x->1. ''bar''->(true ifTrue: [ 2 ]) }\x0a' return: #{'foo'->1. 'bar'->2}.",
+messageSends: ["should:return:"],
 referencedClasses: []
 }),
 globals.CodeGeneratorTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDynamicDictionaryWithMoreArrows",
+protocol: 'tests',
+fn: function (){
+var self=this;
+function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=_st((1).__minus_gt((2))).__minus_gt((3));
+$ctx1.sendIdx["->"]=1;
+$1=_st($HashedCollection())._with_($2);
+self._should_return_("foo ^ #{1->2->3}",$1);
+return self}, function($ctx1) {$ctx1.fill(self,"testDynamicDictionaryWithMoreArrows",{},globals.CodeGeneratorTest)})},
+args: [],
+source: "testDynamicDictionaryWithMoreArrows\x0a\x09self should: 'foo ^ #{1->2->3}' return: (HashedCollection with: 1->2->3)",
+messageSends: ["should:return:", "with:", "->"],
+referencedClasses: ["HashedCollection"]
+}),
+globals.CodeGeneratorTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testGlobalVar",
@@ -541,7 +558,7 @@ fn: function (){
 var self=this;
 function $Array(){return globals.Array||(typeof Array=="undefined"?nil:Array)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1,$5,$6,$4,$8,$9,$7,$11,$12,$10,$14,$13;
+var $2,$3,$1,$5,$6,$4,$8,$9,$7,$11,$10;
 $2="foo".__minus_gt($Array());
 $ctx1.sendIdx["->"]=1;
 $3="bar".__minus_gt((2));
@@ -565,15 +582,10 @@ self._should_return_("foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ Array with: 'foo'
 $ctx1.sendIdx["should:return:"]=3;
 $11="foo".__minus_gt((1));
 $ctx1.sendIdx["->"]=7;
-$12="bar".__minus_gt((2));
-$ctx1.sendIdx["->"]=8;
-$10=[$11,$12];
+$10=[$11,"bar".__minus_gt((2))];
 self._should_return_("foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ { 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",$10);
 $ctx1.sendIdx["should:return:"]=4;
-$14="foo".__minus_gt((1));
-$ctx1.sendIdx["->"]=9;
-$13=globals.HashedCollection._from_([$14,"bar".__minus_gt((2))]);
-self._should_return_("foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ #{ 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",$13);
+self._should_return_("foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ #{ 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",globals.HashedCollection._newFromPairs_(["foo",(1),"bar",(2)]));
 return self}, function($ctx1) {$ctx1.fill(self,"testInnerTemporalDependentElementsOrdered",{},globals.CodeGeneratorTest)})},
 args: [],
 source: "testInnerTemporalDependentElementsOrdered\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := Array.\x0a\x09^ x with: ''foo''->x with: ''bar''->(x := 2)\x0a' return: {'foo'->Array. 'bar'->2}.\x0a\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := Array.\x0a\x09^ x with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])\x0a' return: {'foo'->Array. 'bar'->2}.\x0a\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ Array with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])\x0a' return: {'foo'->1. 'bar'->2}.\x0a\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ { ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }\x0a' return: {'foo'->1. 'bar'->2}.\x0a\x0a\x09self should: 'foo\x0a\x09| x |\x0a\x09x := 1.\x0a\x09^ #{ ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }\x0a' return: #{'foo'->1. 'bar'->2}.",
@@ -605,7 +617,6 @@ protocol: 'tests',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
 self._should_return_("foo ^ 1",(1));
 $ctx1.sendIdx["should:return:"]=1;
 self._should_return_("foo ^ 'hello'","hello");
@@ -618,10 +629,7 @@ self._should_return_("foo ^ true",true);
 $ctx1.sendIdx["should:return:"]=5;
 self._should_return_("foo ^ false",false);
 $ctx1.sendIdx["should:return:"]=6;
-$2=(1).__minus_gt((2));
-$ctx1.sendIdx["->"]=1;
-$1=globals.HashedCollection._from_([$2,(3).__minus_gt((4))]);
-self._should_return_("foo ^ #{1->2. 3->4}",$1);
+self._should_return_("foo ^ #{1->2. 3->4}",globals.HashedCollection._newFromPairs_([(1),(2),(3),(4)]));
 $ctx1.sendIdx["should:return:"]=7;
 self._should_return_("foo ^ #hello","hello");
 $ctx1.sendIdx["should:return:"]=8;
@@ -631,7 +639,7 @@ self._should_return_("foo ^ -2.5e4",(-25000));
 return self}, function($ctx1) {$ctx1.fill(self,"testLiterals",{},globals.CodeGeneratorTest)})},
 args: [],
 source: "testLiterals\x0a\x09self should: 'foo ^ 1' return: 1.\x0a\x09self should: 'foo ^ ''hello''' return: 'hello'.\x0a\x09self should: 'foo ^ #(1 2 3 4)' return: #(1 2 3 4).\x0a\x09self should: 'foo ^ {1. [:x | x ] value: 2. 3. [4] value}' return: #(1 2 3 4).\x0a\x09self should: 'foo ^ true' return: true.\x0a\x09self should: 'foo ^ false' return: false.\x0a\x09self should: 'foo ^ #{1->2. 3->4}' return: #{1->2. 3->4}.\x0a\x09self should: 'foo ^ #hello' return: #hello.\x0a\x09self should: 'foo ^ -123.456' return: -123.456.\x0a\x09self should: 'foo ^ -2.5e4' return: -25000.",
-messageSends: ["should:return:", "->"],
+messageSends: ["should:return:"],
 referencedClasses: []
 }),
 globals.CodeGeneratorTest);
@@ -1176,7 +1184,7 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 self["@receiver"]=anObject;
-$1=self._assert_equals_(self._interpret_receiver_withArguments_(aString,self["@receiver"],globals.HashedCollection._from_([])),aResult);
+$1=self._assert_equals_(self._interpret_receiver_withArguments_(aString,self["@receiver"],globals.HashedCollection._newFromPairs_([])),aResult);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"should:receiver:return:",{aString:aString,anObject:anObject,aResult:aResult},globals.InterpreterTest)})},
 args: ["aString", "anObject", "aResult"],

+ 6 - 2
st/Compiler-Tests.st → js/Compiler-Tests.st

@@ -198,11 +198,15 @@ testDynamicArrayElementsOrdered
 testDynamicDictionaryElementsOrdered
 	self should: 'foo
 	| x |
-	x := ''foo''->1.
-	^ #{ x. (true ifTrue: [ x := ''bar''->2 ]) }
+	x := ''foo''.
+	^ #{ x->1. ''bar''->(true ifTrue: [ 2 ]) }
 ' return: #{'foo'->1. 'bar'->2}.
 !
 
+testDynamicDictionaryWithMoreArrows
+	self should: 'foo ^ #{1->2->3}' return: (HashedCollection with: 1->2->3)
+!
+
 testGlobalVar
 	self should: 'foo ^ eval class' return: BlockClosure.
 	self should: 'foo ^ Math cos: 0' return: 1.

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


+ 38 - 0
js/Helios-Announcements.js

@@ -3,6 +3,7 @@ smalltalk.addPackage('Helios-Announcements');
 smalltalk.packages["Helios-Announcements"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 smalltalk.addClass('HLAboutToChange', globals.Object, ['actionBlock'], 'Helios-Announcements');
+globals.HLAboutToChange.comment="I am announced whenever a change of context is about to be made, and unsaved changes could be lost.\x0a\x0aI am used within `HLModel` to handle such user actions. See `HLModel >> withChangesDo:`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "actionBlock",
@@ -130,6 +131,7 @@ globals.HLPrintItRequested.comment="I am emitted by a `HLCodeWidget` before an o
 
 
 smalltalk.addClass('HLDebuggerAnnouncement', globals.HLAnnouncement, ['context'], 'Helios-Announcements');
+globals.HLDebuggerAnnouncement.comment="I am the root class of debugger announcements, and hold onto the debugged `context`.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "context",
@@ -165,6 +167,7 @@ globals.HLDebuggerAnnouncement);
 
 
 smalltalk.addClass('HLDebuggerContextSelected', globals.HLDebuggerAnnouncement, [], 'Helios-Announcements');
+globals.HLDebuggerContextSelected.comment="I am announced when a new context is selected in a debugger, to update the user interface.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "context",
@@ -551,6 +554,41 @@ smalltalk.addClass('HLShowCommentToggled', globals.HLAnnouncement, [], 'Helios-A
 smalltalk.addClass('HLShowInstanceToggled', globals.HLAnnouncement, [], 'Helios-Announcements');
 
 
+smalltalk.addClass('HLShowTemplate', globals.HLAnnouncement, ['template'], 'Helios-Announcements');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "template",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@template"];
+return $1;
+},
+args: [],
+source: "template\x0a\x09^ template",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLShowTemplate);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "template:",
+protocol: 'accessing',
+fn: function (aString){
+var self=this;
+self["@template"]=aString;
+return self},
+args: ["aString"],
+source: "template: aString\x0a\x09template := aString",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLShowTemplate);
+
+
+
 smalltalk.addClass('HLSourceCodeSaved', globals.HLAnnouncement, [], 'Helios-Announcements');
 
 });

+ 22 - 0
st/Helios-Announcements.st → js/Helios-Announcements.st

@@ -2,6 +2,10 @@ Smalltalk createPackage: 'Helios-Announcements'!
 Object subclass: #HLAboutToChange
 	instanceVariableNames: 'actionBlock'
 	package: 'Helios-Announcements'!
+!HLAboutToChange commentStamp!
+I am announced whenever a change of context is about to be made, and unsaved changes could be lost.
+
+I am used within `HLModel` to handle such user actions. See `HLModel >> withChangesDo:`.!
 
 !HLAboutToChange methodsFor: 'accessing'!
 
@@ -79,6 +83,8 @@ I am emitted by a `HLCodeWidget` before an object is printed.!
 HLAnnouncement subclass: #HLDebuggerAnnouncement
 	instanceVariableNames: 'context'
 	package: 'Helios-Announcements'!
+!HLDebuggerAnnouncement commentStamp!
+I am the root class of debugger announcements, and hold onto the debugged `context`.!
 
 !HLDebuggerAnnouncement methodsFor: 'accessing'!
 
@@ -93,6 +99,8 @@ context: aContext
 HLDebuggerAnnouncement subclass: #HLDebuggerContextSelected
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!
+!HLDebuggerContextSelected commentStamp!
+I am announced when a new context is selected in a debugger, to update the user interface.!
 
 !HLDebuggerContextSelected methodsFor: 'accessing'!
 
@@ -286,6 +294,20 @@ HLAnnouncement subclass: #HLShowInstanceToggled
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!
 
+HLAnnouncement subclass: #HLShowTemplate
+	instanceVariableNames: 'template'
+	package: 'Helios-Announcements'!
+
+!HLShowTemplate methodsFor: 'accessing'!
+
+template
+	^ template
+!
+
+template: aString
+	template := aString
+! !
+
 HLAnnouncement subclass: #HLSourceCodeSaved
 	instanceVariableNames: ''
 	package: 'Helios-Announcements'!

+ 120 - 26
js/Helios-Browser.js

@@ -806,6 +806,34 @@ referencedClasses: []
 }),
 globals.HLBrowserModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "showClassTemplate",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLShowTemplate(){return globals.HLShowTemplate||(typeof HLShowTemplate=="undefined"?nil:HLShowTemplate)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3;
+$1=self._selectedPackage();
+if(($receiver = $1) == nil || $receiver == null){
+$1;
+} else {
+var package_;
+package_=$receiver;
+$2=_st($HLShowTemplate())._new();
+_st($2)._template_(_st(package_)._classTemplate());
+$3=_st($2)._yourself();
+_st(self._announcer())._announce_($3);
+};
+return self}, function($ctx1) {$ctx1.fill(self,"showClassTemplate",{},globals.HLBrowserModel)})},
+args: [],
+source: "showClassTemplate\x0a\x09self selectedPackage ifNotNil: [ :package |\x0a\x09\x09self announcer announce: (HLShowTemplate new\x0a\x09\x09\x09template: package classTemplate;\x0a\x09\x09\x09yourself) ]",
+messageSends: ["ifNotNil:", "selectedPackage", "announce:", "announcer", "template:", "new", "classTemplate", "yourself"],
+referencedClasses: ["HLShowTemplate"]
+}),
+globals.HLBrowserModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "showComment",
@@ -816,14 +844,14 @@ return smalltalk.withContext(function($ctx1) {
 var $2,$1;
 $2=self["@showComment"];
 if(($receiver = $2) == nil || $receiver == null){
-$1=false;
+$1=true;
 } else {
 $1=$2;
 };
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"showComment",{},globals.HLBrowserModel)})},
 args: [],
-source: "showComment\x0a\x09^ showComment ifNil: [ false ]",
+source: "showComment\x0a\x09^ showComment ifNil: [ true ]",
 messageSends: ["ifNil:"],
 referencedClasses: []
 }),
@@ -911,6 +939,34 @@ referencedClasses: ["HLShowInstanceToggled"]
 }),
 globals.HLBrowserModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "showMethodTemplate",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLShowTemplate(){return globals.HLShowTemplate||(typeof HLShowTemplate=="undefined"?nil:HLShowTemplate)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3;
+$1=self._selectedClass();
+if(($receiver = $1) == nil || $receiver == null){
+$1;
+} else {
+var theClass;
+theClass=$receiver;
+$2=_st($HLShowTemplate())._new();
+_st($2)._template_(_st(theClass)._methodTemplate());
+$3=_st($2)._yourself();
+_st(self._announcer())._announce_($3);
+};
+return self}, function($ctx1) {$ctx1.fill(self,"showMethodTemplate",{},globals.HLBrowserModel)})},
+args: [],
+source: "showMethodTemplate\x0a\x09self selectedClass ifNotNil: [ :theClass |\x0a\x09\x09self announcer announce: (HLShowTemplate new\x0a\x09\x09\x09template: theClass methodTemplate;\x0a\x09\x09\x09yourself) ]",
+messageSends: ["ifNotNil:", "selectedClass", "announce:", "announcer", "template:", "new", "methodTemplate", "yourself"],
+referencedClasses: ["HLShowTemplate"]
+}),
+globals.HLBrowserModel);
+
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -1105,12 +1161,10 @@ fn: function (aSelector){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 _st(self._overriddenCache())._removeKey_ifAbsent_(aSelector,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["removeKey:ifAbsent:"]=1;
 _st(self._overrideCache())._removeKey_ifAbsent_(aSelector,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeSelector:",{aSelector:aSelector},globals.HLClassCache)})},
 args: ["aSelector"],
 source: "removeSelector: aSelector\x0a\x09self overriddenCache \x0a    \x09removeKey: aSelector\x0a        ifAbsent: [ ].\x0a    self overrideCache \x0a    \x09removeKey: aSelector\x0a        ifAbsent: [ ]",
@@ -1216,20 +1270,36 @@ protocol: 'accessing',
 fn: function (aClass){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1,$4;
-$3=_st(aClass)._theNonMetaClass();
-$ctx1.sendIdx["theNonMetaClass"]=1;
-$2=_st($3)._comment();
-$1=_st($2)._isEmpty();
-if(smalltalk.assert($1)){
-return "uncommented";
-};
-$4=_st(_st(aClass)._theNonMetaClass())._heliosClass();
-return $4;
+var $1;
+$1=_st(_st(aClass)._theNonMetaClass())._heliosClass();
+return $1;
 }, function($ctx1) {$ctx1.fill(self,"cssClassForItem:",{aClass:aClass},globals.HLClassesListWidget)})},
 args: ["aClass"],
-source: "cssClassForItem: aClass\x0a\x09aClass theNonMetaClass comment isEmpty \x0a\x09\x09ifTrue: [ ^ 'uncommented' ].\x0a\x09^ aClass theNonMetaClass heliosClass",
-messageSends: ["ifTrue:", "isEmpty", "comment", "theNonMetaClass", "heliosClass"],
+source: "cssClassForItem: aClass\x0a\x09^ aClass theNonMetaClass heliosClass",
+messageSends: ["heliosClass", "theNonMetaClass"],
+referencedClasses: []
+}),
+globals.HLClassesListWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "focus",
+protocol: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+globals.HLClassesListWidget.superclass.fn.prototype._focus.apply(_st(self), []);
+$1=self._selectedItem();
+if(($receiver = $1) == nil || $receiver == null){
+_st(self._model())._showClassTemplate();
+} else {
+$1;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"focus",{},globals.HLClassesListWidget)})},
+args: [],
+source: "focus\x0a\x09super focus.\x0a\x09\x0a\x09self selectedItem \x0a\x09\x09ifNil: [ self model showClassTemplate ]",
+messageSends: ["focus", "ifNil:", "selectedItem", "showClassTemplate", "model"],
 referencedClasses: []
 }),
 globals.HLClassesListWidget);
@@ -1533,12 +1603,13 @@ $1=_st(_st(class_)._package()).__eq(_st(self._model())._selectedPackage());
 if(! smalltalk.assert($1)){
 return self;
 };
+self._selectItem_(nil);
 self._setItemsForSelectedPackage();
 self._refresh();
 return self}, function($ctx1) {$ctx1.fill(self,"onClassRemoved:",{anAnnouncement:anAnnouncement,class_:class_},globals.HLClassesListWidget)})},
 args: ["anAnnouncement"],
-source: "onClassRemoved: anAnnouncement\x0a\x09| class |\x0a\x09class := anAnnouncement theClass.\x0a\x0a\x09class package = self model selectedPackage ifFalse: [ ^ self ].\x0a    \x0a    self setItemsForSelectedPackage.\x0a    self refresh",
-messageSends: ["theClass", "ifFalse:", "=", "package", "selectedPackage", "model", "setItemsForSelectedPackage", "refresh"],
+source: "onClassRemoved: anAnnouncement\x0a\x09| class |\x0a\x09class := anAnnouncement theClass.\x0a\x0a\x09class package = self model selectedPackage ifFalse: [ ^ self ].\x0a    \x0a\x09self selectItem: nil.\x0a    self setItemsForSelectedPackage.\x0a    self refresh",
+messageSends: ["theClass", "ifFalse:", "=", "package", "selectedPackage", "model", "selectItem:", "setItemsForSelectedPackage", "refresh"],
 referencedClasses: []
 }),
 globals.HLClassesListWidget);
@@ -2048,10 +2119,10 @@ selector: "defaultDocumentation",
 protocol: 'defaults',
 fn: function (){
 var self=this;
-return "No documentation available. \x0a**That's bad. Seriously.**";
+return "No documentation is available for this class.";
 },
 args: [],
-source: "defaultDocumentation\x0a\x09^ 'No documentation available. \x0a**That''s bad. Seriously.**'",
+source: "defaultDocumentation\x0a\x09^ 'No documentation is available for this class.'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -2546,6 +2617,29 @@ referencedClasses: []
 }),
 globals.HLMethodsListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "focus",
+protocol: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+globals.HLMethodsListWidget.superclass.fn.prototype._focus.apply(_st(self), []);
+$1=self._selectedItem();
+if(($receiver = $1) == nil || $receiver == null){
+_st(self._model())._showMethodTemplate();
+} else {
+$1;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"focus",{},globals.HLMethodsListWidget)})},
+args: [],
+source: "focus\x0a\x09super focus.\x0a\x09\x0a\x09self selectedItem ifNil: [\x0a\x09\x09self model showMethodTemplate ]",
+messageSends: ["focus", "ifNil:", "selectedItem", "showMethodTemplate", "model"],
+referencedClasses: []
+}),
+globals.HLMethodsListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isOverridden:",
@@ -2787,9 +2881,8 @@ $ctx2.sendIdx["selector"]=1;
 return _st(each).__eq($1);
 $ctx2.sendIdx["="]=1;
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[self];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $2=self._selectedItem();
 $ctx1.sendIdx["selectedItem"]=1;
 if(($receiver = $2) == nil || $receiver == null){
@@ -3429,11 +3522,12 @@ protocol: 'actions',
 fn: function (aPackage){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
+globals.HLPackagesListWidget.superclass.fn.prototype._selectItem_.apply(_st(self), [aPackage]);
 _st(self._model())._selectedPackage_(aPackage);
 return self}, function($ctx1) {$ctx1.fill(self,"selectItem:",{aPackage:aPackage},globals.HLPackagesListWidget)})},
 args: ["aPackage"],
-source: "selectItem: aPackage\x0a\x09self model selectedPackage: aPackage",
-messageSends: ["selectedPackage:", "model"],
+source: "selectItem: aPackage\x0a\x09super selectItem: aPackage.\x0a\x09self model selectedPackage: aPackage",
+messageSends: ["selectItem:", "selectedPackage:", "model"],
 referencedClasses: []
 }),
 globals.HLPackagesListWidget);

+ 32 - 5
st/Helios-Browser.st → js/Helios-Browser.st

@@ -231,7 +231,7 @@ HLToolModel subclass: #HLBrowserModel
 !HLBrowserModel methodsFor: 'accessing'!
 
 showComment
-	^ showComment ifNil: [ false ]
+	^ showComment ifNil: [ true ]
 !
 
 showComment: aBoolean
@@ -283,6 +283,20 @@ setClassComment: aString
 	self environment
 		setClassCommentOf: self selectedClass theNonMetaClass
 		to: aString
+!
+
+showClassTemplate
+	self selectedPackage ifNotNil: [ :package |
+		self announcer announce: (HLShowTemplate new
+			template: package classTemplate;
+			yourself) ]
+!
+
+showMethodTemplate
+	self selectedClass ifNotNil: [ :theClass |
+		self announcer announce: (HLShowTemplate new
+			template: theClass methodTemplate;
+			yourself) ]
 ! !
 
 !HLBrowserModel methodsFor: 'commands actions'!
@@ -402,8 +416,6 @@ I render a list of classes in the selected package.!
 !HLClassesListWidget methodsFor: 'accessing'!
 
 cssClassForItem: aClass
-	aClass theNonMetaClass comment isEmpty 
-		ifTrue: [ ^ 'uncommented' ].
 	^ aClass theNonMetaClass heliosClass
 !
 
@@ -422,6 +434,13 @@ label
 
 !HLClassesListWidget methodsFor: 'actions'!
 
+focus
+	super focus.
+	
+	self selectedItem 
+		ifNil: [ self model showClassTemplate ]
+!
+
 focusMethodsListWidget
 	self model announcer announce: HLMethodsListFocus new
 !
@@ -573,6 +592,7 @@ onClassRemoved: anAnnouncement
 
 	class package = self model selectedPackage ifFalse: [ ^ self ].
     
+	self selectItem: nil.
     self setItemsForSelectedPackage.
     self refresh
 !
@@ -777,8 +797,7 @@ unregister
 !HLDocumentationWidget methodsFor: 'defaults'!
 
 defaultDocumentation
-	^ 'No documentation available. 
-**That''s bad. Seriously.**'
+	^ 'No documentation is available for this class.'
 !
 
 defaultHead
@@ -925,6 +944,13 @@ selectorsInProtocol: aString
 
 !HLMethodsListWidget methodsFor: 'actions'!
 
+focus
+	super focus.
+	
+	self selectedItem ifNil: [
+		self model showMethodTemplate ]
+!
+
 observeModel
 	self model announcer 
 		on: HLProtocolSelected 
@@ -1153,6 +1179,7 @@ observeSystem
 !
 
 selectItem: aPackage
+	super selectItem: aPackage.
 	self model selectedPackage: aPackage
 ! !
 

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


+ 2 - 2
js/Helios-Commands-Core.js

@@ -920,10 +920,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Switch";
+return "Switch tab";
 },
 args: [],
-source: "label\x0a\x09^ 'Switch'",
+source: "label\x0a\x09^ 'Switch tab'",
 messageSends: [],
 referencedClasses: []
 }),

+ 1 - 1
st/Helios-Commands-Core.st → js/Helios-Commands-Core.st

@@ -310,7 +310,7 @@ key
 !
 
 label
-	^ 'Switch'
+	^ 'Switch tab'
 ! !
 
 HLCommand subclass: #HLViewCommand

+ 28 - 28
js/Helios-Commands-Tools.js

@@ -210,10 +210,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Commit";
+return "Commit package";
 },
 args: [],
-source: "label\x0a\x09^ 'Commit'",
+source: "label\x0a\x09^ 'Commit package'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -373,10 +373,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Class";
+return "Copy class";
 },
 args: [],
-source: "label\x0a\x09^ 'Class'",
+source: "label\x0a\x09^ 'Copy class'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -548,10 +548,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Class";
+return "Find class";
 },
 args: [],
-source: "label\x0a\x09^ 'Class'",
+source: "label\x0a\x09^ 'Find class'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -701,10 +701,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "References";
+return "Find references";
 },
 args: [],
-source: "label\x0a\x09^ 'References'",
+source: "label\x0a\x09^ 'Find references'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -785,10 +785,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Class";
+return "Move class";
 },
 args: [],
-source: "label\x0a\x09^ 'Class'",
+source: "label\x0a\x09^ 'Move class'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -912,10 +912,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "to package";
+return "Move class to package";
 },
 args: [],
-source: "label\x0a\x09^ 'to package'",
+source: "label\x0a\x09^ 'Move class to package'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -993,10 +993,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Method";
+return "Move method";
 },
 args: [],
-source: "label\x0a\x09^ 'Method'",
+source: "label\x0a\x09^ 'Move method'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1105,10 +1105,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "to class";
+return "Move method to class";
 },
 args: [],
-source: "label\x09\x0a\x09^ 'to class'",
+source: "label\x09\x0a\x09^ 'Move method to class'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1232,10 +1232,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "to protocol";
+return "Move method to protocol";
 },
 args: [],
-source: "label\x0a\x09^ 'to protocol'",
+source: "label\x0a\x09^ 'Move method to protocol'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1362,10 +1362,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Class";
+return "Remove class";
 },
 args: [],
-source: "label\x0a\x09^ 'Class'",
+source: "label\x0a\x09^ 'Remove class'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1459,10 +1459,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Method";
+return "Remove method";
 },
 args: [],
-source: "label\x0a\x09^ 'Method'",
+source: "label\x0a\x09^ 'Remove method'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1556,10 +1556,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Protocol";
+return "Remove protocol";
 },
 args: [],
-source: "label\x0a\x09^ 'Protocol'",
+source: "label\x0a\x09^ 'Remove protocol'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1734,10 +1734,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Class";
+return "Rename class";
 },
 args: [],
-source: "label\x0a\x09^ 'Class'",
+source: "label\x0a\x09^ 'Rename class'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1879,10 +1879,10 @@ selector: "label",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return "Protocol";
+return "Rename protocol";
 },
 args: [],
-source: "label\x0a\x09^ 'Protocol'",
+source: "label\x0a\x09^ 'Rename protocol'",
 messageSends: [],
 referencedClasses: []
 }),

+ 14 - 14
st/Helios-Commands-Tools.st → js/Helios-Commands-Tools.st

@@ -85,7 +85,7 @@ key
 !
 
 label
-	^ 'Commit'
+	^ 'Commit package'
 ! !
 
 HLToolCommand subclass: #HLCopyCommand
@@ -145,7 +145,7 @@ key
 !
 
 label
-	^ 'Class'
+	^ 'Copy class'
 !
 
 menuLabel
@@ -203,7 +203,7 @@ key
 !
 
 label
-	^ 'Class'
+	^ 'Find class'
 ! !
 
 !HLFindClassCommand class methodsFor: 'testing'!
@@ -262,7 +262,7 @@ key
 !
 
 label
-	^ 'References'
+	^ 'Find references'
 ! !
 
 HLToolCommand subclass: #HLMoveToCommand
@@ -296,7 +296,7 @@ key
 !
 
 label
-	^ 'Class'
+	^ 'Move class'
 ! !
 
 HLMoveClassToCommand subclass: #HLMoveClassToPackageCommand
@@ -340,7 +340,7 @@ key
 !
 
 label
-	^ 'to package'
+	^ 'Move class to package'
 !
 
 menuLabel	
@@ -370,7 +370,7 @@ key
 !
 
 label
-	^ 'Method'
+	^ 'Move method'
 ! !
 
 HLMoveMethodToCommand subclass: #HLMoveMethodToClassCommand
@@ -410,7 +410,7 @@ key
 !
 
 label	
-	^ 'to class'
+	^ 'Move method to class'
 !
 
 menuLabel	
@@ -454,7 +454,7 @@ key
 !
 
 label
-	^ 'to protocol'
+	^ 'Move method to protocol'
 !
 
 menuLabel
@@ -504,7 +504,7 @@ key
 !
 
 label
-	^ 'Class'
+	^ 'Remove class'
 !
 
 menuLabel
@@ -540,7 +540,7 @@ key
 !
 
 label
-	^ 'Method'
+	^ 'Remove method'
 !
 
 menuLabel
@@ -576,7 +576,7 @@ key
 !
 
 label
-	^ 'Protocol'
+	^ 'Remove protocol'
 !
 
 menuLabel
@@ -640,7 +640,7 @@ key
 !
 
 label
-	^ 'Class'
+	^ 'Rename class'
 !
 
 menuLabel
@@ -690,7 +690,7 @@ key
 !
 
 label
-	^ 'Protocol'
+	^ 'Rename protocol'
 !
 
 menuLabel

+ 37 - 21
js/Helios-Core.js

@@ -163,8 +163,7 @@ return smalltalk.withContext(function($ctx2) {
 _st(self._announcer())._announce_(_st(_st($HLAboutToChange())._new())._actionBlock_(aBlock));
 return _st(aBlock)._value();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($HLChangeForbidden(),(function(ex){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"withChangesDo:",{aBlock:aBlock},globals.HLModel)})},
 args: ["aBlock"],
 source: "withChangesDo: aBlock\x0a\x09[ \x0a\x09\x09self announcer announce: (HLAboutToChange new\x0a\x09\x09\x09actionBlock: aBlock).\x0a\x09\x09aBlock value.\x0a\x09]\x0a\x09\x09on: HLChangeForbidden \x0a\x09\x09do: [ :ex | ]",
@@ -315,11 +314,11 @@ protocol: 'commands actions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._environment())._commitPackage_(self._selectedPackage());
+_st(self._environment())._commitPackage_(self._packageToCommit());
 return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLToolModel)})},
 args: [],
-source: "commitPackage\x0a\x09self environment commitPackage: self selectedPackage",
-messageSends: ["commitPackage:", "environment", "selectedPackage"],
+source: "commitPackage\x0a\x09self environment commitPackage: self packageToCommit",
+messageSends: ["commitPackage:", "environment", "packageToCommit"],
 referencedClasses: []
 }),
 globals.HLToolModel);
@@ -618,6 +617,31 @@ referencedClasses: []
 }),
 globals.HLToolModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "packageToCommit",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self._selectedMethod();
+if(($receiver = $2) == nil || $receiver == null){
+$1=self._selectedPackage();
+} else {
+var method;
+method=$receiver;
+$1=_st(method)._package();
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"packageToCommit",{},globals.HLToolModel)})},
+args: [],
+source: "packageToCommit\x0a\x09\x22Answer the package to commit depending on the context:\x0a\x09- if a Method is selected, answer its package\x0a\x09- else answer the `selectedPackage`\x22\x0a\x09\x0a\x09^ self selectedMethod \x0a\x09\x09ifNil: [ self selectedPackage ]\x0a\x09\x09ifNotNil: [ :method | method package ]",
+messageSends: ["ifNil:ifNotNil:", "selectedMethod", "selectedPackage", "package"],
+referencedClasses: []
+}),
+globals.HLToolModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "packages",
@@ -892,9 +916,8 @@ if(($receiver = $2) == nil || $receiver == null){
 $1=$2;
 } else {
 $1=_st(_st(self._selectedClass())._methodDictionary())._at_ifAbsent_(self["@selectedSelector"],(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 };
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"selectedMethod",{},globals.HLToolModel)})},
@@ -3209,8 +3232,7 @@ var $2,$1;
 $2=self["@callback"];
 if(($receiver = $2) == nil || $receiver == null){
 $1=(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})});
+});
 } else {
 $1=$2;
 };
@@ -4308,8 +4330,7 @@ var $2,$1;
 $2=self["@actionBlock"];
 if(($receiver = $2) == nil || $receiver == null){
 $1=(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})});
+});
 } else {
 $1=$2;
 };
@@ -4365,8 +4386,7 @@ var $2,$1;
 $2=self["@cancelBlock"];
 if(($receiver = $2) == nil || $receiver == null){
 $1=(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})});
+});
 } else {
 $1=$2;
 };
@@ -4738,8 +4758,7 @@ var $1;
 $1=self._progressBars();
 $ctx1.sendIdx["progressBars"]=1;
 _st($1)._remove_ifAbsent_(aProgressBar,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 _st(_st(_st(aProgressBar)._wrapper())._asJQuery())._remove();
 $ctx1.sendIdx["remove"]=1;
 _st(self._progressBars())._ifEmpty_((function(){
@@ -4852,8 +4871,7 @@ var $2,$1;
 $2=self["@cancelCallback"];
 if(($receiver = $2) == nil || $receiver == null){
 $1=(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})});
+});
 } else {
 $1=$2;
 };
@@ -4909,8 +4927,7 @@ var $2,$1;
 $2=self["@confirmCallback"];
 if(($receiver = $2) == nil || $receiver == null){
 $1=(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})});
+});
 } else {
 $1=$2;
 };
@@ -5039,8 +5056,7 @@ var $2,$1;
 $2=self["@selectCallback"];
 if(($receiver = $2) == nil || $receiver == null){
 $1=(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})});
+});
 } else {
 $1=$2;
 };

+ 11 - 1
st/Helios-Core.st → js/Helios-Core.st

@@ -92,6 +92,16 @@ availableProtocols
 	^ self environment availableProtocolsFor: self selectedClass
 !
 
+packageToCommit
+	"Answer the package to commit depending on the context:
+	- if a Method is selected, answer its package
+	- else answer the `selectedPackage`"
+	
+	^ self selectedMethod 
+		ifNil: [ self selectedPackage ]
+		ifNotNil: [ :method | method package ]
+!
+
 packages
 	^ self environment packages
 !
@@ -191,7 +201,7 @@ saveSourceCode
 !HLToolModel methodsFor: 'commands actions'!
 
 commitPackage
-	self environment commitPackage: self selectedPackage
+	self environment commitPackage: self packageToCommit
 !
 
 copyClassTo: aClassName

+ 13 - 19
js/Helios-Debugger.js

@@ -558,7 +558,7 @@ fn: function (aNode){
 var self=this;
 var token;
 return smalltalk.withContext(function($ctx1) { 
-var $4,$3,$2,$1,$5,$10,$9,$8,$7,$13,$12,$11,$6,$18,$17,$16,$15,$14;
+var $4,$3,$2,$1,$5,$9,$8,$7,$11,$10,$6,$15,$14,$13,$12;
 if(($receiver = aNode) == nil || $receiver == null){
 aNode;
 } else {
@@ -572,34 +572,28 @@ $ctx1.sendIdx["-"]=1;
 $1=self._addStopAt_($2);
 $1;
 $5=self._editor();
-$10=_st(aNode)._positionStart();
+$9=_st(aNode)._positionStart();
 $ctx1.sendIdx["positionStart"]=2;
-$9=_st($10)._x();
+$8=_st($9)._x();
 $ctx1.sendIdx["x"]=2;
-$8=_st($9).__minus((1));
+$7=_st($8).__minus((1));
 $ctx1.sendIdx["-"]=2;
-$7="line".__minus_gt($8);
-$ctx1.sendIdx["->"]=1;
-$13=_st(_st(aNode)._positionStart())._y();
+$11=_st(_st(aNode)._positionStart())._y();
 $ctx1.sendIdx["y"]=1;
-$12=_st($13).__minus((1));
+$10=_st($11).__minus((1));
 $ctx1.sendIdx["-"]=3;
-$11="ch".__minus_gt($12);
-$ctx1.sendIdx["->"]=2;
-$6=globals.HashedCollection._from_([$7,$11]);
-$18=_st(aNode)._positionEnd();
+$6=globals.HashedCollection._newFromPairs_(["line",$7,"ch",$10]);
+$15=_st(aNode)._positionEnd();
 $ctx1.sendIdx["positionEnd"]=1;
-$17=_st($18)._x();
-$16=_st($17).__minus((1));
-$15="line".__minus_gt($16);
-$ctx1.sendIdx["->"]=3;
-$14=globals.HashedCollection._from_([$15,"ch".__minus_gt(_st(_st(aNode)._positionEnd())._y())]);
-_st($5)._setSelection_to_($6,$14);
+$14=_st($15)._x();
+$13=_st($14).__minus((1));
+$12=globals.HashedCollection._newFromPairs_(["line",$13,"ch",_st(_st(aNode)._positionEnd())._y()]);
+_st($5)._setSelection_to_($6,$12);
 };
 return self}, function($ctx1) {$ctx1.fill(self,"highlightNode:",{aNode:aNode,token:token},globals.HLDebuggerCodeWidget)})},
 args: ["aNode"],
 source: "highlightNode: aNode\x0a\x09| token |\x0a\x09\x0a\x09aNode ifNotNil: [\x0a\x09\x09self\x0a\x09\x09\x09clearHighlight;\x0a\x09\x09\x09addStopAt: aNode positionStart x - 1.\x0a\x0a\x09\x09self editor \x0a\x09\x09\x09setSelection: #{ 'line' -> (aNode positionStart x - 1). 'ch' -> (aNode positionStart y - 1) }\x0a\x09\x09\x09to: #{ 'line' -> (aNode positionEnd x - 1). 'ch' -> (aNode positionEnd y) } ]",
-messageSends: ["ifNotNil:", "clearHighlight", "addStopAt:", "-", "x", "positionStart", "setSelection:to:", "editor", "->", "y", "positionEnd"],
+messageSends: ["ifNotNil:", "clearHighlight", "addStopAt:", "-", "x", "positionStart", "setSelection:to:", "editor", "y", "positionEnd"],
 referencedClasses: []
 }),
 globals.HLDebuggerCodeWidget);

+ 0 - 0
st/Helios-Debugger.st → js/Helios-Debugger.st


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


+ 3 - 6
js/Helios-Helpers.js

@@ -316,9 +316,8 @@ protocolBag=_st($Dictionary())._new();
 $ctx1.sendIdx["new"]=1;
 methods=_st(_st($HLReferencesModel())._new())._implementorsOf_(_st(self["@method"])._selector());
 _st(methods)._ifEmpty_ifNotEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[false];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
+}),(function(){
 return smalltalk.withContext(function($ctx2) {
 return _st(methods)._do_((function(aMethod){
 var protocol;
@@ -338,17 +337,15 @@ return _st(protocol).__eq(_st(self["@method"])._defaultProtocol());
 }, function($ctx4) {$ctx4.fillBlock({},$ctx3,5)})}));
 if(! smalltalk.assert($3)){
 return _st(protocolBag)._at_put_(protocol,_st(_st(protocolBag)._at_ifAbsent_(protocol,(function(){
-return smalltalk.withContext(function($ctx4) {
 return (0);
-}, function($ctx4) {$ctx4.fillBlock({},$ctx3,7)})}))).__plus((1)));
+}))).__plus((1)));
 };
 };
 }, function($ctx3) {$ctx3.fillBlock({aMethod:aMethod,protocol:protocol},$ctx2,3)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 _st(protocolBag)._ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[false];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,8)})}));
+}));
 protocolToUse=nil;
 counter=(0);
 _st(protocolBag)._keysAndValuesDo_((function(key,value){

+ 0 - 0
st/Helios-Helpers.st → js/Helios-Helpers.st


+ 5 - 37
js/Helios-Inspector.js

@@ -274,38 +274,6 @@ referencedClasses: []
 }),
 globals.HLInspectorModel);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "onKeyDown:",
-protocol: 'reactions',
-fn: function (anEvent){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-if(anEvent.ctrlKey) {
-		if(anEvent.keyCode === 80) { //ctrl+p
-			self._printIt();
-			anEvent.preventDefault();
-			return false;
-		}
-		if(anEvent.keyCode === 68) { //ctrl+d
-			self._doIt();
-			anEvent.preventDefault();
-			return false;
-		}
-		if(anEvent.keyCode === 73) { //ctrl+i
-			self._inspectIt();
-			anEvent.preventDefault();
-			return false;
-		}
-	};
-return self}, function($ctx1) {$ctx1.fill(self,"onKeyDown:",{anEvent:anEvent},globals.HLInspectorModel)})},
-args: ["anEvent"],
-source: "onKeyDown: anEvent\x0a\x0a\x09<if(anEvent.ctrlKey) {\x0a\x09\x09if(anEvent.keyCode === 80) { //ctrl+p\x0a\x09\x09\x09self._printIt();\x0a\x09\x09\x09anEvent.preventDefault();\x0a\x09\x09\x09return false;\x0a\x09\x09}\x0a\x09\x09if(anEvent.keyCode === 68) { //ctrl+d\x0a\x09\x09\x09self._doIt();\x0a\x09\x09\x09anEvent.preventDefault();\x0a\x09\x09\x09return false;\x0a\x09\x09}\x0a\x09\x09if(anEvent.keyCode === 73) { //ctrl+i\x0a\x09\x09\x09self._inspectIt();\x0a\x09\x09\x09anEvent.preventDefault();\x0a\x09\x09\x09return false;\x0a\x09\x09}\x0a\x09}>",
-messageSends: [],
-referencedClasses: []
-}),
-globals.HLInspectorModel);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectedInstVar:",
@@ -789,12 +757,13 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 _st(self._model())._inspect_on_(anObject,self);
+_st(self._codeWidget())._receiver_(anObject);
 self._refreshVariablesWidget();
 $1=self._refreshDisplayWidget();
 return self}, function($ctx1) {$ctx1.fill(self,"inspect:",{anObject:anObject},globals.HLInspectorWidget)})},
 args: ["anObject"],
-source: "inspect: anObject\x0a\x09self model inspect: anObject on: self.\x0a    \x0a\x09self \x0a    \x09refreshVariablesWidget;\x0a\x09\x09refreshDisplayWidget",
-messageSends: ["inspect:on:", "model", "refreshVariablesWidget", "refreshDisplayWidget"],
+source: "inspect: anObject\x0a\x09self model inspect: anObject on: self.\x0a\x09self codeWidget receiver: anObject.\x0a    \x0a\x09self \x0a    \x09refreshVariablesWidget;\x0a\x09\x09refreshDisplayWidget",
+messageSends: ["inspect:on:", "model", "receiver:", "codeWidget", "refreshVariablesWidget", "refreshDisplayWidget"],
 referencedClasses: []
 }),
 globals.HLInspectorWidget);
@@ -1011,12 +980,11 @@ protocol: 'reactions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._codeWidget())._receiver_(_st(self._model())._selectedInstVarObject());
 self._refreshDisplayWidget();
 return self}, function($ctx1) {$ctx1.fill(self,"onInstanceVariableSelected",{},globals.HLInspectorWidget)})},
 args: [],
-source: "onInstanceVariableSelected\x0a\x09self codeWidget receiver: self model selectedInstVarObject.\x0a\x09self refreshDisplayWidget",
-messageSends: ["receiver:", "codeWidget", "selectedInstVarObject", "model", "refreshDisplayWidget"],
+source: "onInstanceVariableSelected\x0a\x09self refreshDisplayWidget",
+messageSends: ["refreshDisplayWidget"],
 referencedClasses: []
 }),
 globals.HLInspectorWidget);

+ 1 - 24
st/Helios-Inspector.st → js/Helios-Inspector.st

@@ -111,29 +111,6 @@ subscribe: aWidget
 	aWidget subscribeTo: self announcer
 ! !
 
-!HLInspectorModel methodsFor: 'reactions'!
-
-onKeyDown: anEvent
-
-	<if(anEvent.ctrlKey) {
-		if(anEvent.keyCode === 80) { //ctrl+p
-			self._printIt();
-			anEvent.preventDefault();
-			return false;
-		}
-		if(anEvent.keyCode === 68) { //ctrl+d
-			self._doIt();
-			anEvent.preventDefault();
-			return false;
-		}
-		if(anEvent.keyCode === 73) { //ctrl+i
-			self._inspectIt();
-			anEvent.preventDefault();
-			return false;
-		}
-	}>
-! !
-
 !HLInspectorModel class methodsFor: 'actions'!
 
 on: anEnvironment
@@ -287,6 +264,7 @@ variablesWidget
 
 inspect: anObject
 	self model inspect: anObject on: self.
+	self codeWidget receiver: anObject.
     
 	self 
     	refreshVariablesWidget;
@@ -349,7 +327,6 @@ onInspectIt
 !
 
 onInstanceVariableSelected
-	self codeWidget receiver: self model selectedInstVarObject.
 	self refreshDisplayWidget
 !
 

+ 52 - 24
js/Helios-KeyBindings.js

@@ -492,9 +492,8 @@ $1=_st(self._bindings())._detect_ifNone_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(_st(each)._label()).__eq(aString);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"at:",{aString:aString},globals.HLBindingGroup)})},
 args: ["aString"],
@@ -541,9 +540,8 @@ $1=_st(self._bindings())._detect_ifNone_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(_st(each)._key()).__eq(anInteger);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"atKey:",{anInteger:anInteger},globals.HLBindingGroup)})},
 args: ["anInteger"],
@@ -668,8 +666,7 @@ var $2,$1;
 $2=self["@callback"];
 if(($receiver = $2) == nil || $receiver == null){
 self["@callback"]=(function(value){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1,2)})});
+});
 $1=self["@callback"];
 } else {
 $1=$2;
@@ -990,7 +987,7 @@ self["@input"]=$5;
 self["@input"];
 $11=_st(self["@input"])._asJQuery();
 $ctx2.sendIdx["asJQuery"]=2;
-_st($11)._typeahead_(globals.HashedCollection._from_(["source".__minus_gt(self._inputCompletion())]));
+_st($11)._typeahead_(globals.HashedCollection._newFromPairs_(["source",self._inputCompletion()]));
 $12=_st(html)._span();
 _st($12)._class_("help-inline");
 _st($12)._with_(self._message());
@@ -1006,7 +1003,7 @@ return _st(_st(self["@input"])._asJQuery())._focus();
 return self}, function($ctx1) {$ctx1.fill(self,"renderOn:",{html:html},globals.HLBindingActionInputWidget)})},
 args: ["html"],
 source: "renderOn: html\x0a\x09wrapper ifNil: [ wrapper := html span ].\x0a\x0a\x09wrapper \x0a\x09\x09class: self status;\x0a\x09\x09with: [\x0a\x09\x09\x09input := html input\x0a\x09\x09\x09\x09placeholder: self ghostText;\x0a\x09\x09\x09\x09value: self defaultValue;\x0a\x09\x09\x09\x09onKeyDown: [ :event | \x0a\x09\x09\x09\x09\x09event which = 13 ifTrue: [\x0a\x09\x09\x09\x09\x09\x09self evaluate: input asJQuery val ] ]\x0a\x09\x09\x09\x09yourself.\x0a\x09\x09\x09input asJQuery \x0a\x09\x09\x09\x09typeahead: #{ 'source' -> self inputCompletion }.\x0a\x09\x09\x09messageTag := (html span\x0a\x09\x09\x09\x09class: 'help-inline';\x0a\x09\x09\x09\x09with: self message;\x0a\x09\x09\x09\x09yourself) ].\x0a\x09\x0a\x09\x22Evaluate with a timeout to ensure focus.\x0a\x09Commands can be executed from a menu, clicking on the menu to\x0a\x09evaluate the command would give it the focus otherwise\x22\x0a\x09\x0a\x09[ input asJQuery focus ] valueWithTimeout: 10",
-messageSends: ["ifNil:", "span", "class:", "status", "with:", "placeholder:", "input", "ghostText", "value:", "defaultValue", "onKeyDown:", "yourself", "ifTrue:", "=", "which", "evaluate:", "val", "asJQuery", "typeahead:", "->", "inputCompletion", "message", "valueWithTimeout:", "focus"],
+messageSends: ["ifNil:", "span", "class:", "status", "with:", "placeholder:", "input", "ghostText", "value:", "defaultValue", "onKeyDown:", "yourself", "ifTrue:", "=", "which", "evaluate:", "val", "asJQuery", "typeahead:", "inputCompletion", "message", "valueWithTimeout:", "focus"],
 referencedClasses: []
 }),
 globals.HLBindingActionInputWidget);
@@ -1558,6 +1555,22 @@ referencedClasses: []
 }),
 globals.HLKeyBinderHelperWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "deactivate",
+protocol: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._keyBinder())._deactivate();
+return self}, function($ctx1) {$ctx1.fill(self,"deactivate",{},globals.HLKeyBinderHelperWidget)})},
+args: [],
+source: "deactivate\x0a\x09self keyBinder deactivate",
+messageSends: ["deactivate", "keyBinder"],
+referencedClasses: []
+}),
+globals.HLKeyBinderHelperWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "hide",
@@ -1565,11 +1578,16 @@ protocol: 'actions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(".".__comma(self._cssClass()))._asJQuery())._remove();
+var $1;
+$1=_st(".".__comma(self._cssClass()))._asJQuery();
+$ctx1.sendIdx["asJQuery"]=1;
+_st($1)._remove();
+$ctx1.sendIdx["remove"]=1;
+_st("#overlay"._asJQuery())._remove();
 self._showCog();
 return self}, function($ctx1) {$ctx1.fill(self,"hide",{},globals.HLKeyBinderHelperWidget)})},
 args: [],
-source: "hide\x0a\x09('.', self cssClass) asJQuery remove.\x0a\x09self showCog",
+source: "hide\x0a\x09('.', self cssClass) asJQuery remove.\x0a\x09'#overlay' asJQuery remove.\x0a\x09self showCog",
 messageSends: ["remove", "asJQuery", ",", "cssClass", "showCog"],
 referencedClasses: []
 }),
@@ -1647,12 +1665,11 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1,$3,$4,$5,$6,$2;
 $1=_st(html)._span();
-$ctx1.sendIdx["span"]=1;
 _st($1)._class_("command");
 $ctx1.sendIdx["class:"]=1;
 $2=_st($1)._with_((function(){
 return smalltalk.withContext(function($ctx2) {
-$3=_st(html)._span();
+$3=_st(html)._strong();
 _st($3)._class_("label");
 $ctx2.sendIdx["class:"]=2;
 $4=_st($3)._with_(_st(_st(aBinding)._shortcut())._asLowercase());
@@ -1670,8 +1687,8 @@ return $6;
 $ctx1.sendIdx["with:"]=1;
 return self}, function($ctx1) {$ctx1.fill(self,"renderBindingActionFor:on:",{aBinding:aBinding,html:html},globals.HLKeyBinderHelperWidget)})},
 args: ["aBinding", "html"],
-source: "renderBindingActionFor: aBinding on: html\x0a\x09html span class: 'command'; with: [\x0a\x09\x09html span \x0a\x09\x09\x09class: 'label'; \x0a\x09\x09\x09with: aBinding shortcut asLowercase.\x0a  \x09\x09html a \x0a        \x09class: 'action'; \x0a            with: aBinding displayLabel;\x0a  \x09\x09\x09onClick: [ self keyBinder applyBinding: aBinding ] ]",
-messageSends: ["class:", "span", "with:", "asLowercase", "shortcut", "a", "displayLabel", "onClick:", "applyBinding:", "keyBinder"],
+source: "renderBindingActionFor: aBinding on: html\x0a\x09html span class: 'command'; with: [\x0a\x09\x09html strong \x0a\x09\x09\x09class: 'label'; \x0a\x09\x09\x09with: aBinding shortcut asLowercase.\x0a  \x09\x09html a \x0a        \x09class: 'action'; \x0a            with: aBinding displayLabel;\x0a  \x09\x09\x09onClick: [ self keyBinder applyBinding: aBinding ] ]",
+messageSends: ["class:", "span", "with:", "strong", "asLowercase", "shortcut", "a", "displayLabel", "onClick:", "applyBinding:", "keyBinder"],
 referencedClasses: []
 }),
 globals.HLKeyBinderHelperWidget);
@@ -1771,27 +1788,38 @@ protocol: 'rendering',
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$2;
+var $1,$2,$3,$5,$6,$4;
 $1=_st(html)._div();
 $ctx1.sendIdx["div"]=1;
-_st($1)._class_(self._cssClass());
-$2=_st($1)._with_((function(){
+_st($1)._id_("overlay");
+$ctx1.sendIdx["id:"]=1;
+_st($1)._class_("light");
+$ctx1.sendIdx["class:"]=1;
+$2=_st($1)._onClick_((function(){
 return smalltalk.withContext(function($ctx2) {
-self._renderLabelOn_(html);
+return self._deactivate();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 $3=_st(html)._div();
-_st($3)._id_(self._mainId());
+$ctx1.sendIdx["div"]=2;
+_st($3)._class_(self._cssClass());
 $4=_st($3)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
+self._renderLabelOn_(html);
+$5=_st(html)._div();
+_st($5)._id_(self._mainId());
+$6=_st($5)._with_((function(){
 return smalltalk.withContext(function($ctx3) {
 return self._renderSelectedBindingOn_(html);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
-$4;
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
+$6;
 return self._renderCloseOn_(html);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 $ctx1.sendIdx["with:"]=1;
+_st(":focus"._asJQuery())._blur();
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLKeyBinderHelperWidget)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html div 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 ]",
-messageSends: ["class:", "div", "cssClass", "with:", "renderLabelOn:", "id:", "mainId", "renderSelectedBindingOn:", "renderCloseOn:"],
+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",
+messageSends: ["id:", "div", "class:", "onClick:", "deactivate", "cssClass", "with:", "renderLabelOn:", "mainId", "renderSelectedBindingOn:", "renderCloseOn:", "blur", "asJQuery"],
 referencedClasses: []
 }),
 globals.HLKeyBinderHelperWidget);

+ 15 - 3
st/Helios-KeyBindings.st → js/Helios-KeyBindings.st

@@ -536,8 +536,13 @@ selectedBinding
 
 !HLKeyBinderHelperWidget methodsFor: 'actions'!
 
+deactivate
+	self keyBinder deactivate
+!
+
 hide
 	('.', self cssClass) asJQuery remove.
+	'#overlay' asJQuery remove.
 	self showCog
 !
 
@@ -566,7 +571,7 @@ showWidget: aWidget
 
 renderBindingActionFor: aBinding on: html
 	html span class: 'command'; with: [
-		html span 
+		html strong 
 			class: 'label'; 
 			with: aBinding shortcut asLowercase.
   		html a 
@@ -600,12 +605,19 @@ renderCog
 !
 
 renderContentOn: html
+	html div 
+		id: 'overlay';
+		class: 'light';
+		onClick: [ self deactivate ].
+	
 	html div class: self cssClass; with: [
-      	self renderLabelOn:html.
+      	self renderLabelOn: html.
 		html div
 			id: self mainId;
 			with: [ self renderSelectedBindingOn: html ].
-		self renderCloseOn: html ]
+		self renderCloseOn: html ].
+		
+	':focus' asJQuery blur
 !
 
 renderLabelOn: html

+ 10 - 28
js/Helios-Layout.js

@@ -394,29 +394,20 @@ protocol: 'rendering',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$5,$6,$2;
+var $1;
 $1=_st(self["@splitter"])._asJQuery();
 $ctx1.sendIdx["asJQuery"]=1;
-$3="axis".__minus_gt("y");
-$ctx1.sendIdx["->"]=1;
-$4="containment".__minus_gt(_st(_st(self["@splitter"])._asJQuery())._parent());
-$ctx1.sendIdx["->"]=2;
-$5="helper".__minus_gt("clone");
-$ctx1.sendIdx["->"]=3;
-$6="start".__minus_gt((function(e,ui){
+_st($1)._draggable_(globals.HashedCollection._newFromPairs_(["axis","y","containment",_st(_st(self["@splitter"])._asJQuery())._parent(),"helper","clone","start",(function(e,ui){
 return smalltalk.withContext(function($ctx2) {
 return self._startResizing_(_st(ui)._helper());
-}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,1)})}));
-$ctx1.sendIdx["->"]=4;
-$2=globals.HashedCollection._from_([$3,$4,$5,$6,"drag".__minus_gt((function(e,ui){
+}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,1)})}),"drag",(function(e,ui){
 return smalltalk.withContext(function($ctx2) {
 return self._resize_(_st(_st(ui)._offset())._top());
-}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,2)})}))]);
-_st($1)._draggable_($2);
+}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,2)})})]));
 return self}, function($ctx1) {$ctx1.fill(self,"setupSplitter",{},globals.HLHorizontalSplitter)})},
 args: [],
 source: "setupSplitter\x0a\x09splitter asJQuery draggable: #{ \x0a    \x09'axis' -> 'y'. \x0a        'containment' -> splitter asJQuery parent.\x0a        'helper' -> 'clone'.\x0a        'start' -> [ :e :ui | self startResizing: ui helper ].\x0a        'drag' -> [ :e :ui | self resize: ui offset top ] }",
-messageSends: ["draggable:", "asJQuery", "->", "parent", "startResizing:", "helper", "resize:", "top", "offset"],
+messageSends: ["draggable:", "asJQuery", "parent", "startResizing:", "helper", "resize:", "top", "offset"],
 referencedClasses: []
 }),
 globals.HLHorizontalSplitter);
@@ -551,29 +542,20 @@ protocol: 'rendering',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$5,$6,$2;
+var $1;
 $1=_st(self["@splitter"])._asJQuery();
 $ctx1.sendIdx["asJQuery"]=1;
-$3="axis".__minus_gt("x");
-$ctx1.sendIdx["->"]=1;
-$4="containment".__minus_gt(_st(_st(self["@splitter"])._asJQuery())._parent());
-$ctx1.sendIdx["->"]=2;
-$5="helper".__minus_gt("clone");
-$ctx1.sendIdx["->"]=3;
-$6="start".__minus_gt((function(e,ui){
+_st($1)._draggable_(globals.HashedCollection._newFromPairs_(["axis","x","containment",_st(_st(self["@splitter"])._asJQuery())._parent(),"helper","clone","start",(function(e,ui){
 return smalltalk.withContext(function($ctx2) {
 return self._startResizing_(_st(ui)._helper());
-}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,1)})}));
-$ctx1.sendIdx["->"]=4;
-$2=globals.HashedCollection._from_([$3,$4,$5,$6,"drag".__minus_gt((function(e,ui){
+}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,1)})}),"drag",(function(e,ui){
 return smalltalk.withContext(function($ctx2) {
 return self._resize_(_st(_st(ui)._offset())._left());
-}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,2)})}))]);
-_st($1)._draggable_($2);
+}, function($ctx2) {$ctx2.fillBlock({e:e,ui:ui},$ctx1,2)})})]));
 return self}, function($ctx1) {$ctx1.fill(self,"setupSplitter",{},globals.HLVerticalSplitter)})},
 args: [],
 source: "setupSplitter\x0a\x09splitter asJQuery draggable: #{ \x0a    \x09'axis' -> 'x'. \x0a        'containment' -> splitter asJQuery parent.\x0a        'helper' -> 'clone'.\x0a        'start' -> [ :e :ui | self startResizing: ui helper ].\x0a        'drag' -> [ :e :ui | self resize: (ui offset left) ] }",
-messageSends: ["draggable:", "asJQuery", "->", "parent", "startResizing:", "helper", "resize:", "left", "offset"],
+messageSends: ["draggable:", "asJQuery", "parent", "startResizing:", "helper", "resize:", "left", "offset"],
 referencedClasses: []
 }),
 globals.HLVerticalSplitter);

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


+ 1 - 2
js/Helios-References.js

@@ -545,9 +545,8 @@ $1=_st(aMethod)._selector();
 $ctx2.sendIdx["selector"]=1;
 return _st(each).__eq($1);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[self];
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+}));
 $2=_st(aMethod)._selector();
 $ctx1.sendIdx["selector"]=2;
 self._selectedItem_($2);

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


+ 0 - 0
st/Helios-Transcript.st → js/Helios-Transcript.st


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


+ 57 - 164
js/Helios-Workspace.js

@@ -390,35 +390,18 @@ selector: "editorOptions",
 protocol: 'accessing',
 fn: function (){
 var self=this;
+function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$1;
-$2="theme".__minus_gt("default");
-$ctx1.sendIdx["->"]=1;
-$3="mode".__minus_gt("text/x-stsrc");
-$ctx1.sendIdx["->"]=2;
-$4="lineNumbers".__minus_gt(true);
-$ctx1.sendIdx["->"]=3;
-$5="enterMode".__minus_gt("flat");
-$ctx1.sendIdx["->"]=4;
-$6="indentWithTabs".__minus_gt(true);
-$ctx1.sendIdx["->"]=5;
-$7="indentUnit".__minus_gt((4));
-$ctx1.sendIdx["->"]=6;
-$8="matchBrackets".__minus_gt(true);
-$ctx1.sendIdx["->"]=7;
-$9="electricChars".__minus_gt(false);
-$ctx1.sendIdx["->"]=8;
-$10="keyMap".__minus_gt("Amber");
-$ctx1.sendIdx["->"]=9;
-$11="extraKeys".__minus_gt(globals.HashedCollection._from_(["Shift-Space".__minus_gt("autocomplete")]));
-$ctx1.sendIdx["->"]=10;
-$1=globals.HashedCollection._from_([$2,$3,$4,$5,$6,$7,$8,$9,$10,$11]);
+var $2,$1;
+$2="helios.codeMirrorTheme"._settingValueIfAbsent_("default helios");
+$ctx1.sendIdx["settingValueIfAbsent:"]=1;
+$1=globals.HashedCollection._newFromPairs_(["theme",$2,"mode","text/x-stsrc","lineNumbers",true,"enterMode","flat","indentWithTabs",true,"indentUnit",(4),"matchBrackets",true,"electricChars",false,"keyMap","Amber","extraKeys",_st($HashedCollection())._with_(_st("helios.completionKey"._settingValueIfAbsent_("Shift-Space")).__minus_gt("autocomplete"))]);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"editorOptions",{},globals.HLCodeWidget)})},
 args: [],
-source: "editorOptions\x0a\x09^ #{\x0a\x09\x09'theme' -> 'default'.\x0a\x09\x09'mode' -> 'text/x-stsrc'.\x0a        'lineNumbers' -> true.\x0a        'enterMode' -> 'flat'.\x0a        'indentWithTabs' -> true.\x0a\x09\x09'indentUnit' -> 4.\x0a        'matchBrackets' -> true.\x0a        'electricChars' -> false.\x0a\x09\x09'keyMap' -> 'Amber'.\x0a\x09\x09'extraKeys' -> #{'Shift-Space' -> 'autocomplete'}\x0a\x09}",
-messageSends: ["->"],
-referencedClasses: []
+source: "editorOptions\x0a\x09^ #{\x0a\x09\x09'theme' -> ('helios.codeMirrorTheme' settingValueIfAbsent: 'default helios').\x0a\x09\x09'mode' -> 'text/x-stsrc'.\x0a        'lineNumbers' -> true.\x0a        'enterMode' -> 'flat'.\x0a        'indentWithTabs' -> true.\x0a\x09\x09'indentUnit' -> 4.\x0a        'matchBrackets' -> true.\x0a        'electricChars' -> false.\x0a\x09\x09'keyMap' -> 'Amber'.\x0a\x09\x09'extraKeys' -> (HashedCollection with: ('helios.completionKey' settingValueIfAbsent: 'Shift-Space') -> 'autocomplete')\x0a\x09}",
+messageSends: ["settingValueIfAbsent:", "with:", "->"],
+referencedClasses: ["HashedCollection"]
 }),
 globals.HLCodeWidget);
 
@@ -648,7 +631,7 @@ var self=this;
 var start,stop,currentLine;
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$4,$3,$5,$6,$7,$8,$10,$9,$11,$12,$13,$15,$14;
+var $1,$2,$4,$3,$5,$6,$7,$8,$9,$10,$12,$11;
 $1=_st(self["@editor"])._getCursor_(false);
 $ctx1.sendIdx["getCursor:"]=1;
 currentLine=_st($1)._line();
@@ -671,32 +654,28 @@ $7=_st(_st(self["@editor"])._getLine_(currentLine))._size();
 $ctx2.sendIdx["size"]=1;
 _st($6)._at_put_("ch",$7);
 $ctx2.sendIdx["at:put:"]=3;
-$8=self["@editor"];
-$10="line".__minus_gt(currentLine);
-$ctx2.sendIdx["->"]=1;
-$9=globals.HashedCollection._from_([$10,"ch".__minus_gt((0))]);
-return _st($8)._setSelection_end_($9,start);
+return _st(self["@editor"])._setSelection_end_(globals.HashedCollection._newFromPairs_(["line",currentLine,"ch",(0)]),start);
 $ctx2.sendIdx["setSelection:end:"]=1;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 stop=_st($HashedCollection())._new();
 _st(stop)._at_put_("line",currentLine);
 $ctx1.sendIdx["at:put:"]=4;
-$11=stop;
-$12=_st(_st(_st(start)._at_("ch")).__plus(_st(aString)._size())).__plus((2));
+$8=stop;
+$9=_st(_st(_st(start)._at_("ch")).__plus(_st(aString)._size())).__plus((2));
 $ctx1.sendIdx["+"]=1;
-_st($11)._at_put_("ch",$12);
-$13=self["@editor"];
-$15=_st(_st(_st(self["@editor"])._getSelection()).__comma(" ")).__comma(aString);
+_st($8)._at_put_("ch",$9);
+$10=self["@editor"];
+$12=_st(_st(_st(self["@editor"])._getSelection()).__comma(" ")).__comma(aString);
 $ctx1.sendIdx[","]=2;
-$14=_st($15).__comma(" ");
+$11=_st($12).__comma(" ");
 $ctx1.sendIdx[","]=1;
-_st($13)._replaceSelection_($14);
+_st($10)._replaceSelection_($11);
 _st(self["@editor"])._setCursor_(_st(self["@editor"])._getCursor_(true));
 _st(self["@editor"])._setSelection_end_(stop,start);
 return self}, function($ctx1) {$ctx1.fill(self,"print:",{aString:aString,start:start,stop:stop,currentLine:currentLine},globals.HLCodeWidget)})},
 args: ["aString"],
 source: "print: aString\x0a\x09| start stop currentLine |\x0a    currentLine := (editor getCursor: false) line.\x0a\x09start := HashedCollection new.\x0a\x09start at: 'line' put: currentLine.\x0a\x09start at: 'ch' put: (editor getCursor: false) ch.\x0a    (editor getSelection) ifEmpty: [\x0a    \x09\x22select current line if selection is empty\x22\x0a    \x09start at: 'ch' put: (editor getLine: currentLine) size.\x0a        editor setSelection: #{'line' -> currentLine. 'ch' -> 0} end: start.\x0a    ].\x0a\x09stop := HashedCollection new.\x0a\x09stop at: 'line' put: currentLine.\x0a\x09stop at: 'ch' put: ((start at: 'ch') + aString size + 2).\x0a\x0a\x09editor replaceSelection: (editor getSelection, ' ', aString, ' ').\x0a\x09editor setCursor: (editor getCursor: true).\x0a\x09editor setSelection: stop end: start",
-messageSends: ["line", "getCursor:", "new", "at:put:", "ch", "ifEmpty:", "getSelection", "size", "getLine:", "setSelection:end:", "->", "+", "at:", "replaceSelection:", ",", "setCursor:"],
+messageSends: ["line", "getCursor:", "new", "at:put:", "ch", "ifEmpty:", "getSelection", "size", "getLine:", "setSelection:end:", "+", "at:", "replaceSelection:", ",", "setCursor:"],
 referencedClasses: ["HashedCollection"]
 }),
 globals.HLCodeWidget);
@@ -1039,7 +1018,7 @@ var cursor,token,completions;
 function $CodeMirror(){return globals.CodeMirror||(typeof CodeMirror=="undefined"?nil:CodeMirror)}
 function $HLCodeWidget(){return globals.HLCodeWidget||(typeof HLCodeWidget=="undefined"?nil:HLCodeWidget)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$4,$3,$2,$5,$7,$10,$11,$9,$8,$6;
+var $1,$4,$3,$2,$5,$7,$9,$10,$8,$6;
 cursor=_st(anEditor)._getCursor();
 token=_st(anEditor)._getTokenAt_(cursor);
 $1=token;
@@ -1055,22 +1034,19 @@ completions=_st($HLCodeWidget())._variableHintFor_token_(anEditor,token);
 } else {
 completions=_st($HLCodeWidget())._messageHintFor_token_(anEditor,token);
 };
-$7="list".__minus_gt(completions);
-$ctx1.sendIdx["->"]=1;
-$10=_st($CodeMirror())._basicAt_("Pos");
+$7=completions;
+$9=_st($CodeMirror())._basicAt_("Pos");
 $ctx1.sendIdx["basicAt:"]=2;
-$11=_st(cursor)._line();
+$10=_st(cursor)._line();
 $ctx1.sendIdx["line"]=1;
-$9=_st($10)._value_value_($11,_st(token)._end());
+$8=_st($9)._value_value_($10,_st(token)._end());
 $ctx1.sendIdx["value:value:"]=2;
-$8="from".__minus_gt($9);
-$ctx1.sendIdx["->"]=2;
-$6=globals.HashedCollection._from_([$7,$8,"to".__minus_gt(_st(_st($CodeMirror())._basicAt_("Pos"))._value_value_(_st(cursor)._line(),_st(token)._start()))]);
+$6=globals.HashedCollection._newFromPairs_(["list",$7,"from",$8,"to",_st(_st($CodeMirror())._basicAt_("Pos"))._value_value_(_st(cursor)._line(),_st(token)._start())]);
 return $6;
 }, function($ctx1) {$ctx1.fill(self,"hintFor:options:",{anEditor:anEditor,options:options,cursor:cursor,token:token,completions:completions},globals.HLCodeWidget.klass)})},
 args: ["anEditor", "options"],
 source: "hintFor: anEditor options: options\x0a\x09| cursor token completions |\x0a\x09\x0a\x09cursor := anEditor getCursor.\x0a\x09token := anEditor getTokenAt: cursor.\x0a\x09token at: 'state' put: ((CodeMirror basicAt: 'innerMode')\x0a\x09\x09value: anEditor getMode value: (token at: 'state')) state.\x0a\x09\x0a\x09completions := token type = 'variable' \x0a\x09\x09ifTrue: [ HLCodeWidget variableHintFor: anEditor token: token ]\x0a\x09\x09ifFalse: [ HLCodeWidget messageHintFor: anEditor token: token ].\x0a\x09\x0a\x09^ #{\x0a\x09\x09'list' -> completions.\x0a\x09\x09'from' -> ((CodeMirror basicAt: 'Pos') value: cursor line value: token end).\x0a\x09\x09'to' -> ((CodeMirror basicAt: 'Pos') value: cursor line value: token start)\x0a\x09}",
-messageSends: ["getCursor", "getTokenAt:", "at:put:", "state", "value:value:", "basicAt:", "getMode", "at:", "ifTrue:ifFalse:", "=", "type", "variableHintFor:token:", "messageHintFor:token:", "->", "line", "end", "start"],
+messageSends: ["getCursor", "getTokenAt:", "at:put:", "state", "value:value:", "basicAt:", "getMode", "at:", "ifTrue:ifFalse:", "=", "type", "variableHintFor:token:", "messageHintFor:token:", "line", "end", "start"],
 referencedClasses: ["CodeMirror", "HLCodeWidget"]
 }),
 globals.HLCodeWidget.klass);
@@ -1125,64 +1101,13 @@ selector: "macKeyMap",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$1;
-$2="Alt-Backspace".__minus_gt("delWordBefore");
-$ctx1.sendIdx["->"]=1;
-$3="Alt-Delete".__minus_gt("delWordAfter");
-$ctx1.sendIdx["->"]=2;
-$4="Alt-Left".__minus_gt("goWordBoundaryLeft");
-$ctx1.sendIdx["->"]=3;
-$5="Alt-Right".__minus_gt("goWordBoundaryRight");
-$ctx1.sendIdx["->"]=4;
-$6="Cmd-A".__minus_gt("selectAll");
-$ctx1.sendIdx["->"]=5;
-$7="Cmd-Alt-F".__minus_gt("replace");
-$ctx1.sendIdx["->"]=6;
-$8="Cmd-D".__minus_gt("doIt");
-$ctx1.sendIdx["->"]=7;
-$9="Cmd-Down".__minus_gt("goDocEnd");
-$ctx1.sendIdx["->"]=8;
-$10="Cmd-End".__minus_gt("goDocEnd");
-$ctx1.sendIdx["->"]=9;
-$11="Cmd-F".__minus_gt("find");
-$ctx1.sendIdx["->"]=10;
-$12="Cmd-G".__minus_gt("findNext");
-$ctx1.sendIdx["->"]=11;
-$13="Cmd-I".__minus_gt("inspectIt");
-$ctx1.sendIdx["->"]=12;
-$14="Cmd-Left".__minus_gt("goLineStart");
-$ctx1.sendIdx["->"]=13;
-$15="Cmd-P".__minus_gt("printIt");
-$ctx1.sendIdx["->"]=14;
-$16="Cmd-Right".__minus_gt("goLineEnd");
-$ctx1.sendIdx["->"]=15;
-$17="Cmd-S".__minus_gt("saveIt");
-$ctx1.sendIdx["->"]=16;
-$18="Cmd-Up".__minus_gt("goDocStart");
-$ctx1.sendIdx["->"]=17;
-$19="Cmd-Y".__minus_gt("redo");
-$ctx1.sendIdx["->"]=18;
-$20="Cmd-Z".__minus_gt("undo");
-$ctx1.sendIdx["->"]=19;
-$21="Cmd-[".__minus_gt("indentLess");
-$ctx1.sendIdx["->"]=20;
-$22="Cmd-]".__minus_gt("indentMore");
-$ctx1.sendIdx["->"]=21;
-$23="Ctrl-Alt-Backspace".__minus_gt("delWordAfter");
-$ctx1.sendIdx["->"]=22;
-$24="Shift-Cmd-Alt-F".__minus_gt("replaceAll");
-$ctx1.sendIdx["->"]=23;
-$25="Shift-Cmd-G".__minus_gt("findPrev");
-$ctx1.sendIdx["->"]=24;
-$26="Shift-Cmd-Z".__minus_gt("redo");
-$ctx1.sendIdx["->"]=25;
-$1=globals.HashedCollection._from_([$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,"fallthrough".__minus_gt(["basic","emacsy"])]);
+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"]]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"macKeyMap",{},globals.HLCodeWidget.klass)})},
+},
 args: [],
-source: "macKeyMap\x0a\x09^ #{\x0a\x09\x09'Alt-Backspace'\x09\x09-> 'delWordBefore'.\x0a\x09\x09'Alt-Delete'\x09\x09-> 'delWordAfter'. \x0a\x09\x09'Alt-Left'\x09\x09-> 'goWordBoundaryLeft'.\x0a\x09\x09'Alt-Right'\x09\x09-> 'goWordBoundaryRight'. \x0a\x09\x09'Cmd-A'\x09\x09\x09-> 'selectAll'. \x0a\x09\x09'Cmd-Alt-F'\x09\x09-> 'replace'. \x0a\x09\x09'Cmd-D'\x09\x09\x09-> 'doIt'. \x0a\x09\x09'Cmd-Down'\x09\x09-> 'goDocEnd'. \x0a\x09\x09'Cmd-End'\x09\x09-> 'goDocEnd'. \x0a\x09\x09'Cmd-F'\x09\x09\x09-> 'find'.\x0a\x09\x09'Cmd-G'\x09\x09\x09-> 'findNext'. \x0a\x09\x09'Cmd-I'\x09\x09\x09-> 'inspectIt'. \x0a\x09\x09'Cmd-Left'\x09\x09-> 'goLineStart'. \x0a\x09\x09'Cmd-P'\x09\x09\x09-> 'printIt'. \x0a\x09\x09'Cmd-Right'\x09\x09-> 'goLineEnd'. \x0a\x09\x09'Cmd-S'\x09\x09\x09-> 'saveIt'. \x0a\x09\x09'Cmd-Up'\x09\x09-> 'goDocStart'. \x0a\x09\x09'Cmd-Y'\x09\x09\x09-> 'redo'.\x0a\x09\x09'Cmd-Z'\x09\x09\x09-> 'undo'. \x0a\x09\x09'Cmd-['\x09\x09\x09-> 'indentLess'. \x0a\x09\x09'Cmd-]'\x09\x09\x09-> 'indentMore'.\x0a\x09\x09'Ctrl-Alt-Backspace'\x09-> 'delWordAfter'. \x0a\x09\x09'Shift-Cmd-Alt-F'\x09-> 'replaceAll'.\x0a\x09\x09'Shift-Cmd-G'\x09\x09-> 'findPrev'. \x0a\x09\x09'Shift-Cmd-Z'\x09\x09-> 'redo'. \x0a    \x09'fallthrough' \x09-> { 'basic'. 'emacsy' }\x0a  }",
-messageSends: ["->"],
+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  }",
+messageSends: [],
 referencedClasses: []
 }),
 globals.HLCodeWidget.klass);
@@ -1211,64 +1136,13 @@ selector: "pcKeyMap",
 protocol: 'accessing',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$1;
-$2="Alt-Left".__minus_gt("goLineStart");
-$ctx1.sendIdx["->"]=1;
-$3="Alt-Right".__minus_gt("goLineEnd");
-$ctx1.sendIdx["->"]=2;
-$4="Alt-Up".__minus_gt("goDocStart");
-$ctx1.sendIdx["->"]=3;
-$5="Ctrl-A".__minus_gt("selectAll");
-$ctx1.sendIdx["->"]=4;
-$6="Ctrl-Backspace".__minus_gt("delWordBefore");
-$ctx1.sendIdx["->"]=5;
-$7="Ctrl-D".__minus_gt("doIt");
-$ctx1.sendIdx["->"]=6;
-$8="Ctrl-Delete".__minus_gt("delWordAfter");
-$ctx1.sendIdx["->"]=7;
-$9="Ctrl-Down".__minus_gt("goDocEnd");
-$ctx1.sendIdx["->"]=8;
-$10="Ctrl-End".__minus_gt("goDocEnd");
-$ctx1.sendIdx["->"]=9;
-$11="Ctrl-F".__minus_gt("find");
-$ctx1.sendIdx["->"]=10;
-$12="Ctrl-G".__minus_gt("findNext");
-$ctx1.sendIdx["->"]=11;
-$13="Ctrl-I".__minus_gt("inspectIt");
-$ctx1.sendIdx["->"]=12;
-$14="Ctrl-Home".__minus_gt("goDocStart");
-$ctx1.sendIdx["->"]=13;
-$15="Ctrl-Left".__minus_gt("goWordBoundaryLeft");
-$ctx1.sendIdx["->"]=14;
-$16="Ctrl-P".__minus_gt("printIt");
-$ctx1.sendIdx["->"]=15;
-$17="Ctrl-Right".__minus_gt("goWordBoundaryRight");
-$ctx1.sendIdx["->"]=16;
-$18="Ctrl-S".__minus_gt("saveIt");
-$ctx1.sendIdx["->"]=17;
-$19="Ctrl-Y".__minus_gt("redo");
-$ctx1.sendIdx["->"]=18;
-$20="Ctrl-Z".__minus_gt("undo");
-$ctx1.sendIdx["->"]=19;
-$21="Ctrl-[".__minus_gt("indentLess");
-$ctx1.sendIdx["->"]=20;
-$22="Ctrl-]".__minus_gt("indentMore");
-$ctx1.sendIdx["->"]=21;
-$23="Shift-Ctrl-F".__minus_gt("replace");
-$ctx1.sendIdx["->"]=22;
-$24="Shift-Ctrl-G".__minus_gt("findPrev");
-$ctx1.sendIdx["->"]=23;
-$25="Shift-Ctrl-R".__minus_gt("replaceAll");
-$ctx1.sendIdx["->"]=24;
-$26="Shift-Ctrl-Z".__minus_gt("redo");
-$ctx1.sendIdx["->"]=25;
-$1=globals.HashedCollection._from_([$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,"fallthrough".__minus_gt(["basic"])]);
+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"]]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"pcKeyMap",{},globals.HLCodeWidget.klass)})},
+},
 args: [],
-source: "pcKeyMap\x0a\x09^ #{\x0a\x09\x09'Alt-Left' -> 'goLineStart'. \x0a\x09\x09'Alt-Right' -> 'goLineEnd'.\x0a\x09\x09'Alt-Up' -> 'goDocStart'. \x0a\x09\x09'Ctrl-A' -> 'selectAll'. \x0a\x09\x09'Ctrl-Backspace' -> 'delWordBefore'. \x0a\x09\x09'Ctrl-D' -> 'doIt'. \x0a\x09\x09'Ctrl-Delete' -> 'delWordAfter'. \x0a\x09\x09'Ctrl-Down' -> 'goDocEnd'.\x0a\x09\x09'Ctrl-End' -> 'goDocEnd'. \x0a\x09\x09'Ctrl-F' -> 'find'.\x0a\x09\x09'Ctrl-G' -> 'findNext'. \x0a\x09\x09'Ctrl-I' -> 'inspectIt'.\x0a\x09\x09'Ctrl-Home' -> 'goDocStart'. \x0a\x09\x09'Ctrl-Left' -> 'goWordBoundaryLeft'. \x0a\x09\x09'Ctrl-P' -> 'printIt'.\x0a\x09\x09'Ctrl-Right' -> 'goWordBoundaryRight'. \x0a\x09\x09'Ctrl-S' -> 'saveIt'. \x0a\x09\x09'Ctrl-Y' -> 'redo'.\x0a\x09\x09'Ctrl-Z' -> 'undo'. \x0a\x09\x09'Ctrl-[' -> 'indentLess'. \x0a\x09\x09'Ctrl-]' -> 'indentMore'.\x0a\x09\x09'Shift-Ctrl-F' -> 'replace'. \x0a\x09\x09'Shift-Ctrl-G' -> 'findPrev'. \x0a\x09\x09'Shift-Ctrl-R' -> 'replaceAll'.\x0a\x09\x09'Shift-Ctrl-Z' -> 'redo'. \x0a\x09\x09'fallthrough' -> #('basic')\x0a}",
-messageSends: ["->"],
+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}",
+messageSends: [],
 referencedClasses: []
 }),
 globals.HLCodeWidget.klass);
@@ -1588,6 +1462,7 @@ function $HLClassSelected(){return globals.HLClassSelected||(typeof HLClassSelec
 function $HLPackageSelected(){return globals.HLPackageSelected||(typeof HLPackageSelected=="undefined"?nil:HLPackageSelected)}
 function $HLProtocolSelected(){return globals.HLProtocolSelected||(typeof HLProtocolSelected=="undefined"?nil:HLProtocolSelected)}
 function $HLSourceCodeFocusRequested(){return globals.HLSourceCodeFocusRequested||(typeof HLSourceCodeFocusRequested=="undefined"?nil:HLSourceCodeFocusRequested)}
+function $HLShowTemplate(){return globals.HLShowTemplate||(typeof HLShowTemplate=="undefined"?nil:HLShowTemplate)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 $1=_st(self._browserModel())._announcer();
@@ -1615,12 +1490,14 @@ _st($1)._on_send_to_($HLPackageSelected(),"onPackageSelected:",self);
 $ctx1.sendIdx["on:send:to:"]=11;
 _st($1)._on_send_to_($HLProtocolSelected(),"onProtocolSelected:",self);
 $ctx1.sendIdx["on:send:to:"]=12;
-$2=_st($1)._on_send_to_($HLSourceCodeFocusRequested(),"onSourceCodeFocusRequested",self);
+_st($1)._on_send_to_($HLSourceCodeFocusRequested(),"onSourceCodeFocusRequested",self);
+$ctx1.sendIdx["on:send:to:"]=13;
+$2=_st($1)._on_send_to_($HLShowTemplate(),"onShowTemplate:",self);
 return self}, function($ctx1) {$ctx1.fill(self,"observeBrowserModel",{},globals.HLBrowserCodeWidget)})},
 args: [],
-source: "observeBrowserModel\x0a\x09self browserModel announcer\x0a\x09\x09on: HLSaveSourceCode\x0a\x09\x09send: #onSaveIt\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLShowInstanceToggled\x0a\x09\x09send: #onShowInstanceToggled\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLSourceCodeSaved\x0a\x09\x09send: #onSourceCodeSaved\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLAboutToChange\x0a\x09\x09send: #onBrowserAboutToChange:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLParseErrorRaised\x0a\x09\x09send: #onParseError:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLCompileErrorRaised\x0a\x09\x09send: #onCompileError:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLUnknownVariableErrorRaised\x0a\x09\x09send: #onUnknownVariableError:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLInstVarAdded \x0a\x09\x09send: #onInstVarAdded\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLMethodSelected \x0a\x09\x09send: #onMethodSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a    \x09on: HLClassSelected \x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLPackageSelected \x0a\x09\x09send: #onPackageSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a    \x09on: HLProtocolSelected \x0a\x09\x09send: #onProtocolSelected: \x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLSourceCodeFocusRequested \x0a\x09\x09send: #onSourceCodeFocusRequested\x0a\x09\x09to: self",
+source: "observeBrowserModel\x0a\x09self browserModel announcer\x0a\x09\x09on: HLSaveSourceCode\x0a\x09\x09send: #onSaveIt\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLShowInstanceToggled\x0a\x09\x09send: #onShowInstanceToggled\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLSourceCodeSaved\x0a\x09\x09send: #onSourceCodeSaved\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLAboutToChange\x0a\x09\x09send: #onBrowserAboutToChange:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLParseErrorRaised\x0a\x09\x09send: #onParseError:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLCompileErrorRaised\x0a\x09\x09send: #onCompileError:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLUnknownVariableErrorRaised\x0a\x09\x09send: #onUnknownVariableError:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLInstVarAdded \x0a\x09\x09send: #onInstVarAdded\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLMethodSelected \x0a\x09\x09send: #onMethodSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a    \x09on: HLClassSelected \x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLPackageSelected \x0a\x09\x09send: #onPackageSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a    \x09on: HLProtocolSelected \x0a\x09\x09send: #onProtocolSelected: \x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLSourceCodeFocusRequested \x0a\x09\x09send: #onSourceCodeFocusRequested\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLShowTemplate\x0a\x09\x09send: #onShowTemplate:\x0a\x09\x09to: self",
 messageSends: ["on:send:to:", "announcer", "browserModel"],
-referencedClasses: ["HLSaveSourceCode", "HLShowInstanceToggled", "HLSourceCodeSaved", "HLAboutToChange", "HLParseErrorRaised", "HLCompileErrorRaised", "HLUnknownVariableErrorRaised", "HLInstVarAdded", "HLMethodSelected", "HLClassSelected", "HLPackageSelected", "HLProtocolSelected", "HLSourceCodeFocusRequested"]
+referencedClasses: ["HLSaveSourceCode", "HLShowInstanceToggled", "HLSourceCodeSaved", "HLAboutToChange", "HLParseErrorRaised", "HLCompileErrorRaised", "HLUnknownVariableErrorRaised", "HLInstVarAdded", "HLMethodSelected", "HLClassSelected", "HLPackageSelected", "HLProtocolSelected", "HLSourceCodeFocusRequested", "HLShowTemplate"]
 }),
 globals.HLBrowserCodeWidget);
 
@@ -1948,6 +1825,22 @@ referencedClasses: []
 }),
 globals.HLBrowserCodeWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onShowTemplate:",
+protocol: 'reactions',
+fn: function (anAnnouncement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._contents_(_st(anAnnouncement)._template());
+return self}, function($ctx1) {$ctx1.fill(self,"onShowTemplate:",{anAnnouncement:anAnnouncement},globals.HLBrowserCodeWidget)})},
+args: ["anAnnouncement"],
+source: "onShowTemplate: anAnnouncement\x0a\x09self contents: anAnnouncement template",
+messageSends: ["contents:", "template"],
+referencedClasses: []
+}),
+globals.HLBrowserCodeWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "onSourceCodeFocusRequested",

+ 60 - 52
st/Helios-Workspace.st → js/Helios-Workspace.st

@@ -82,7 +82,7 @@ currentLineOrSelection
 
 editorOptions
 	^ #{
-		'theme' -> 'default'.
+		'theme' -> ('helios.codeMirrorTheme' settingValueIfAbsent: 'default helios').
 		'mode' -> 'text/x-stsrc'.
         'lineNumbers' -> true.
         'enterMode' -> 'flat'.
@@ -91,7 +91,7 @@ editorOptions
         'matchBrackets' -> true.
         'electricChars' -> false.
 		'keyMap' -> 'Amber'.
-		'extraKeys' -> #{'Shift-Space' -> 'autocomplete'}
+		'extraKeys' -> (HashedCollection with: ('helios.completionKey' settingValueIfAbsent: 'Shift-Space') -> 'autocomplete')
 	}
 !
 
@@ -316,63 +316,63 @@ keyMap
 
 macKeyMap
 	^ #{
-		'Alt-Backspace'		-> 'delWordBefore'.
-		'Alt-Delete'		-> 'delWordAfter'. 
-		'Alt-Left'		-> 'goWordBoundaryLeft'.
-		'Alt-Right'		-> 'goWordBoundaryRight'. 
-		'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'.
+		'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' }
+		'Shift-Cmd-Alt-F'		-> 'replaceAll'.
+		'Shift-Cmd-G'			-> 'findPrev'. 
+		'Shift-Cmd-Z'			-> 'redo'. 
+    	'fallthrough' 			-> { 'basic'. 'emacsy' }
   }
 !
 
 pcKeyMap
 	^ #{
-		'Alt-Left' -> 'goLineStart'. 
-		'Alt-Right' -> 'goLineEnd'.
-		'Alt-Up' -> 'goDocStart'. 
-		'Ctrl-A' -> 'selectAll'. 
+		'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' -> 'goWordBoundaryLeft'. 
-		'Ctrl-P' -> 'printIt'.
-		'Ctrl-Right' -> 'goWordBoundaryRight'. 
-		'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')
+		'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')
 }
 ! !
 
@@ -561,6 +561,10 @@ observeBrowserModel
 		
 		on: HLSourceCodeFocusRequested 
 		send: #onSourceCodeFocusRequested
+		to: self;
+		
+		on: HLShowTemplate
+		send: #onShowTemplate:
 		to: self
 !
 
@@ -699,6 +703,10 @@ onShowInstanceToggled
 	self contents: self browserModel selectedClass definition
 !
 
+onShowTemplate: anAnnouncement
+	self contents: anAnnouncement template
+!
+
 onSourceCodeFocusRequested
 	self focus
 !

+ 87 - 99
js/IDE.js

@@ -784,7 +784,7 @@ var self=this;
 var start,stop,currentLine;
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$4,$3,$5,$6,$7,$8,$10,$9,$11,$12,$13,$15,$14;
+var $1,$2,$4,$3,$5,$6,$7,$8,$9,$10,$12,$11;
 $1=_st(self["@editor"])._getCursor_(false);
 $ctx1.sendIdx["getCursor:"]=1;
 currentLine=_st($1)._line();
@@ -807,32 +807,28 @@ $7=_st(_st(self["@editor"])._getLine_(currentLine))._size();
 $ctx2.sendIdx["size"]=1;
 _st($6)._at_put_("ch",$7);
 $ctx2.sendIdx["at:put:"]=3;
-$8=self["@editor"];
-$10="line".__minus_gt(currentLine);
-$ctx2.sendIdx["->"]=1;
-$9=globals.HashedCollection._from_([$10,"ch".__minus_gt((0))]);
-return _st($8)._setSelection_end_($9,start);
+return _st(self["@editor"])._setSelection_end_(globals.HashedCollection._newFromPairs_(["line",currentLine,"ch",(0)]),start);
 $ctx2.sendIdx["setSelection:end:"]=1;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 stop=_st($HashedCollection())._new();
 _st(stop)._at_put_("line",currentLine);
 $ctx1.sendIdx["at:put:"]=4;
-$11=stop;
-$12=_st(_st(_st(start)._at_("ch")).__plus(_st(aString)._size())).__plus((2));
+$8=stop;
+$9=_st(_st(_st(start)._at_("ch")).__plus(_st(aString)._size())).__plus((2));
 $ctx1.sendIdx["+"]=1;
-_st($11)._at_put_("ch",$12);
-$13=self["@editor"];
-$15=_st(_st(_st(self["@editor"])._getSelection()).__comma(" ")).__comma(aString);
+_st($8)._at_put_("ch",$9);
+$10=self["@editor"];
+$12=_st(_st(_st(self["@editor"])._getSelection()).__comma(" ")).__comma(aString);
 $ctx1.sendIdx[","]=2;
-$14=_st($15).__comma(" ");
+$11=_st($12).__comma(" ");
 $ctx1.sendIdx[","]=1;
-_st($13)._replaceSelection_($14);
+_st($10)._replaceSelection_($11);
 _st(self["@editor"])._setCursor_(_st(self["@editor"])._getCursor_(true));
 _st(self["@editor"])._setSelection_end_(stop,start);
 return self}, function($ctx1) {$ctx1.fill(self,"print:",{aString:aString,start:start,stop:stop,currentLine:currentLine},globals.SourceArea)})},
 args: ["aString"],
 source: "print: aString\x0a\x09| start stop currentLine |\x0a\x09currentLine := (editor getCursor: false) line.\x0a\x09start := HashedCollection new.\x0a\x09start at: 'line' put: currentLine.\x0a\x09start at: 'ch' put: (editor getCursor: false) ch.\x0a\x09(editor getSelection) ifEmpty: [\x0a\x09\x09\x22select current line if selection is empty\x22\x0a\x09\x09start at: 'ch' put: (editor getLine: currentLine) size.\x0a\x09\x09editor setSelection: #{'line' -> currentLine. 'ch' -> 0} end: start.\x0a\x09].\x0a\x09stop := HashedCollection new.\x0a\x09stop at: 'line' put: currentLine.\x0a\x09stop at: 'ch' put: ((start at: 'ch') + aString size + 2).\x0a\x0a\x09editor replaceSelection: (editor getSelection, ' ', aString, ' ').\x0a\x09editor setCursor: (editor getCursor: true).\x0a\x09editor setSelection: stop end: start",
-messageSends: ["line", "getCursor:", "new", "at:put:", "ch", "ifEmpty:", "getSelection", "size", "getLine:", "setSelection:end:", "->", "+", "at:", "replaceSelection:", ",", "setCursor:"],
+messageSends: ["line", "getCursor:", "new", "at:put:", "ch", "ifEmpty:", "getSelection", "size", "getLine:", "setSelection:end:", "+", "at:", "replaceSelection:", ",", "setCursor:"],
 referencedClasses: ["HashedCollection"]
 }),
 globals.SourceArea);
@@ -946,7 +942,7 @@ fn: function (aTextarea){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 self['@editor'] = CodeMirror.fromTextArea(aTextarea, {
-		theme: 'default',
+		theme: 'ide.codeMirrorTheme'._settingValueIfAbsent_('default'),
 		mode: 'text/x-stsrc',
 		lineNumbers: true,
 		enterMode: 'flat',
@@ -957,7 +953,7 @@ self['@editor'] = CodeMirror.fromTextArea(aTextarea, {
 	});
 return self}, function($ctx1) {$ctx1.fill(self,"setEditorOn:",{aTextarea:aTextarea},globals.SourceArea)})},
 args: ["aTextarea"],
-source: "setEditorOn: aTextarea\x0a\x09<self['@editor'] = CodeMirror.fromTextArea(aTextarea, {\x0a\x09\x09theme: 'default',\x0a\x09\x09mode: 'text/x-stsrc',\x0a\x09\x09lineNumbers: true,\x0a\x09\x09enterMode: 'flat',\x0a\x09\x09indentWithTabs: true,\x0a\x09\x09indentUnit: 4,\x0a\x09\x09matchBrackets: true,\x0a\x09\x09electricChars: false\x0a\x09})>",
+source: "setEditorOn: aTextarea\x0a\x09<self['@editor'] = CodeMirror.fromTextArea(aTextarea, {\x0a\x09\x09theme: 'ide.codeMirrorTheme'._settingValueIfAbsent_('default'),\x0a\x09\x09mode: 'text/x-stsrc',\x0a\x09\x09lineNumbers: true,\x0a\x09\x09enterMode: 'flat',\x0a\x09\x09indentWithTabs: true,\x0a\x09\x09indentUnit: 4,\x0a\x09\x09matchBrackets: true,\x0a\x09\x09electricChars: false\x0a\x09})>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1214,18 +1210,11 @@ protocol: 'actions',
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$2;
-$1="#amber"._asJQuery();
-$3="handles".__minus_gt("n");
-$ctx1.sendIdx["->"]=1;
-$4="resize".__minus_gt(aBlock);
-$ctx1.sendIdx["->"]=2;
-$2=globals.HashedCollection._from_([$3,$4,"minHeight".__minus_gt((230))]);
-_st($1)._resizable_($2);
+_st("#amber"._asJQuery())._resizable_(globals.HashedCollection._newFromPairs_(["handles","n","resize",aBlock,"minHeight",(230)]));
 return self}, function($ctx1) {$ctx1.fill(self,"onResize:",{aBlock:aBlock},globals.TabManager)})},
 args: ["aBlock"],
 source: "onResize: aBlock\x0a\x09'#amber' asJQuery resizable: #{\x0a\x09\x09'handles' -> 'n'.\x0a\x09\x09'resize' -> aBlock.\x0a\x09\x09'minHeight' -> 230\x0a\x09}",
-messageSends: ["resizable:", "asJQuery", "->"],
+messageSends: ["resizable:", "asJQuery"],
 referencedClasses: []
 }),
 globals.TabManager);
@@ -4538,8 +4527,7 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 _st(self["@inspector"])._contents_((function(html){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({html:html},$ctx1,1)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"updateInspector",{},globals.Debugger)})},
 args: [],
 source: "updateInspector\x0a\x09inspector contents: [ :html | ]",
@@ -7254,28 +7242,21 @@ var $1;
 variables=_st($Dictionary())._new();
 _st(variables)._at_put_("#self",self);
 $ctx1.sendIdx["at:put:"]=1;
-_st(variables)._at_put_("#year",self._year());
+_st(variables)._at_put_("#keys",self._keys());
 $ctx1.sendIdx["at:put:"]=2;
-_st(variables)._at_put_("#month",self._month());
-$ctx1.sendIdx["at:put:"]=3;
-_st(variables)._at_put_("#day",self._day());
-$ctx1.sendIdx["at:put:"]=4;
-_st(variables)._at_put_("#hours",self._hours());
-$ctx1.sendIdx["at:put:"]=5;
-_st(variables)._at_put_("#minutes",self._minutes());
-$ctx1.sendIdx["at:put:"]=6;
-_st(variables)._at_put_("#seconds",self._seconds());
-$ctx1.sendIdx["at:put:"]=7;
-_st(variables)._at_put_("#milliseconds",self._milliseconds());
+self._keysAndValuesDo_((function(key,value){
+return smalltalk.withContext(function($ctx2) {
+return _st(variables)._at_put_(key,value);
+}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,1)})}));
 _st(anInspector)._setLabel_(self._printString());
 $1=_st(anInspector)._setVariables_(variables);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},globals.Date)})},
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},globals.AssociativeCollection)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#year' put: self year.\x0a\x09variables at: '#month' put: self month.\x0a\x09variables at: '#day' put: self day.\x0a\x09variables at: '#hours' put: self hours.\x0a\x09variables at: '#minutes' put: self minutes.\x0a\x09variables at: '#seconds' put: self seconds.\x0a\x09variables at: '#milliseconds' put: self milliseconds.\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-messageSends: ["new", "at:put:", "year", "month", "day", "hours", "minutes", "seconds", "milliseconds", "setLabel:", "printString", "setVariables:"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#keys' put: self keys.\x0a\x09self keysAndValuesDo: [ :key :value |\x0a\x09\x09variables at: key put: value ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+messageSends: ["new", "at:put:", "keys", "keysAndValuesDo:", "setLabel:", "printString", "setVariables:"],
 referencedClasses: ["Dictionary"]
 }),
-globals.Date);
+globals.AssociativeCollection);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -7310,32 +7291,35 @@ selector: "inspectOn:",
 protocol: '*IDE',
 fn: function (anInspector){
 var self=this;
-var label;
+var variables;
+function $Dictionary(){return globals.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1,$5,$4;
-globals.String.superclass.fn.prototype._inspectOn_.apply(_st(self), [anInspector]);
-$3=self._printString();
-$ctx1.sendIdx["printString"]=1;
-$2=_st($3)._size();
-$1=_st($2).__gt((30));
-if(smalltalk.assert($1)){
-$5=self._printString();
-$ctx1.sendIdx["printString"]=2;
-$4=_st($5)._copyFrom_to_((1),(30));
-label=_st($4).__comma("...'");
-label;
-} else {
-label=self._printString();
-label;
-};
-_st(anInspector)._setLabel_(label);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,label:label},globals.String)})},
+var $1;
+variables=_st($Dictionary())._new();
+_st(variables)._at_put_("#self",self);
+$ctx1.sendIdx["at:put:"]=1;
+_st(variables)._at_put_("#year",self._year());
+$ctx1.sendIdx["at:put:"]=2;
+_st(variables)._at_put_("#month",self._month());
+$ctx1.sendIdx["at:put:"]=3;
+_st(variables)._at_put_("#day",self._day());
+$ctx1.sendIdx["at:put:"]=4;
+_st(variables)._at_put_("#hours",self._hours());
+$ctx1.sendIdx["at:put:"]=5;
+_st(variables)._at_put_("#minutes",self._minutes());
+$ctx1.sendIdx["at:put:"]=6;
+_st(variables)._at_put_("#seconds",self._seconds());
+$ctx1.sendIdx["at:put:"]=7;
+_st(variables)._at_put_("#milliseconds",self._milliseconds());
+_st(anInspector)._setLabel_(self._printString());
+$1=_st(anInspector)._setVariables_(variables);
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},globals.Date)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| label |\x0a\x09super inspectOn: anInspector.\x0a\x09self printString size > 30\x0a\x09\x09ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]\x0a\x09\x09ifFalse: [ label := self printString ].\x0a\x09anInspector setLabel: label",
-messageSends: ["inspectOn:", "ifTrue:ifFalse:", ">", "size", "printString", ",", "copyFrom:to:", "setLabel:"],
-referencedClasses: []
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#year' put: self year.\x0a\x09variables at: '#month' put: self month.\x0a\x09variables at: '#day' put: self day.\x0a\x09variables at: '#hours' put: self hours.\x0a\x09variables at: '#minutes' put: self minutes.\x0a\x09variables at: '#seconds' put: self seconds.\x0a\x09variables at: '#milliseconds' put: self milliseconds.\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+messageSends: ["new", "at:put:", "year", "month", "day", "hours", "minutes", "seconds", "milliseconds", "setLabel:", "printString", "setVariables:"],
+referencedClasses: ["Dictionary"]
 }),
-globals.String);
+globals.Date);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -7350,21 +7334,27 @@ var $1;
 variables=_st($Dictionary())._new();
 _st(variables)._at_put_("#self",self);
 $ctx1.sendIdx["at:put:"]=1;
-_st(variables)._at_put_("#keys",self._keys());
+_st(variables)._at_put_("#home",self._home());
 $ctx1.sendIdx["at:put:"]=2;
-self._keysAndValuesDo_((function(key,value){
+_st(variables)._at_put_("#receiver",self._receiver());
+$ctx1.sendIdx["at:put:"]=3;
+_st(variables)._at_put_("#selector",self._selector());
+$ctx1.sendIdx["at:put:"]=4;
+_st(variables)._at_put_("#locals",self._locals());
+$ctx1.sendIdx["at:put:"]=5;
+_st(_st(self._class())._instanceVariableNames())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-return _st(variables)._at_put_(key,value);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,1)})}));
+return _st(variables)._at_put_(each,self._instVarAt_(each));
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 _st(anInspector)._setLabel_(self._printString());
 $1=_st(anInspector)._setVariables_(variables);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},globals.AssociativeCollection)})},
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},globals.MethodContext)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#keys' put: self keys.\x0a\x09self keysAndValuesDo: [ :key :value |\x0a\x09\x09variables at: key put: value ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-messageSends: ["new", "at:put:", "keys", "keysAndValuesDo:", "setLabel:", "printString", "setVariables:"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#home' put: self home.\x0a\x09variables at: '#receiver' put: self receiver.\x0a\x09variables at: '#selector' put: self selector.\x0a\x09variables at: '#locals' put: self locals.\x0a\x09self class instanceVariableNames do: [ :each |\x0a\x09\x09variables at: each put: (self instVarAt: each) ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+messageSends: ["new", "at:put:", "home", "receiver", "selector", "locals", "do:", "instanceVariableNames", "class", "instVarAt:", "setLabel:", "printString", "setVariables:"],
 referencedClasses: ["Dictionary"]
 }),
-globals.AssociativeCollection);
+globals.MethodContext);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -7402,33 +7392,31 @@ selector: "inspectOn:",
 protocol: '*IDE',
 fn: function (anInspector){
 var self=this;
-var variables;
-function $Dictionary(){return globals.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
+var label;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-variables=_st($Dictionary())._new();
-_st(variables)._at_put_("#self",self);
-$ctx1.sendIdx["at:put:"]=1;
-_st(variables)._at_put_("#home",self._home());
-$ctx1.sendIdx["at:put:"]=2;
-_st(variables)._at_put_("#receiver",self._receiver());
-$ctx1.sendIdx["at:put:"]=3;
-_st(variables)._at_put_("#selector",self._selector());
-$ctx1.sendIdx["at:put:"]=4;
-_st(variables)._at_put_("#locals",self._locals());
-$ctx1.sendIdx["at:put:"]=5;
-_st(_st(self._class())._instanceVariableNames())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(variables)._at_put_(each,self._instVarAt_(each));
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
-_st(anInspector)._setLabel_(self._printString());
-$1=_st(anInspector)._setVariables_(variables);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},globals.MethodContext)})},
+var $3,$2,$1,$5,$4;
+globals.String.superclass.fn.prototype._inspectOn_.apply(_st(self), [anInspector]);
+$3=self._printString();
+$ctx1.sendIdx["printString"]=1;
+$2=_st($3)._size();
+$1=_st($2).__gt((30));
+if(smalltalk.assert($1)){
+$5=self._printString();
+$ctx1.sendIdx["printString"]=2;
+$4=_st($5)._copyFrom_to_((1),(30));
+label=_st($4).__comma("...'");
+label;
+} else {
+label=self._printString();
+label;
+};
+_st(anInspector)._setLabel_(label);
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,label:label},globals.String)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#home' put: self home.\x0a\x09variables at: '#receiver' put: self receiver.\x0a\x09variables at: '#selector' put: self selector.\x0a\x09variables at: '#locals' put: self locals.\x0a\x09self class instanceVariableNames do: [ :each |\x0a\x09\x09variables at: each put: (self instVarAt: each) ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-messageSends: ["new", "at:put:", "home", "receiver", "selector", "locals", "do:", "instanceVariableNames", "class", "instVarAt:", "setLabel:", "printString", "setVariables:"],
-referencedClasses: ["Dictionary"]
+source: "inspectOn: anInspector\x0a\x09| label |\x0a\x09super inspectOn: anInspector.\x0a\x09self printString size > 30\x0a\x09\x09ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]\x0a\x09\x09ifFalse: [ label := self printString ].\x0a\x09anInspector setLabel: label",
+messageSends: ["inspectOn:", "ifTrue:ifFalse:", ">", "size", "printString", ",", "copyFrom:to:", "setLabel:"],
+referencedClasses: []
 }),
-globals.MethodContext);
+globals.String);
 
 });

+ 33 - 33
st/IDE.st → js/IDE.st

@@ -210,7 +210,7 @@ selection
 
 setEditorOn: aTextarea
 	<self['@editor'] = CodeMirror.fromTextArea(aTextarea, {
-		theme: 'default',
+		theme: 'ide.codeMirrorTheme'._settingValueIfAbsent_('default'),
 		mode: 'text/x-stsrc',
 		lineNumbers: true,
 		enterMode: 'flat',
@@ -2301,19 +2301,15 @@ renderButtonsOn: html
 	onClick: [ self clearWorkspace ]
 ! !
 
-!Date methodsFor: '*IDE'!
+!AssociativeCollection methodsFor: '*IDE'!
 
 inspectOn: anInspector
 	| variables |
 	variables := Dictionary new.
 	variables at: '#self' put: self.
-	variables at: '#year' put: self year.
-	variables at: '#month' put: self month.
-	variables at: '#day' put: self day.
-	variables at: '#hours' put: self hours.
-	variables at: '#minutes' put: self minutes.
-	variables at: '#seconds' put: self seconds.
-	variables at: '#milliseconds' put: self milliseconds.
+	variables at: '#keys' put: self keys.
+	self keysAndValuesDo: [ :key :value |
+		variables at: key put: value ].
 	anInspector
 		setLabel: self printString;
 		setVariables: variables
@@ -2332,26 +2328,36 @@ inspectOn: anInspector
 		setVariables: variables
 ! !
 
-!String methodsFor: '*IDE'!
+!Date methodsFor: '*IDE'!
 
 inspectOn: anInspector
-	| label |
-	super inspectOn: anInspector.
-	self printString size > 30
-		ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]
-		ifFalse: [ label := self printString ].
-	anInspector setLabel: label
+	| variables |
+	variables := Dictionary new.
+	variables at: '#self' put: self.
+	variables at: '#year' put: self year.
+	variables at: '#month' put: self month.
+	variables at: '#day' put: self day.
+	variables at: '#hours' put: self hours.
+	variables at: '#minutes' put: self minutes.
+	variables at: '#seconds' put: self seconds.
+	variables at: '#milliseconds' put: self milliseconds.
+	anInspector
+		setLabel: self printString;
+		setVariables: variables
 ! !
 
-!AssociativeCollection methodsFor: '*IDE'!
+!MethodContext methodsFor: '*IDE'!
 
 inspectOn: anInspector
 	| variables |
 	variables := Dictionary new.
 	variables at: '#self' put: self.
-	variables at: '#keys' put: self keys.
-	self keysAndValuesDo: [ :key :value |
-		variables at: key put: value ].
+	variables at: '#home' put: self home.
+	variables at: '#receiver' put: self receiver.
+	variables at: '#selector' put: self selector.
+	variables at: '#locals' put: self locals.
+	self class instanceVariableNames do: [ :each |
+		variables at: each put: (self instVarAt: each) ].
 	anInspector
 		setLabel: self printString;
 		setVariables: variables
@@ -2372,20 +2378,14 @@ inspectOn: anInspector
 		setVariables: variables
 ! !
 
-!MethodContext methodsFor: '*IDE'!
+!String methodsFor: '*IDE'!
 
 inspectOn: anInspector
-	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self.
-	variables at: '#home' put: self home.
-	variables at: '#receiver' put: self receiver.
-	variables at: '#selector' put: self selector.
-	variables at: '#locals' put: self locals.
-	self class instanceVariableNames do: [ :each |
-		variables at: each put: (self instVarAt: each) ].
-	anInspector
-		setLabel: self printString;
-		setVariables: variables
+	| label |
+	super inspectOn: anInspector.
+	self printString size > 30
+		ifTrue: [ label := (self printString copyFrom: 1 to: 30), '...''' ]
+		ifFalse: [ label := self printString ].
+	anInspector setLabel: label
 ! !
 

+ 0 - 0
st/Kernel-Announcements.st → js/Kernel-Announcements.st


+ 70 - 2
js/Kernel-Classes.js

@@ -35,9 +35,8 @@ function $SystemAnnouncer(){return globals.SystemAnnouncer||(typeof SystemAnnoun
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1,$4,$5,$6,$7,$8,$9,$10,$11;
 oldMethod=_st(self._methodDictionary())._at_ifAbsent_(_st(aMethod)._selector(),(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $2=self._protocols();
 $3=_st(aMethod)._protocol();
 $ctx1.sendIdx["protocol"]=1;
@@ -638,6 +637,57 @@ referencedClasses: []
 }),
 globals.Behavior);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "methodTemplate",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $String(){return globals.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $3,$4,$2,$7,$8,$6,$9,$5,$10,$1;
+$1=_st($String())._streamContents_((function(stream){
+return smalltalk.withContext(function($ctx2) {
+_st(stream)._nextPutAll_("messageSelectorAndArgumentNames");
+$ctx2.sendIdx["nextPutAll:"]=1;
+$3=_st($String())._lf();
+$ctx2.sendIdx["lf"]=1;
+$4=_st($String())._tab();
+$ctx2.sendIdx["tab"]=1;
+$2=_st($3).__comma($4);
+$ctx2.sendIdx[","]=1;
+_st(stream)._nextPutAll_($2);
+$ctx2.sendIdx["nextPutAll:"]=2;
+_st(stream)._nextPutAll_("\x22comment stating purpose of message\x22");
+$ctx2.sendIdx["nextPutAll:"]=3;
+$7=_st($String())._lf();
+$ctx2.sendIdx["lf"]=2;
+$8=_st($String())._lf();
+$ctx2.sendIdx["lf"]=3;
+$6=_st($7).__comma($8);
+$ctx2.sendIdx[","]=3;
+$9=_st($String())._tab();
+$ctx2.sendIdx["tab"]=2;
+$5=_st($6).__comma($9);
+$ctx2.sendIdx[","]=2;
+_st(stream)._nextPutAll_($5);
+$ctx2.sendIdx["nextPutAll:"]=4;
+_st(stream)._nextPutAll_("| temporary variable names |");
+$ctx2.sendIdx["nextPutAll:"]=5;
+_st(stream)._nextPutAll_(_st(_st($String())._lf()).__comma(_st($String())._tab()));
+$ctx2.sendIdx["nextPutAll:"]=6;
+$10=_st(stream)._nextPutAll_("statements");
+return $10;
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"methodTemplate",{},globals.Behavior)})},
+args: [],
+source: "methodTemplate\x0a\x09^ String streamContents: [ :stream |\x0a\x09\x09stream \x0a\x09\x09\x09nextPutAll: 'messageSelectorAndArgumentNames';\x0a\x09\x09\x09nextPutAll: String lf, String tab;\x0a\x09\x09\x09nextPutAll: '\x22comment stating purpose of message\x22';\x0a\x09\x09\x09nextPutAll: String lf, String lf, String tab;\x0a\x09\x09\x09nextPutAll: '| temporary variable names |';\x0a\x09\x09\x09nextPutAll: String lf, String tab;\x0a\x09\x09\x09nextPutAll: 'statements' ]",
+messageSends: ["streamContents:", "nextPutAll:", ",", "lf", "tab"],
+referencedClasses: ["String"]
+}),
+globals.Behavior);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "methods",
@@ -1454,6 +1504,24 @@ referencedClasses: []
 }),
 globals.Metaclass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "package",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._instanceClass())._package();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"package",{},globals.Metaclass)})},
+args: [],
+source: "package\x0a\x09^ self instanceClass package",
+messageSends: ["package", "instanceClass"],
+referencedClasses: []
+}),
+globals.Metaclass);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "printOn:",

+ 16 - 0
st/Kernel-Classes.st → js/Kernel-Classes.st

@@ -129,6 +129,18 @@ methodDictionary
 	return dict>
 !
 
+methodTemplate
+	^ String streamContents: [ :stream |
+		stream 
+			nextPutAll: 'messageSelectorAndArgumentNames';
+			nextPutAll: String lf, String tab;
+			nextPutAll: '"comment stating purpose of message"';
+			nextPutAll: String lf, String lf, String tab;
+			nextPutAll: '| temporary variable names |';
+			nextPutAll: String lf, String tab;
+			nextPutAll: 'statements' ]
+!
+
 methods
 	^ self methodDictionary values
 !
@@ -471,6 +483,10 @@ instanceVariableNames: aCollection
 		class: self instanceVariableNames: aCollection
 !
 
+package
+	^ self instanceClass package
+!
+
 subclasses
 	^ (self instanceClass subclasses 
 		select: [ :each | each isMetaclass not ])

+ 15 - 21
js/Kernel-Collections.js

@@ -400,9 +400,8 @@ return smalltalk.withContext(function($ctx2) {
 return self._error_("Collection is empty");
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 self._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
 throw $early=[each];
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
+}));
 return self}
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"anyOne",{},globals.Collection)})},
@@ -686,10 +685,9 @@ var self=this;
 var actionBeforeElement;
 return smalltalk.withContext(function($ctx1) { 
 actionBeforeElement=(function(){
-return smalltalk.withContext(function($ctx2) {
 actionBeforeElement=anotherBlock;
 return actionBeforeElement;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})});
+});
 self._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
 _st(actionBeforeElement)._value();
@@ -729,9 +727,8 @@ return smalltalk.withContext(function($ctx1) {
 var $2,$1;
 $2=self._isEmpty();
 $1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
-return smalltalk.withContext(function($ctx2) {
 return self;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifEmpty:",{aBlock:aBlock},globals.Collection)})},
 args: ["aBlock"],
@@ -770,9 +767,8 @@ return smalltalk.withContext(function($ctx1) {
 var $2,$1;
 $2=self._notEmpty();
 $1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
-return smalltalk.withContext(function($ctx2) {
 return self;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:",{aBlock:aBlock},globals.Collection)})},
 args: ["aBlock"],
@@ -1331,9 +1327,8 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=self._at_ifPresent_ifAbsent_(anIndex,aBlock,(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"at:ifPresent:",{anIndex:anIndex,aBlock:aBlock},globals.IndexableCollection)})},
 args: ["anIndex", "aBlock"],
@@ -2245,9 +2240,8 @@ var index;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 index=_st(self["@values"])._indexOf_ifAbsent_(anObject,(function(){
-return smalltalk.withContext(function($ctx2) {
 return (0);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $2=_st(index).__eq((0));
 if(smalltalk.assert($2)){
 $1=_st(aBlock)._value();
@@ -2920,9 +2914,8 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=_st(self._indexOf_ifAbsent_(anObject,(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})))._notNil();
+})))._notNil();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"includes:",{anObject:anObject},globals.SequenceableCollection)})},
 args: ["anObject"],
@@ -2963,9 +2956,8 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=self._indexOf_startingAt_ifAbsent_(anObject,start,(function(){
-return smalltalk.withContext(function($ctx2) {
 return (0);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"indexOf:startingAt:",{anObject:anObject,start:start},globals.SequenceableCollection)})},
 args: ["anObject", "start"],
@@ -3522,9 +3514,8 @@ var index;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 index=self._indexOf_ifAbsent_(anObject,(function(){
-return smalltalk.withContext(function($ctx2) {
 return (0);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $2=_st(index).__eq((0));
 if(smalltalk.assert($2)){
 $1=_st(aBlock)._value();
@@ -3669,12 +3660,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=self._basicPerform_("sort");
+$1=self._sort_((function(a,b){
+return smalltalk.withContext(function($ctx2) {
+return _st(a).__lt(b);
+}, function($ctx2) {$ctx2.fillBlock({a:a,b:b},$ctx1,1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"sort",{},globals.Array)})},
 args: [],
-source: "sort\x0a\x09^ self basicPerform: 'sort'",
-messageSends: ["basicPerform:"],
+source: "sort\x0a\x09^ self sort: [ :a :b | a < b ]",
+messageSends: ["sort:", "<"],
 referencedClasses: []
 }),
 globals.Array);

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

@@ -1273,7 +1273,7 @@ select: aBlock
 !
 
 sort
-	^ self basicPerform: 'sort'
+	^ self sort: [ :a :b | a < b ]
 !
 
 sort: aBlock

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


+ 45 - 37
js/Kernel-ImportExport.js

@@ -104,26 +104,33 @@ function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedC
 function $Smalltalk(){return globals.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
 function $ExportMethodProtocol(){return globals.ExportMethodProtocol||(typeof ExportMethodProtocol=="undefined"?nil:ExportMethodProtocol)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-extensionName="*".__comma(_st(aPackage)._name());
+var $1,$2,$3,$4;
+$1=_st(aPackage)._name();
+$ctx1.sendIdx["name"]=1;
+extensionName="*".__comma($1);
 result=_st($OrderedCollection())._new();
-_st(_st($Smalltalk())._classes())._do_((function(each){
+_st(_st(_st(_st($Smalltalk())._classes())._asArray())._sorted_((function(a,b){
+return smalltalk.withContext(function($ctx2) {
+$2=_st(a)._name();
+$ctx2.sendIdx["name"]=2;
+return _st($2).__lt(_st(b)._name());
+}, function($ctx2) {$ctx2.fillBlock({a:a,b:b},$ctx1,1)})})))._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st([each,_st(each)._class()])._do_((function(behavior){
 return smalltalk.withContext(function($ctx3) {
-$1=_st(_st(behavior)._protocols())._includes_(extensionName);
-if(smalltalk.assert($1)){
+$3=_st(_st(behavior)._protocols())._includes_(extensionName);
+if(smalltalk.assert($3)){
 return _st(result)._add_(_st($ExportMethodProtocol())._name_theClass_(extensionName,behavior));
 };
-}, function($ctx3) {$ctx3.fillBlock({behavior:behavior},$ctx2,2)})}));
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+}, function($ctx3) {$ctx3.fillBlock({behavior:behavior},$ctx2,3)})}));
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
 $ctx1.sendIdx["do:"]=1;
-$2=result;
-return $2;
+$4=result;
+return $4;
 }, function($ctx1) {$ctx1.fill(self,"extensionProtocolsOfPackage:",{aPackage:aPackage,extensionName:extensionName,result:result},globals.AbstractExporter)})},
 args: ["aPackage"],
-source: "extensionProtocolsOfPackage: aPackage\x0a\x09| extensionName result |\x0a\x09\x0a\x09extensionName := '*', aPackage name.\x0a\x09result := OrderedCollection new.\x0a\x09\x0a\x09\x22The classes must be loaded since it is extensions only.\x0a\x09Therefore sorting (dependency resolution) does not matter here.\x0a\x09Not sorting improves the speed by a number of magnitude.\x22\x0a\x09\x0a\x09Smalltalk classes do: [ :each |\x0a\x09\x09{each. each class} do: [ :behavior |\x0a\x09\x09\x09(behavior protocols includes: extensionName) ifTrue: [\x0a\x09\x09\x09\x09result add: (ExportMethodProtocol name: extensionName theClass: behavior) ] ] ].\x0a\x0a\x09^ result",
-messageSends: [",", "name", "new", "do:", "classes", "class", "ifTrue:", "includes:", "protocols", "add:", "name:theClass:"],
+source: "extensionProtocolsOfPackage: aPackage\x0a\x09| extensionName result |\x0a\x09\x0a\x09extensionName := '*', aPackage name.\x0a\x09result := OrderedCollection new.\x0a\x09\x0a\x09\x22The classes must be loaded since it is extensions only.\x0a\x09Therefore topological sorting (dependency resolution) does not matter here.\x0a\x09Not sorting topologically improves the speed by a number of magnitude.\x0a\x09\x0a\x09Not to shuffle diffs, classes are sorted by their name.\x22\x0a\x09\x0a\x09(Smalltalk classes asArray sorted: [ :a :b | a name < b name ]) do: [ :each |\x0a\x09\x09{each. each class} do: [ :behavior |\x0a\x09\x09\x09(behavior protocols includes: extensionName) ifTrue: [\x0a\x09\x09\x09\x09result add: (ExportMethodProtocol name: extensionName theClass: behavior) ] ] ].\x0a\x0a\x09^ result",
+messageSends: [",", "name", "new", "do:", "sorted:", "asArray", "classes", "<", "class", "ifTrue:", "includes:", "protocols", "add:", "name:theClass:"],
 referencedClasses: ["OrderedCollection", "Smalltalk", "ExportMethodProtocol"]
 }),
 globals.AbstractExporter);
@@ -1424,30 +1431,21 @@ protocol: 'private',
 fn: function (aURL,aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$5,$8,$7,$6,$1;
-$2="url".__minus_gt(aURL);
-$ctx1.sendIdx["->"]=1;
-$3="type".__minus_gt("PUT");
-$ctx1.sendIdx["->"]=2;
-$4="data".__minus_gt(aString);
-$ctx1.sendIdx["->"]=3;
-$5="contentType".__minus_gt("text/plain;charset=UTF-8");
-$ctx1.sendIdx["->"]=4;
-$1=globals.HashedCollection._from_([$2,$3,$4,$5,"error".__minus_gt((function(xhr){
+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) {
-$8=_st("Commiting ".__comma(aURL)).__comma(" failed with reason: \x22");
+$3=_st("Commiting ".__comma(aURL)).__comma(" failed with reason: \x22");
 $ctx2.sendIdx[","]=3;
-$7=_st($8).__comma(_st(xhr)._responseText());
+$2=_st($3).__comma(_st(xhr)._responseText());
 $ctx2.sendIdx[","]=2;
-$6=_st($7).__comma("\x22");
+$1=_st($2).__comma("\x22");
 $ctx2.sendIdx[","]=1;
-return self._alert_($6);
-}, function($ctx2) {$ctx2.fillBlock({xhr:xhr},$ctx1,1)})}))]);
-self._ajax_($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"],
+messageSends: ["ajax:", "alert:", ",", "responseText"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1707,14 +1705,24 @@ selector: "commitPathStFor:",
 protocol: 'accessing',
 fn: function (aPackage){
 var self=this;
+var path,pathWithout;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self._toUrl_(_st(self._namespaceFor_(aPackage)).__comma("/_source"));
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"commitPathStFor:",{aPackage:aPackage},globals.AmdPackageHandler)})},
+var $1,$3,$2;
+$1=_st(self._namespaceFor_(aPackage)).__comma("/_source");
+$ctx1.sendIdx[","]=1;
+path=self._toUrl_($1);
+pathWithout=self._commitPathJsFor_(aPackage);
+$3=_st(path).__eq(_st(pathWithout).__comma("/_source"));
+if(smalltalk.assert($3)){
+$2=pathWithout;
+} else {
+$2=path;
+};
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"commitPathStFor:",{aPackage:aPackage,path:path,pathWithout:pathWithout},globals.AmdPackageHandler)})},
 args: ["aPackage"],
-source: "commitPathStFor: aPackage\x0a\x09\x22if _source is not mapped, .st commit will likely fail\x22\x0a\x09^ self toUrl: (self namespaceFor: aPackage), '/_source'.",
-messageSends: ["toUrl:", ",", "namespaceFor:"],
+source: "commitPathStFor: aPackage\x0a\x09\x22If _source is not mapped, .st will be committed to .js path.\x0a\x09It is recommended not to use _source as it can be deprecated.\x22\x0a\x09\x0a\x09| path pathWithout |\x0a\x09path := self toUrl: (self namespaceFor: aPackage), '/_source'.\x0a\x09pathWithout := self commitPathJsFor: aPackage.\x0a\x09^ path = (pathWithout, '/_source') ifTrue: [ pathWithout ] ifFalse: [ path ]",
+messageSends: ["toUrl:", ",", "namespaceFor:", "commitPathJsFor:", "ifTrue:ifFalse:", "="],
 referencedClasses: []
 }),
 globals.AmdPackageHandler);
@@ -1856,12 +1864,12 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=globals.HashedCollection._from_(["type".__minus_gt(self._type())]);
+$1=globals.HashedCollection._newFromPairs_(["type",self._type()]);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"asJSON",{},globals.PackageTransport)})},
 args: [],
 source: "asJSON\x0a\x09^ #{ 'type' -> self type }",
-messageSends: ["->", "type"],
+messageSends: ["type"],
 referencedClasses: []
 }),
 globals.PackageTransport);
@@ -2104,7 +2112,7 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 globals.PackageTransport.klass.superclass.fn.prototype._initialize.apply(_st(self), []);
-self["@registry"]=globals.HashedCollection._from_([]);
+self["@registry"]=globals.HashedCollection._newFromPairs_([]);
 self._register();
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},globals.PackageTransport.klass)})},
 args: [],

+ 12 - 5
st/Kernel-ImportExport.st → js/Kernel-ImportExport.st

@@ -29,10 +29,12 @@ extensionProtocolsOfPackage: aPackage
 	result := OrderedCollection new.
 	
 	"The classes must be loaded since it is extensions only.
-	Therefore sorting (dependency resolution) does not matter here.
-	Not sorting improves the speed by a number of magnitude."
+	Therefore topological sorting (dependency resolution) does not matter here.
+	Not sorting topologically improves the speed by a number of magnitude.
 	
-	Smalltalk classes do: [ :each |
+	Not to shuffle diffs, classes are sorted by their name."
+	
+	(Smalltalk classes asArray sorted: [ :a :b | a name < b name ]) do: [ :each |
 		{each. each class} do: [ :behavior |
 			(behavior protocols includes: extensionName) ifTrue: [
 				result add: (ExportMethodProtocol name: extensionName theClass: behavior) ] ] ].
@@ -643,8 +645,13 @@ commitPathJsFor: aPackage
 !
 
 commitPathStFor: aPackage
-	"if _source is not mapped, .st commit will likely fail"
-	^ self toUrl: (self namespaceFor: aPackage), '/_source'.
+	"If _source is not mapped, .st will be committed to .js path.
+	It is recommended not to use _source as it can be deprecated."
+	
+	| path pathWithout |
+	path := self toUrl: (self namespaceFor: aPackage), '/_source'.
+	pathWithout := self commitPathJsFor: aPackage.
+	^ path = (pathWithout, '/_source') ifTrue: [ pathWithout ] ifFalse: [ path ]
 !
 
 exporterClass

+ 313 - 17
js/Kernel-Infrastructure.js

@@ -1079,7 +1079,7 @@ return smalltalk.withContext(function($ctx1) {
 return self["@jsObject"] === aJSObject;
 return self}, function($ctx1) {$ctx1.fill(self,"compareJSObjectWith:",{aJSObject:aJSObject},globals.JSObjectProxy)})},
 args: ["aJSObject"],
-source: " compareJSObjectWith: aJSObject\x0a \x09<return self[\x22@jsObject\x22] === aJSObject>",
+source: "compareJSObjectWith: aJSObject\x0a \x09<return self[\x22@jsObject\x22] === aJSObject>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1461,6 +1461,52 @@ referencedClasses: []
 }),
 globals.Package);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "classTemplate",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $String(){return globals.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+var $3,$4,$2,$5,$6,$7,$1;
+$1=_st($String())._streamContents_((function(stream){
+return smalltalk.withContext(function($ctx2) {
+_st(stream)._nextPutAll_("Object");
+$ctx2.sendIdx["nextPutAll:"]=1;
+_st(stream)._nextPutAll_(" subclass: #NameOfSubclass");
+$ctx2.sendIdx["nextPutAll:"]=2;
+$3=_st($String())._lf();
+$ctx2.sendIdx["lf"]=1;
+$4=_st($String())._tab();
+$ctx2.sendIdx["tab"]=1;
+$2=_st($3).__comma($4);
+$ctx2.sendIdx[","]=1;
+_st(stream)._nextPutAll_($2);
+$ctx2.sendIdx["nextPutAll:"]=3;
+$5=_st(stream)._nextPutAll_("instanceVariableNames: ''");
+$ctx2.sendIdx["nextPutAll:"]=4;
+$5;
+$6=_st("'".__comma(_st($String())._lf())).__comma(_st($String())._tab());
+$ctx2.sendIdx[","]=2;
+_st(stream)._nextPutAll_($6);
+$ctx2.sendIdx["nextPutAll:"]=5;
+_st(stream)._nextPutAll_("package: '");
+$ctx2.sendIdx["nextPutAll:"]=6;
+_st(stream)._nextPutAll_(self._name());
+$ctx2.sendIdx["nextPutAll:"]=7;
+$7=_st(stream)._nextPutAll_("'");
+return $7;
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"classTemplate",{},globals.Package)})},
+args: [],
+source: "classTemplate\x0a\x09^ String streamContents: [ :stream |\x0a\x09\x09stream\x0a\x09\x09\x09nextPutAll: 'Object';\x0a\x09\x09\x09nextPutAll: ' subclass: #NameOfSubclass';\x0a\x09\x09\x09nextPutAll: String lf, String tab;\x0a\x09\x09\x09nextPutAll: 'instanceVariableNames: '''''.\x0a\x09\x09stream\x0a\x09\x09\x09nextPutAll: '''', String lf, String tab;\x0a\x09\x09\x09nextPutAll: 'package: ''';\x0a\x09\x09\x09nextPutAll: self name;\x0a\x09\x09\x09nextPutAll: '''' ]",
+messageSends: ["streamContents:", "nextPutAll:", ",", "lf", "tab", "name"],
+referencedClasses: ["String"]
+}),
+globals.Package);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "classes",
@@ -1558,8 +1604,7 @@ return smalltalk.withContext(function($ctx2) {
 return _st(each)._package();
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})})))._asSet();
 _st($2)._remove_ifAbsent_(self,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $3=_st($2)._yourself();
 $1=$3;
 return $1;
@@ -1591,8 +1636,7 @@ return _st(each)._superclass();
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 $2=_st($3)._asSet();
 _st($2)._remove_ifAbsent_(nil,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 _st($2)._addAll_(_st(_st($Smalltalk())._classes())._select_((function(each){
 return smalltalk.withContext(function($ctx2) {
 $6=_st(each)._protocols();
@@ -1972,12 +2016,10 @@ function $PlatformInterface(){return globals.PlatformInterface||(typeof Platform
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=_st(_st($PlatformInterface())._globals())._at_ifPresent_ifAbsent_(aString,(function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"existsGlobal:",{aString:aString},globals.PlatformInterface.klass)})},
 args: ["aString"],
@@ -2294,6 +2336,153 @@ referencedClasses: []
 globals.Transcript.klass);
 
 
+smalltalk.addClass('Setting', globals.Object, ['key', 'value', 'defaultValue'], 'Kernel-Infrastructure');
+globals.Setting.comment="I represent a setting accessible via `Smalltalk settings`.\x0a\x0a## API\x0a\x0aA `Setting` value can be read using `value` and set using `value:`.\x0a\x0aSettings are accessed with `'key' asSetting` or `'key' asSettingIfAbsent: 'defaultValue'`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultValue",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@defaultValue"];
+return $1;
+},
+args: [],
+source: "defaultValue\x0a\x09^ defaultValue",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Setting);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "defaultValue:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@defaultValue"]=anObject;
+return self},
+args: ["anObject"],
+source: "defaultValue: anObject\x0a\x09defaultValue := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Setting);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@key"];
+return $1;
+},
+args: [],
+source: "key\x0a\x09^ key",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Setting);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@key"]=anObject;
+return self},
+args: ["anObject"],
+source: "key: anObject\x0a\x09key := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Setting);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $Smalltalk(){return globals.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st($Smalltalk())._settings())._at_ifAbsent_(self._key(),(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._defaultValue();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value",{},globals.Setting)})},
+args: [],
+source: "value\x0a\x09^ Smalltalk settings at: self key ifAbsent: [ self defaultValue ]",
+messageSends: ["at:ifAbsent:", "settings", "key", "defaultValue"],
+referencedClasses: ["Smalltalk"]
+}),
+globals.Setting);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "value:",
+protocol: 'accessing',
+fn: function (aString){
+var self=this;
+function $Smalltalk(){return globals.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st($Smalltalk())._settings())._at_put_(self._key(),aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value:",{aString:aString},globals.Setting)})},
+args: ["aString"],
+source: "value: aString\x0a\x09^ Smalltalk settings at: self key put: aString",
+messageSends: ["at:put:", "settings", "key"],
+referencedClasses: ["Smalltalk"]
+}),
+globals.Setting);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "at:ifAbsent:",
+protocol: 'instance creation',
+fn: function (aString,anotherString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=globals.Setting.klass.superclass.fn.prototype._new.apply(_st(self), []);
+_st($2)._key_(aString);
+_st($2)._defaultValue_(anotherString);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aString:aString,anotherString:anotherString},globals.Setting.klass)})},
+args: ["aString", "anotherString"],
+source: "at: aString ifAbsent: anotherString\x0a\x09^ super new\x0a\x09\x09key: aString;\x0a\x09\x09defaultValue: anotherString;\x0a\x09\x09yourself",
+messageSends: ["key:", "new", "defaultValue:", "yourself"],
+referencedClasses: []
+}),
+globals.Setting.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "new",
+protocol: 'instance creation',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._shouldNotImplement();
+return self}, function($ctx1) {$ctx1.fill(self,"new",{},globals.Setting.klass)})},
+args: [],
+source: "new\x0a\x09self shouldNotImplement",
+messageSends: ["shouldNotImplement"],
+referencedClasses: []
+}),
+globals.Setting.klass);
+
+
 smalltalk.addClass('SmalltalkImage', globals.Object, [], 'Kernel-Infrastructure');
 globals.SmalltalkImage.comment="I represent the Smalltalk system, wrapping\x0aoperations of variable `smalltalk` declared in `js/boot.js`.\x0a\x0a## API\x0a\x0aI have only one instance, accessed with global variable `Smalltalk`.\x0a\x0aThe `smalltalk` object holds all class and packages defined in the system.\x0a\x0a## Classes\x0a\x0aClasses can be accessed using the following methods:\x0a\x0a- `#classes` answers the full list of Smalltalk classes in the system\x0a- `#at:` answers a specific class or `nil`\x0a\x0a## Packages\x0a\x0aPackages can be accessed using the following methods:\x0a\x0a- `#packages` answers the full list of packages\x0a- `#packageAt:` answers a specific package or `nil`\x0a\x0a## Parsing\x0a\x0aThe `#parse:` method is used to parse Amber source code.\x0aIt requires the `Compiler` package and the `js/parser.js` parser file in order to work.";
 smalltalk.addMethod(
@@ -2545,12 +2734,12 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self._vm())._defaultAmdNamespace();
+$1="transport.defaultAmdNamespace"._settingValue();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"defaultAmdNamespace",{},globals.SmalltalkImage)})},
 args: [],
-source: "defaultAmdNamespace\x0a\x09^ self vm defaultAmdNamespace",
-messageSends: ["defaultAmdNamespace", "vm"],
+source: "defaultAmdNamespace\x0a\x09^ 'transport.defaultAmdNamespace' settingValue",
+messageSends: ["settingValue"],
 referencedClasses: []
 }),
 globals.SmalltalkImage);
@@ -2562,11 +2751,11 @@ protocol: 'accessing amd',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._vm())._defaultAmdNamespace_(aString);
+"transport.defaultAmdNamespace"._settingValue_(aString);
 return self}, function($ctx1) {$ctx1.fill(self,"defaultAmdNamespace:",{aString:aString},globals.SmalltalkImage)})},
 args: ["aString"],
-source: "defaultAmdNamespace: aString\x0a\x09self vm defaultAmdNamespace: aString",
-messageSends: ["defaultAmdNamespace:", "vm"],
+source: "defaultAmdNamespace: aString\x0a\x09'transport.defaultAmdNamespace' settingValue: aString",
+messageSends: ["settingValue:"],
 referencedClasses: []
 }),
 globals.SmalltalkImage);
@@ -2595,8 +2784,7 @@ fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 _st(self._globalJsVariables())._remove_ifAbsent_(aString,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"deleteGlobalJsVariable:",{aString:aString},globals.SmalltalkImage)})},
 args: ["aString"],
 source: "deleteGlobalJsVariable: aString\x0a\x09self globalJsVariables remove: aString ifAbsent:[]",
@@ -2937,6 +3125,22 @@ referencedClasses: []
 }),
 globals.SmalltalkImage);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "settings",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $SmalltalkSettings(){return globals.SmalltalkSettings||(typeof SmalltalkSettings=="undefined"?nil:SmalltalkSettings)}
+return $SmalltalkSettings();
+},
+args: [],
+source: "settings\x0a\x09^ SmalltalkSettings",
+messageSends: [],
+referencedClasses: ["SmalltalkSettings"]
+}),
+globals.SmalltalkImage);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "version",
@@ -3062,4 +3266,96 @@ referencedClasses: []
 }),
 globals.String);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asSetting",
+protocol: '*Kernel-Infrastructure',
+fn: function (){
+var self=this;
+function $Setting(){return globals.Setting||(typeof Setting=="undefined"?nil:Setting)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($Setting())._at_ifAbsent_(self,nil);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSetting",{},globals.String)})},
+args: [],
+source: "asSetting\x0a\x09^ Setting at: self ifAbsent: nil",
+messageSends: ["at:ifAbsent:"],
+referencedClasses: ["Setting"]
+}),
+globals.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asSettingIfAbsent:",
+protocol: '*Kernel-Infrastructure',
+fn: function (aString){
+var self=this;
+function $Setting(){return globals.Setting||(typeof Setting=="undefined"?nil:Setting)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($Setting())._at_ifAbsent_(self,aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSettingIfAbsent:",{aString:aString},globals.String)})},
+args: ["aString"],
+source: "asSettingIfAbsent: aString\x0a\x09^ Setting at: self ifAbsent: aString",
+messageSends: ["at:ifAbsent:"],
+referencedClasses: ["Setting"]
+}),
+globals.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "settingValue",
+protocol: '*Kernel-Infrastructure',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._asSetting())._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"settingValue",{},globals.String)})},
+args: [],
+source: "settingValue\x0a\x09^ self asSetting value",
+messageSends: ["value", "asSetting"],
+referencedClasses: []
+}),
+globals.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "settingValue:",
+protocol: '*Kernel-Infrastructure',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._asSetting())._value_(aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"settingValue:",{aString:aString},globals.String)})},
+args: ["aString"],
+source: "settingValue: aString\x0a\x09^ self asSetting value: aString",
+messageSends: ["value:", "asSetting"],
+referencedClasses: []
+}),
+globals.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "settingValueIfAbsent:",
+protocol: '*Kernel-Infrastructure',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._asSettingIfAbsent_(aString))._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"settingValueIfAbsent:",{aString:aString},globals.String)})},
+args: ["aString"],
+source: "settingValueIfAbsent: aString\x0a\x09^ (self asSettingIfAbsent: aString) value",
+messageSends: ["value", "asSettingIfAbsent:"],
+referencedClasses: []
+}),
+globals.String);
+
 });

+ 91 - 2
st/Kernel-Infrastructure.st → js/Kernel-Infrastructure.st

@@ -559,6 +559,20 @@ basicTransport
 	<return self.transport>
 !
 
+classTemplate
+	^ String streamContents: [ :stream |
+		stream
+			nextPutAll: 'Object';
+			nextPutAll: ' subclass: #NameOfSubclass';
+			nextPutAll: String lf, String tab;
+			nextPutAll: 'instanceVariableNames: '''''.
+		stream
+			nextPutAll: '''', String lf, String tab;
+			nextPutAll: 'package: ''';
+			nextPutAll: self name;
+			nextPutAll: '''' ]
+!
+
 definition
 	^ String streamContents: [ :stream |
 		stream 
@@ -895,6 +909,57 @@ show: anObject
 	self current show: anObject
 ! !
 
+Object subclass: #Setting
+	instanceVariableNames: 'key value defaultValue'
+	package: 'Kernel-Infrastructure'!
+!Setting commentStamp!
+I represent a setting accessible via `Smalltalk settings`.
+
+## API
+
+A `Setting` value can be read using `value` and set using `value:`.
+
+Settings are accessed with `'key' asSetting` or `'key' asSettingIfAbsent: 'defaultValue'`.!
+
+!Setting methodsFor: 'accessing'!
+
+defaultValue
+	^ defaultValue
+!
+
+defaultValue: anObject
+	defaultValue := anObject
+!
+
+key
+	^ key
+!
+
+key: anObject
+	key := anObject
+!
+
+value
+	^ Smalltalk settings at: self key ifAbsent: [ self defaultValue ]
+!
+
+value: aString
+	^ Smalltalk settings at: self key put: aString
+! !
+
+!Setting class methodsFor: 'instance creation'!
+
+at: aString ifAbsent: anotherString
+	^ super new
+		key: aString;
+		defaultValue: anotherString;
+		yourself
+!
+
+new
+	self shouldNotImplement
+! !
+
 Object subclass: #SmalltalkImage
 	instanceVariableNames: ''
 	package: 'Kernel-Infrastructure'!
@@ -985,6 +1050,10 @@ reservedWords
 	<return smalltalk.reservedWords>
 !
 
+settings
+	^ SmalltalkSettings
+!
+
 version
 	"Answer the version string of Amber"
 	
@@ -1003,11 +1072,11 @@ amdRequire
 !
 
 defaultAmdNamespace
-	^ self vm defaultAmdNamespace
+	^ 'transport.defaultAmdNamespace' settingValue
 !
 
 defaultAmdNamespace: aString
-	self vm defaultAmdNamespace: aString
+	'transport.defaultAmdNamespace' settingValue: aString
 ! !
 
 !SmalltalkImage methodsFor: 'classes'!
@@ -1184,5 +1253,25 @@ do: aBlock displayingProgress: aString
 asJavaScriptSelector
 	"Return first keyword of the selector, without trailing colon."
 	^ self replace: '^([a-zA-Z0-9]*).*$' with: '$1'
+!
+
+asSetting
+	^ Setting at: self ifAbsent: nil
+!
+
+asSettingIfAbsent: aString
+	^ Setting at: self ifAbsent: aString
+!
+
+settingValue
+	^ self asSetting value
+!
+
+settingValue: aString
+	^ self asSetting value: aString
+!
+
+settingValueIfAbsent: aString
+	^ (self asSettingIfAbsent: aString) value
 ! !
 

+ 37 - 10
js/Kernel-Methods.js

@@ -185,15 +185,13 @@ fn: function (aCollection){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-		var constructor = function() {};
-		constructor.prototype = self.prototype;
-		var object = new constructor;
+		var object = Object.create(self.prototype);
 		var result = self.apply(object, aCollection);
 		return typeof result === "object" ? result : object;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"newWithValues:",{aCollection:aCollection},globals.BlockClosure)})},
 args: ["aCollection"],
-source: "newWithValues: aCollection\x0a\x09\x22Use the receiver as a JavaScript constructor with a variable number of arguments.\x0a\x09Answer the object created using the operator `new`.\x0a\x0a\x09This algorithm was inspired by http://stackoverflow.com/a/6069331.\x0a\x0a\x09Here's a general breakdown of what's going on:\x0a\x091) Create a new, empty constructor function.\x0a\x092) Set it's prototype to the receiver's prototype. Because the receiver is a `BlockClosure`, it is also a JavaScript function.\x0a\x093) Instantiate a new object using the constructor function just created. \x0a\x09\x09This forces the interpreter to set the internal [[prototype]] property to what was set on the function before. \x0a   \x09\x09This has to be done, as we have no access to the [[prototype]] property externally.\x0a\x094) Apply `self` to the object I just instantiated.\x22\x0a\x0a\x09<\x0a\x09\x09var constructor = function() {};\x0a\x09\x09constructor.prototype = self.prototype;\x0a\x09\x09var object = new constructor;\x0a\x09\x09var result = self.apply(object, aCollection);\x0a\x09\x09return typeof result === \x22object\x22 ? result : object;\x0a\x09>",
+source: "newWithValues: aCollection\x0a\x09\x22Simulates JS new operator by combination of Object.create and .apply\x22\x0a\x09<\x0a\x09\x09var object = Object.create(self.prototype);\x0a\x09\x09var result = self.apply(object, aCollection);\x0a\x09\x09return typeof result === \x22object\x22 ? result : object;\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -405,8 +403,7 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 self._whileFalse_((function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"whileFalse",{},globals.BlockClosure)})},
 args: [],
 source: "whileFalse\x0a\x09self whileFalse: []",
@@ -439,8 +436,7 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 self._whileTrue_((function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"whileTrue",{},globals.BlockClosure)})},
 args: [],
 source: "whileTrue\x0a\x09self whileTrue: []",
@@ -662,6 +658,38 @@ referencedClasses: []
 }),
 globals.CompiledMethod);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "package",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $Package(){return globals.Package||(typeof Package=="undefined"?nil:Package)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$4,$3,$5;
+$2=self._protocol();
+$ctx1.sendIdx["protocol"]=1;
+$1=_st($2)._beginsWith_("*");
+if(! smalltalk.assert($1)){
+$4=self._methodClass();
+$ctx1.sendIdx["methodClass"]=1;
+$3=_st($4)._package();
+$ctx1.sendIdx["package"]=1;
+return $3;
+};
+$5=_st($Package())._named_ifAbsent_(_st(self._protocol())._allButFirst(),(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._methodClass())._package();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+return $5;
+}, function($ctx1) {$ctx1.fill(self,"package",{},globals.CompiledMethod)})},
+args: [],
+source: "package\x0a\x09\x22Answer the package the receiver belongs to:\x0a\x09- if it is an extension method, answer the corresponding package\x0a\x09- else answer the `methodClass` package\x22\x0a\x09\x0a\x09(self protocol beginsWith: '*') ifFalse: [\x0a\x09\x09^ self methodClass package ].\x0a\x09\x09\x0a\x09^ Package \x0a\x09\x09named: self protocol allButFirst\x0a\x09\x09ifAbsent: [ self methodClass package ]",
+messageSends: ["ifFalse:", "beginsWith:", "protocol", "package", "methodClass", "named:ifAbsent:", "allButFirst"],
+referencedClasses: ["Package"]
+}),
+globals.CompiledMethod);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "protocol",
@@ -926,9 +954,8 @@ return smalltalk.withContext(function($ctx2) {
 self["@poolSize"]=_st(self["@poolSize"]).__minus((1));
 self["@poolSize"];
 block=_st(self["@queue"])._nextIfAbsent_((function(){
-return smalltalk.withContext(function($ctx3) {
 return sentinel;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}));
 block;
 $2=_st(block).__eq_eq(sentinel);
 if(! smalltalk.assert($2)){

+ 15 - 16
st/Kernel-Methods.st → js/Kernel-Methods.st

@@ -121,23 +121,9 @@ newValue: anObject value: anObject2 value: anObject3
 !
 
 newWithValues: aCollection
-	"Use the receiver as a JavaScript constructor with a variable number of arguments.
-	Answer the object created using the operator `new`.
-
-	This algorithm was inspired by http://stackoverflow.com/a/6069331.
-
-	Here's a general breakdown of what's going on:
-	1) Create a new, empty constructor function.
-	2) Set it's prototype to the receiver's prototype. Because the receiver is a `BlockClosure`, it is also a JavaScript function.
-	3) Instantiate a new object using the constructor function just created. 
-		This forces the interpreter to set the internal [[prototype]] property to what was set on the function before. 
-   		This has to be done, as we have no access to the [[prototype]] property externally.
-	4) Apply `self` to the object I just instantiated."
-
+	"Simulates JS new operator by combination of Object.create and .apply"
 	<
-		var constructor = function() {};
-		constructor.prototype = self.prototype;
-		var object = new constructor;
+		var object = Object.create(self.prototype);
 		var result = self.apply(object, aCollection);
 		return typeof result === "object" ? result : object;
 	>
@@ -238,6 +224,19 @@ methodClass
 	^ self basicAt: 'methodClass'
 !
 
+package
+	"Answer the package the receiver belongs to:
+	- if it is an extension method, answer the corresponding package
+	- else answer the `methodClass` package"
+	
+	(self protocol beginsWith: '*') ifFalse: [
+		^ self methodClass package ].
+		
+	^ Package 
+		named: self protocol allButFirst
+		ifAbsent: [ self methodClass package ]
+!
+
 protocol
 	^ (self basicAt: 'protocol') ifNil: [ self defaultProtocol ]
 !

+ 5 - 10
js/Kernel-Objects.js

@@ -1306,9 +1306,8 @@ return smalltalk.withContext(function($ctx1) {
 var $2,$1;
 $2=self.__eq(true);
 $1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"and:",{aBlock:aBlock},globals.Boolean)})},
 args: ["aBlock"],
@@ -1395,8 +1394,7 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=self._ifTrue_ifFalse_((function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),aBlock);
+}),aBlock);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifFalse:",{aBlock:aBlock},globals.Boolean)})},
 args: ["aBlock"],
@@ -1433,8 +1431,7 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=self._ifTrue_ifFalse_(aBlock,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifTrue:",{aBlock:aBlock},globals.Boolean)})},
 args: ["aBlock"],
@@ -1524,9 +1521,8 @@ return smalltalk.withContext(function($ctx1) {
 var $2,$1;
 $2=self.__eq(true);
 $1=_st($2)._ifTrue_ifFalse_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),aBlock);
+}),aBlock);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"or:",{aBlock:aBlock},globals.Boolean)})},
 args: ["aBlock"],
@@ -3844,8 +3840,7 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=self._ifNil_ifNotNil_(aBlock,(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNil:",{aBlock:aBlock},globals.UndefinedObject)})},
 args: ["aBlock"],

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


+ 105 - 230
js/Kernel-Tests.js

@@ -220,12 +220,10 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 self._assert_equals_(_st((function(){
-return smalltalk.withContext(function($ctx2) {
 return (3);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._ensure_((function(){
-return smalltalk.withContext(function($ctx2) {
+}))._ensure_((function(){
 return (4);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})})),(3));
+})),(3));
 return self}, function($ctx1) {$ctx1.fill(self,"testEnsure",{},globals.BlockClosureTest)})},
 args: [],
 source: "testEnsure\x0a\x09self assert: ([ 3 ] ensure: [ 4 ]) equals: 3",
@@ -248,9 +246,8 @@ return _st((function(){
 return smalltalk.withContext(function($ctx3) {
 return _st(_st($Error())._new())._signal();
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}))._ensure_((function(){
-return smalltalk.withContext(function($ctx3) {
 return true;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
+}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
 return self}, function($ctx1) {$ctx1.fill(self,"testEnsureRaises",{},globals.BlockClosureTest)})},
 args: [],
@@ -299,20 +296,19 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-	function theTestPrototype() {this.name = "theTestPrototype";}
-	function theTestConstructor(arg1, arg2, arg3) {}
-	theTestConstructor.prototype = new theTestPrototype;
+	function TestConstructor(arg1, arg2, arg3) {}
+	TestConstructor.prototype.name = 'theTestPrototype';
 
-	var theWrappedConstructor = _st(theTestConstructor);
-	var theResult = theWrappedConstructor._newWithValues_([1, 2, 3 ]);
-	self._assert_equals_(Object.getPrototypeOf(theResult).name, 'theTestPrototype');
+	var wrappedConstructor = _st(TestConstructor);
+	var result = wrappedConstructor._newWithValues_([1, 2, 3 ]);
+	self._assert_(result instanceof TestConstructor);
+	self._assert_equals_(result.name, 'theTestPrototype');
 
 	"newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made."
-	function constructionShouldFail() {var anotherResult = theWrappedConstructor._newWithValues_('This is so wrong');}
-	self._should_raise_(_st(constructionShouldFail), globals.Error);;
+	self._should_raise_(function () {wrappedConstructor._newWithValues_('single argument');}, globals.Error);;
 return self}, function($ctx1) {$ctx1.fill(self,"testNewWithValues",{},globals.BlockClosureTest)})},
 args: [],
-source: "testNewWithValues\x0a<\x0a\x09function theTestPrototype() {this.name = \x22theTestPrototype\x22;}\x0a\x09function theTestConstructor(arg1, arg2, arg3) {}\x0a\x09theTestConstructor.prototype = new theTestPrototype;\x0a\x0a\x09var theWrappedConstructor = _st(theTestConstructor);\x0a\x09var theResult = theWrappedConstructor._newWithValues_([1, 2, 3 ]);\x0a\x09self._assert_equals_(Object.getPrototypeOf(theResult).name, 'theTestPrototype');\x0a\x0a\x09\x22newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made.\x22\x0a\x09function constructionShouldFail() {var anotherResult = theWrappedConstructor._newWithValues_('This is so wrong');}\x0a\x09self._should_raise_(_st(constructionShouldFail), globals.Error);\x0a>",
+source: "testNewWithValues\x0a<\x0a\x09function TestConstructor(arg1, arg2, arg3) {}\x0a\x09TestConstructor.prototype.name = 'theTestPrototype';\x0a\x0a\x09var wrappedConstructor = _st(TestConstructor);\x0a\x09var result = wrappedConstructor._newWithValues_([1, 2, 3 ]);\x0a\x09self._assert_(result instanceof TestConstructor);\x0a\x09self._assert_equals_(result.name, 'theTestPrototype');\x0a\x0a\x09\x22newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made.\x22\x0a\x09self._should_raise_(function () {wrappedConstructor._newWithValues_('single argument');}, globals.Error);\x0a>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -327,14 +323,12 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=_st((function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._numArgs();
+}))._numArgs();
 $ctx1.sendIdx["numArgs"]=1;
 self._assert_equals_($1,(0));
 $ctx1.sendIdx["assert:equals:"]=1;
 self._assert_equals_(_st((function(a,b){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({a:a,b:b},$ctx1,2)})}))._numArgs(),(2));
+}))._numArgs(),(2));
 return self}, function($ctx1) {$ctx1.fill(self,"testNumArgs",{},globals.BlockClosureTest)})},
 args: [],
 source: "testNumArgs\x0a\x09self assert: [] numArgs equals: 0.\x0a\x09self assert: [ :a :b | ] numArgs equals: 2",
@@ -355,9 +349,8 @@ self._assert_(_st((function(){
 return smalltalk.withContext(function($ctx2) {
 return _st(_st($Error())._new())._signal();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(ex){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})})));
+})));
 return self}, function($ctx1) {$ctx1.fill(self,"testOnDo",{},globals.BlockClosureTest)})},
 args: [],
 source: "testOnDo\x0a\x09self assert: ([ Error new signal ] on: Error do: [ :ex | true ])",
@@ -393,9 +386,8 @@ return _st(x).__star(y);
 }, function($ctx2) {$ctx2.fillBlock({x:x,y:y},$ctx1,3)})}))._value_value_((2),(4)),(8));
 $ctx1.sendIdx["assert:equals:"]=3;
 self._assert_equals_(_st((function(a,b,c){
-return smalltalk.withContext(function($ctx2) {
 return (1);
-}, function($ctx2) {$ctx2.fillBlock({a:a,b:b,c:c},$ctx1,4)})}))._value(),(1));
+}))._value(),(1));
 return self}, function($ctx1) {$ctx1.fill(self,"testValue",{},globals.BlockClosureTest)})},
 args: [],
 source: "testValue\x0a\x09self assert: ([ 1+1 ] value) equals: 2.\x0a\x09self assert: ([ :x | x +1 ] value: 2) equals: 3.\x0a\x09self assert: ([ :x :y | x*y ] value: 2 value: 4) equals: 8.\x0a\x0a\x09\x22Arguments are optional in Amber. This isn't ANSI compliant.\x22\x0a\x0a\x09self assert: ([ :a :b :c | 1 ] value) equals: 1",
@@ -413,9 +405,8 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 $1=_st((function(){
-return smalltalk.withContext(function($ctx2) {
 return (1);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._valueWithPossibleArguments_([(3), (4)]);
+}))._valueWithPossibleArguments_([(3), (4)]);
 $ctx1.sendIdx["valueWithPossibleArguments:"]=1;
 self._assert_equals_($1,(1));
 $ctx1.sendIdx["assert:equals:"]=1;
@@ -862,58 +853,50 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3,$5,$4,$6,$7,$8,$10,$9,$11,$13,$12,$16,$15,$14,$17,$19,$18,$22,$21,$20;
 $1=true._and_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["and:"]=1;
 self._assert_($1);
 $ctx1.sendIdx["assert:"]=1;
 $2=true._and_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["and:"]=2;
 self._deny_($2);
 $ctx1.sendIdx["deny:"]=1;
 $3=false._and_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+}));
 $ctx1.sendIdx["and:"]=3;
 self._deny_($3);
 $ctx1.sendIdx["deny:"]=2;
 $5=false._and_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+}));
 $ctx1.sendIdx["and:"]=4;
 $4=self._deny_($5);
 $ctx1.sendIdx["deny:"]=3;
 $6=true._or_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
+}));
 $ctx1.sendIdx["or:"]=1;
 self._assert_($6);
 $ctx1.sendIdx["assert:"]=2;
 $7=true._or_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,6)})}));
+}));
 $ctx1.sendIdx["or:"]=2;
 self._assert_($7);
 $ctx1.sendIdx["assert:"]=3;
 $8=false._or_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,7)})}));
+}));
 $ctx1.sendIdx["or:"]=3;
 self._assert_($8);
 $ctx1.sendIdx["assert:"]=4;
 $10=false._or_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,8)})}));
+}));
 $ctx1.sendIdx["or:"]=4;
 $9=self._deny_($10);
 $ctx1.sendIdx["deny:"]=4;
@@ -928,9 +911,8 @@ $ctx1.sendIdx["assert:"]=5;
 $13=(1).__gt((0));
 $ctx1.sendIdx[">"]=2;
 $12=_st($13)._and_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,10)})}));
+}));
 $ctx1.sendIdx["and:"]=6;
 self._deny_($12);
 $ctx1.sendIdx["deny:"]=5;
@@ -953,9 +935,8 @@ $ctx1.sendIdx["assert:"]=6;
 $19=(1).__gt((0));
 $ctx1.sendIdx[">"]=6;
 $18=_st($19)._or_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,13)})}));
+}));
 $ctx1.sendIdx["or:"]=6;
 self._assert_($18);
 $ctx1.sendIdx["assert:"]=7;
@@ -1646,9 +1627,8 @@ var $2,$1,$3,$5,$4,$8,$7,$6,$11,$10,$9;
 $2=self._collection();
 $ctx1.sendIdx["collection"]=1;
 $1=_st($2)._collect_((function(each){
-return smalltalk.withContext(function($ctx2) {
 return each;
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["collect:"]=1;
 $3=self._collection();
 $ctx1.sendIdx["collection"]=2;
@@ -1657,9 +1637,8 @@ $ctx1.sendIdx["assert:equals:"]=1;
 $5=self._collectionWithNewValue();
 $ctx1.sendIdx["collectionWithNewValue"]=1;
 $4=_st($5)._collect_((function(each){
-return smalltalk.withContext(function($ctx2) {
 return each;
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["collect:"]=2;
 self._assert_equals_($4,self._collectionWithNewValue());
 $ctx1.sendIdx["assert:equals:"]=2;
@@ -1684,9 +1663,8 @@ $ctx2.sendIdx["sampleNewValue"]=1;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
 $ctx1.sendIdx["collect:"]=4;
 $9=_st($10)._detect_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
+}));
 self._assert_equals_($9,self._sampleNewValue());
 $ctx1.sendIdx["assert:equals:"]=4;
 self._assert_equals_(_st(self._collection())._collect_((function(each){
@@ -1777,9 +1755,8 @@ return smalltalk.withContext(function($ctx2) {
 $1=self._collection();
 $ctx2.sendIdx["collection"]=1;
 return _st($1)._detect_((function(){
-return smalltalk.withContext(function($ctx3) {
 return true;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}));
 $ctx2.sendIdx["detect:"]=1;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
 self._should_raise_((function(){
@@ -1787,16 +1764,14 @@ return smalltalk.withContext(function($ctx2) {
 $2=self._collection();
 $ctx2.sendIdx["collection"]=2;
 return _st($2)._detect_((function(){
-return smalltalk.withContext(function($ctx3) {
 return false;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,4)})}));
+}));
 $ctx2.sendIdx["detect:"]=2;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}),$Error());
 $ctx1.sendIdx["should:raise:"]=1;
 $3=_st(self._sampleNewValueAsCollection())._detect_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
+}));
 $ctx1.sendIdx["detect:"]=3;
 $4=self._sampleNewValue();
 $ctx1.sendIdx["sampleNewValue"]=1;
@@ -1842,34 +1817,28 @@ sentinel=_st($Object())._new();
 $3=self._collection();
 $ctx1.sendIdx["collection"]=1;
 $2=_st($3)._detect_ifNone_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return sentinel;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["detect:ifNone:"]=1;
 $1=_st($2).__tild_eq(sentinel);
 self._assert_($1);
 $5=self._collection();
 $ctx1.sendIdx["collection"]=2;
 $4=_st($5)._detect_ifNone_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return sentinel;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+}));
 $ctx1.sendIdx["detect:ifNone:"]=2;
 self._assert_equals_($4,sentinel);
 $ctx1.sendIdx["assert:equals:"]=1;
 $6=_st(self._sampleNewValueAsCollection())._detect_ifNone_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return sentinel;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,6)})}));
+}));
 $ctx1.sendIdx["detect:ifNone:"]=3;
 $7=self._sampleNewValue();
 $ctx1.sendIdx["sampleNewValue"]=1;
@@ -1882,9 +1851,8 @@ $ctx2.sendIdx["sampleNewValue"]=2;
 return _st(each).__eq($9);
 $ctx2.sendIdx["="]=1;
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,7)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return sentinel;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,8)})}));
+}));
 $ctx1.sendIdx["detect:ifNone:"]=4;
 $10=self._sampleNewValue();
 $ctx1.sendIdx["sampleNewValue"]=3;
@@ -1894,9 +1862,8 @@ self._assert_equals_(_st(self._collection())._detect_ifNone_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(each).__eq(self._sampleNewValue());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,9)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return sentinel;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,10)})})),sentinel);
+})),sentinel);
 return self}, function($ctx1) {$ctx1.fill(self,"testDetectIfNone",{sentinel:sentinel},globals.CollectionTest)})},
 args: [],
 source: "testDetectIfNone\x0a\x09| sentinel |\x0a\x09sentinel := Object new.\x0a\x09self assert: (self collection detect: [ true ] ifNone: [ sentinel ]) ~= sentinel.\x0a\x09self assert: (self collection detect: [ false ] ifNone: [ sentinel ]) equals: sentinel.\x0a\x09self assert: (self sampleNewValueAsCollection detect: [ true ] ifNone: [ sentinel ]) equals: self sampleNewValue.\x0a\x09self assert: (self collectionWithNewValue detect: [ :each | each = self sampleNewValue ] ifNone: [ sentinel ]) equals: self sampleNewValue.\x0a\x09self assert: (self collection detect: [ :each | each = self sampleNewValue ] ifNone: [ sentinel ]) equals: sentinel",
@@ -1956,18 +1923,16 @@ $ctx1.sendIdx["collectionClass"]=1;
 $2=_st($3)._new();
 $ctx1.sendIdx["new"]=1;
 $1=_st($2)._ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["ifEmpty:"]=1;
 self._assert_equals_($1,(42));
 $ctx1.sendIdx["assert:equals:"]=1;
 $5=self._collection();
 $ctx1.sendIdx["collection"]=1;
 $4=_st($5)._ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $6=self._collection();
 $ctx1.sendIdx["collection"]=2;
 self._assert_equals_($4,$6);
@@ -1977,9 +1942,8 @@ $ctx1.sendIdx["collectionClass"]=2;
 $8=_st($9)._new();
 $ctx1.sendIdx["new"]=2;
 $7=_st($8)._ifNotEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+}));
 $ctx1.sendIdx["ifNotEmpty:"]=1;
 $11=self._collectionClass();
 $ctx1.sendIdx["collectionClass"]=3;
@@ -1990,9 +1954,8 @@ $ctx1.sendIdx["assert:equals:"]=3;
 $13=self._collection();
 $ctx1.sendIdx["collection"]=3;
 $12=_st($13)._ifNotEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+}));
 self._assert_equals_($12,(42));
 $ctx1.sendIdx["assert:equals:"]=4;
 $16=self._collectionClass();
@@ -2000,43 +1963,35 @@ $ctx1.sendIdx["collectionClass"]=4;
 $15=_st($16)._new();
 $ctx1.sendIdx["new"]=4;
 $14=_st($15)._ifEmpty_ifNotEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return (999);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,6)})}));
+}));
 $ctx1.sendIdx["ifEmpty:ifNotEmpty:"]=1;
 self._assert_equals_($14,(42));
 $ctx1.sendIdx["assert:equals:"]=5;
 $18=self._collection();
 $ctx1.sendIdx["collection"]=4;
 $17=_st($18)._ifEmpty_ifNotEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,7)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return (999);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,8)})}));
+}));
 self._assert_equals_($17,(999));
 $ctx1.sendIdx["assert:equals:"]=6;
 $19=_st(_st(self._collectionClass())._new())._ifNotEmpty_ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,9)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return (999);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,10)})}));
+}));
 $ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1;
 self._assert_equals_($19,(999));
 $ctx1.sendIdx["assert:equals:"]=7;
 self._assert_equals_(_st(self._collection())._ifNotEmpty_ifEmpty_((function(){
-return smalltalk.withContext(function($ctx2) {
 return (42);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,11)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
+}),(function(){
 return (999);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,12)})})),(42));
+})),(42));
 return self}, function($ctx1) {$ctx1.fill(self,"testIfEmptyFamily",{},globals.CollectionTest)})},
 args: [],
 source: "testIfEmptyFamily\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ]) equals: self collection.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ]) equals: self collectionClass new.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ]) equals: 42.\x0a\x09\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 999.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 999.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 42",
@@ -2130,9 +2085,8 @@ var $2,$1,$4,$3,$6,$5,$7,$9,$10,$8,$12,$13,$11,$14,$16,$17,$15;
 $2=self._collection();
 $ctx1.sendIdx["collection"]=1;
 $1=_st($2)._select_((function(){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["select:"]=1;
 $4=self._collectionClass();
 $ctx1.sendIdx["collectionClass"]=1;
@@ -2143,9 +2097,8 @@ $ctx1.sendIdx["assert:equals:"]=1;
 $6=self._collection();
 $ctx1.sendIdx["collection"]=2;
 $5=_st($6)._select_((function(){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["select:"]=2;
 $7=self._collection();
 $ctx1.sendIdx["collection"]=3;
@@ -2451,11 +2404,10 @@ visited;
 $2=self._collection();
 $ctx2.sendIdx["collection"]=1;
 $1=_st($2)._at_ifPresent_(each,(function(value1){
-return smalltalk.withContext(function($ctx3) {
 visited=value1;
 visited;
 return sentinel;
-}, function($ctx3) {$ctx3.fillBlock({value1:value1},$ctx2,2)})}));
+}));
 $ctx2.sendIdx["at:ifPresent:"]=1;
 self._assert_equals_($1,nil);
 $ctx2.sendIdx["assert:equals:"]=1;
@@ -2468,11 +2420,10 @@ visited;
 $4=self._collection();
 $ctx2.sendIdx["collection"]=2;
 $3=_st($4)._at_ifPresent_(index,(function(value2){
-return smalltalk.withContext(function($ctx3) {
 visited=value2;
 visited;
 return sentinel;
-}, function($ctx3) {$ctx3.fillBlock({value2:value2},$ctx2,4)})}));
+}));
 self._assert_equals_($3,sentinel);
 $ctx2.sendIdx["assert:equals:"]=2;
 return self._assert_equals_(visited,_st(self._collection())._at_(index));
@@ -2503,11 +2454,10 @@ visited;
 $2=self._collection();
 $ctx2.sendIdx["collection"]=1;
 $1=_st($2)._at_ifPresent_ifAbsent_(each,(function(value1){
-return smalltalk.withContext(function($ctx3) {
 visited=value1;
 visited;
 return sentinel;
-}, function($ctx3) {$ctx3.fillBlock({value1:value1},$ctx2,2)})}),(function(){
+}),(function(){
 return smalltalk.withContext(function($ctx3) {
 return self._sampleNewValue();
 $ctx3.sendIdx["sampleNewValue"]=1;
@@ -2526,11 +2476,10 @@ visited;
 $5=self._collection();
 $ctx2.sendIdx["collection"]=2;
 $4=_st($5)._at_ifPresent_ifAbsent_(index,(function(value2){
-return smalltalk.withContext(function($ctx3) {
 visited=value2;
 visited;
 return sentinel;
-}, function($ctx3) {$ctx3.fillBlock({value2:value2},$ctx2,5)})}),(function(){
+}),(function(){
 return smalltalk.withContext(function($ctx3) {
 return self._sampleNewValue();
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,6)})}));
@@ -2913,17 +2862,11 @@ fn: function (){
 var self=this;
 var associations;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$5,$4;
+var $1;
 $1="a".__minus_gt((1));
 $ctx1.sendIdx["->"]=1;
-$2="b".__minus_gt((2));
-$ctx1.sendIdx["->"]=2;
-associations=[$1,$2];
-$3=_st(_st(self._class())._collectionClass())._from_(associations);
-$5="a".__minus_gt((1));
-$ctx1.sendIdx["->"]=3;
-$4=globals.HashedCollection._from_([$5,"b".__minus_gt((2))]);
-self._assertSameContents_as_($3,$4);
+associations=[$1,"b".__minus_gt((2))];
+self._assertSameContents_as_(_st(_st(self._class())._collectionClass())._from_(associations),globals.HashedCollection._newFromPairs_(["a",(1),"b",(2)]));
 return self}, function($ctx1) {$ctx1.fill(self,"testFrom",{associations:associations},globals.AssociativeCollectionTest)})},
 args: [],
 source: "testFrom\x0a\x22Accept a collection of associations.\x22\x0a| associations |\x0aassociations := { 'a' -> 1. 'b' -> 2 }.\x0aself assertSameContents: ( self class collectionClass from: associations ) as: #{ 'a' -> 1. 'b' -> 2 }.",
@@ -2967,17 +2910,12 @@ fn: function (){
 var self=this;
 var flattenedAssociations;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$2;
 flattenedAssociations=["a",(1),"b",(2)];
-$1=_st(_st(self._class())._collectionClass())._newFromPairs_(flattenedAssociations);
-$3="a".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$2=globals.HashedCollection._from_([$3,"b".__minus_gt((2))]);
-self._assertSameContents_as_($1,$2);
+self._assertSameContents_as_(_st(_st(self._class())._collectionClass())._newFromPairs_(flattenedAssociations),globals.HashedCollection._newFromPairs_(["a",(1),"b",(2)]));
 return self}, function($ctx1) {$ctx1.fill(self,"testNewFromPairs",{flattenedAssociations:flattenedAssociations},globals.AssociativeCollectionTest)})},
 args: [],
 source: "testNewFromPairs\x0a\x22Accept an array in which all odd indexes are keys and evens are values.\x22\x0a| flattenedAssociations |\x0aflattenedAssociations := { 'a'. 1. 'b'. 2 }.\x0aself assertSameContents: ( self class collectionClass newFromPairs: flattenedAssociations ) as: #{ 'a' -> 1. 'b' -> 2 }.",
-messageSends: ["assertSameContents:as:", "newFromPairs:", "collectionClass", "class", "->"],
+messageSends: ["assertSameContents:as:", "newFromPairs:", "collectionClass", "class"],
 referencedClasses: []
 }),
 globals.AssociativeCollectionTest);
@@ -3386,16 +3324,14 @@ $ctx1.sendIdx["at:"]=1;
 self._assert_equals_($1,"world");
 $ctx1.sendIdx["assert:equals:"]=1;
 $2=_st(d)._at_ifAbsent_("hello",(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["at:ifAbsent:"]=1;
 self._assert_equals_($2,"world");
 $ctx1.sendIdx["assert:equals:"]=2;
 self._deny_(_st(_st(d)._at_ifAbsent_("foo",(function(){
-return smalltalk.withContext(function($ctx2) {
 return nil;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}))).__eq("world"));
+}))).__eq("world"));
 $ctx1.sendIdx["deny:"]=1;
 $3=_st(d)._includesKey_("hello");
 $ctx1.sendIdx["includesKey:"]=1;
@@ -3443,16 +3379,11 @@ fn: function (){
 var self=this;
 function $Dictionary(){return globals.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1;
-$3="hello".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$2=globals.HashedCollection._from_([$3]);
-$1=_st($2)._asDictionary();
-self._assert_equals_($1,_st($Dictionary())._with_("hello".__minus_gt((1))));
+self._assert_equals_(_st(globals.HashedCollection._newFromPairs_(["hello",(1)]))._asDictionary(),_st($Dictionary())._with_("hello".__minus_gt((1))));
 return self}, function($ctx1) {$ctx1.fill(self,"testDynamicDictionaries",{},globals.DictionaryTest)})},
 args: [],
 source: "testDynamicDictionaries\x0a\x09self assert: #{'hello' -> 1} asDictionary equals: (Dictionary with: 'hello' -> 1)",
-messageSends: ["assert:equals:", "asDictionary", "->", "with:"],
+messageSends: ["assert:equals:", "asDictionary", "with:", "->"],
 referencedClasses: ["Dictionary"]
 }),
 globals.DictionaryTest);
@@ -3482,20 +3413,13 @@ selector: "collection",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$1;
-$2="b".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$3="a".__minus_gt((2));
-$ctx1.sendIdx["->"]=2;
-$4="c".__minus_gt((3));
-$ctx1.sendIdx["->"]=3;
-$1=globals.HashedCollection._from_([$2,$3,$4,"d".__minus_gt((-4))]);
+var $1;
+$1=globals.HashedCollection._newFromPairs_(["b",(1),"a",(2),"c",(3),"d",(-4)]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"collection",{},globals.HashedCollectionTest)})},
+},
 args: [],
 source: "collection\x0a\x09^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4 }",
-messageSends: ["->"],
+messageSends: [],
 referencedClasses: []
 }),
 globals.HashedCollectionTest);
@@ -3523,20 +3447,13 @@ selector: "collectionOfPrintStrings",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$1;
-$2="b".__minus_gt("1");
-$ctx1.sendIdx["->"]=1;
-$3="a".__minus_gt("2");
-$ctx1.sendIdx["->"]=2;
-$4="c".__minus_gt("3");
-$ctx1.sendIdx["->"]=3;
-$1=globals.HashedCollection._from_([$2,$3,$4,"d".__minus_gt("-4")]);
+var $1;
+$1=globals.HashedCollection._newFromPairs_(["b","1","a","2","c","3","d","-4"]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"collectionOfPrintStrings",{},globals.HashedCollectionTest)})},
+},
 args: [],
 source: "collectionOfPrintStrings\x0a\x09^ #{ 'b' -> '1'. 'a' -> '2'. 'c' -> '3'. 'd' -> '-4' }",
-messageSends: ["->"],
+messageSends: [],
 referencedClasses: []
 }),
 globals.HashedCollectionTest);
@@ -3579,26 +3496,13 @@ selector: "collectionWithDuplicates",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$5,$6,$7,$1;
-$2="b".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$3="a".__minus_gt((2));
-$ctx1.sendIdx["->"]=2;
-$4="c".__minus_gt((3));
-$ctx1.sendIdx["->"]=3;
-$5="d".__minus_gt((-4));
-$ctx1.sendIdx["->"]=4;
-$6="e".__minus_gt((1));
-$ctx1.sendIdx["->"]=5;
-$7="f".__minus_gt((2));
-$ctx1.sendIdx["->"]=6;
-$1=globals.HashedCollection._from_([$2,$3,$4,$5,$6,$7,"g".__minus_gt((10))]);
+var $1;
+$1=globals.HashedCollection._newFromPairs_(["b",(1),"a",(2),"c",(3),"d",(-4),"e",(1),"f",(2),"g",(10)]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"collectionWithDuplicates",{},globals.HashedCollectionTest)})},
+},
 args: [],
 source: "collectionWithDuplicates\x0a\x09^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4. 'e' -> 1. 'f' -> 2. 'g' -> 10 }",
-messageSends: ["->"],
+messageSends: [],
 referencedClasses: []
 }),
 globals.HashedCollectionTest);
@@ -3609,22 +3513,13 @@ selector: "collectionWithNewValue",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$5,$1;
-$2="b".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$3="a".__minus_gt((2));
-$ctx1.sendIdx["->"]=2;
-$4="c".__minus_gt((3));
-$ctx1.sendIdx["->"]=3;
-$5="d".__minus_gt((-4));
-$ctx1.sendIdx["->"]=4;
-$1=globals.HashedCollection._from_([$2,$3,$4,$5,"new".__minus_gt("N")]);
+var $1;
+$1=globals.HashedCollection._newFromPairs_(["b",(1),"a",(2),"c",(3),"d",(-4),"new","N"]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"collectionWithNewValue",{},globals.HashedCollectionTest)})},
+},
 args: [],
 source: "collectionWithNewValue\x0a\x09^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4. 'new' -> 'N' }",
-messageSends: ["->"],
+messageSends: [],
 referencedClasses: []
 }),
 globals.HashedCollectionTest);
@@ -3635,14 +3530,13 @@ selector: "sampleNewValueAsCollection",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=globals.HashedCollection._from_(["new".__minus_gt("N")]);
+$1=globals.HashedCollection._newFromPairs_(["new","N"]);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"sampleNewValueAsCollection",{},globals.HashedCollectionTest)})},
+},
 args: [],
 source: "sampleNewValueAsCollection\x0a\x09^ #{ 'new' -> 'N' }",
-messageSends: ["->"],
+messageSends: [],
 referencedClasses: []
 }),
 globals.HashedCollectionTest);
@@ -3655,16 +3549,11 @@ fn: function (){
 var self=this;
 function $HashedCollection(){return globals.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1;
-$3="hello".__minus_gt((1));
-$ctx1.sendIdx["->"]=1;
-$2=globals.HashedCollection._from_([$3]);
-$1=_st($2)._asHashedCollection();
-self._assert_equals_($1,_st($HashedCollection())._with_("hello".__minus_gt((1))));
+self._assert_equals_(_st(globals.HashedCollection._newFromPairs_(["hello",(1)]))._asHashedCollection(),_st($HashedCollection())._with_("hello".__minus_gt((1))));
 return self}, function($ctx1) {$ctx1.fill(self,"testDynamicDictionaries",{},globals.HashedCollectionTest)})},
 args: [],
 source: "testDynamicDictionaries\x0a\x09self assert: #{'hello' -> 1} asHashedCollection equals: (HashedCollection with: 'hello' -> 1)",
-messageSends: ["assert:equals:", "asHashedCollection", "->", "with:"],
+messageSends: ["assert:equals:", "asHashedCollection", "with:", "->"],
 referencedClasses: ["HashedCollection"]
 }),
 globals.HashedCollectionTest);
@@ -4498,12 +4387,12 @@ fn: function (){
 var self=this;
 var array;
 return smalltalk.withContext(function($ctx1) { 
-array=[(3), (1), (4), (5), (2)];
+array=[(10), (1), (5)];
 _st(array)._sort();
-self._assert_equals_(array,[(1), (2), (3), (4), (5)]);
+self._assert_equals_(array,[(1), (5), (10)]);
 return self}, function($ctx1) {$ctx1.fill(self,"testSort",{array:array},globals.ArrayTest)})},
 args: [],
-source: "testSort\x0a\x09| array |\x0a\x09array := #(3 1 4 5 2). \x0a\x09array sort.\x0a\x09self assert: array equals: #(1 2 3 4 5)",
+source: "testSort\x0a\x09| array |\x0a\x09array := #(10 1 5). \x0a\x09array sort.\x0a\x09self assert: array equals: #(1 5 10)",
 messageSends: ["sort", "assert:equals:"],
 referencedClasses: []
 }),
@@ -4851,9 +4740,8 @@ return smalltalk.withContext(function($ctx1) {
 self._should_raise_((function(){
 return smalltalk.withContext(function($ctx2) {
 return "hello"._at_ifAbsentPut_((6),(function(){
-return smalltalk.withContext(function($ctx3) {
 return "a";
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
 return self}, function($ctx1) {$ctx1.fill(self,"testAtIfAbsentPut",{},globals.StringTest)})},
 args: [],
@@ -5003,8 +4891,7 @@ $ctx1.sendIdx["="]=1;
 self._deny_($1);
 $ctx1.sendIdx["deny:"]=1;
 $2="hello".__eq([]._at_ifAbsent_((1),(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})));
+})));
 $ctx1.sendIdx["="]=2;
 self._deny_($2);
 $ctx1.sendIdx["deny:"]=2;
@@ -5807,30 +5694,26 @@ return smalltalk.withContext(function($ctx1) {
 var $1,$2,$3;
 testObject=self._jsObject();
 $1=_st(testObject)._at_ifAbsent_("abc",(function(){
-return smalltalk.withContext(function($ctx2) {
 return "Property does not exist";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["at:ifAbsent:"]=1;
 self._assert_equals_($1,"Property does not exist");
 $ctx1.sendIdx["assert:equals:"]=1;
 $2=_st(testObject)._at_ifAbsent_("e",(function(){
-return smalltalk.withContext(function($ctx2) {
 return "Property does not exist";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["at:ifAbsent:"]=2;
 self._assert_equals_($2,nil);
 $ctx1.sendIdx["assert:equals:"]=2;
 $3=_st(testObject)._at_ifAbsent_("a",(function(){
-return smalltalk.withContext(function($ctx2) {
 return "Property does not exist";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+}));
 $ctx1.sendIdx["at:ifAbsent:"]=3;
 self._assert_equals_($3,(1));
 $ctx1.sendIdx["assert:equals:"]=3;
 self._assert_equals_(_st(testObject)._at_ifAbsent_("f",(function(){
-return smalltalk.withContext(function($ctx2) {
 return "Property does not exist";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})})),nil);
+})),nil);
 return self}, function($ctx1) {$ctx1.fill(self,"testAtIfAbsent",{testObject:testObject},globals.JSObjectProxyTest)})},
 args: [],
 source: "testAtIfAbsent\x0a\x09| testObject |\x0a\x09testObject := self jsObject.\x0a\x09self assert: (testObject at: 'abc' ifAbsent: [ 'Property does not exist' ]) equals: 'Property does not exist'.\x0a\x09self assert: (testObject at: 'e' ifAbsent: [ 'Property does not exist' ]) equals: nil.\x0a\x09self assert: (testObject at: 'a' ifAbsent: [ 'Property does not exist' ]) equals: 1.\x0a\x09self assert: (testObject at: 'f' ifAbsent: [ 'Property does not exist' ]) equals: nil.",
@@ -5908,9 +5791,8 @@ $ctx2.sendIdx["asString"]=1;
 return "hello ".__comma($2);
 $ctx2.sendIdx[","]=1;
 }, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return "not present";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["at:ifPresent:ifAbsent:"]=1;
 self._assert_equals_($1,"not present");
 $ctx1.sendIdx["assert:equals:"]=1;
@@ -5921,9 +5803,8 @@ $ctx2.sendIdx["asString"]=2;
 return "hello ".__comma($4);
 $ctx2.sendIdx[","]=2;
 }, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,3)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return "not present";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+}));
 $ctx1.sendIdx["at:ifPresent:ifAbsent:"]=2;
 self._assert_equals_($3,"hello nil");
 $ctx1.sendIdx["assert:equals:"]=2;
@@ -5934,9 +5815,8 @@ $ctx2.sendIdx["asString"]=3;
 return "hello ".__comma($6);
 $ctx2.sendIdx[","]=3;
 }, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,5)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return "not present";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,6)})}));
+}));
 $ctx1.sendIdx["at:ifPresent:ifAbsent:"]=3;
 self._assert_equals_($5,"hello 1");
 $ctx1.sendIdx["assert:equals:"]=3;
@@ -5944,9 +5824,8 @@ self._assert_equals_(_st(testObject)._at_ifPresent_ifAbsent_("f",(function(x){
 return smalltalk.withContext(function($ctx2) {
 return "hello ".__comma(_st(x)._asString());
 }, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,7)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
 return "not present";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,8)})})),"hello nil");
+})),"hello nil");
 return self}, function($ctx1) {$ctx1.fill(self,"testAtIfPresentIfAbsent",{testObject:testObject},globals.JSObjectProxyTest)})},
 args: [],
 source: "testAtIfPresentIfAbsent\x0a\x09| testObject |\x0a\x09testObject := self jsObject.\x0a\x09self assert: (testObject at: 'abc' ifPresent: [ :x|'hello ',x asString ] ifAbsent: [ 'not present' ]) equals: 'not present'.\x0a\x09self assert: (testObject at: 'e' ifPresent: [ :x|'hello ',x asString ] ifAbsent: [ 'not present' ]) equals: 'hello nil'.\x0a\x09self assert: (testObject at: 'a' ifPresent: [ :x|'hello ',x asString ] ifAbsent: [ 'not present' ]) equals: 'hello 1'.\x0a\x09self assert: (testObject at: 'f' ifPresent: [ :x|'hello ',x asString ] ifAbsent: [ 'not present' ]) equals: 'hello nil'.",
@@ -6643,22 +6522,19 @@ _st((function(){
 return smalltalk.withContext(function($ctx2) {
 return self._deinstallTop();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}));
 $ctx1.sendIdx["on:do:"]=1;
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
 return self._deinstallMiddle();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}))._on_do_($Error(),(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+}));
 $ctx1.sendIdx["on:do:"]=2;
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
 return self._deinstallBottom();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}))._on_do_($Error(),(function(){
-return smalltalk.withContext(function($ctx2) {
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,6)})}));
+}));
 return self}, function($ctx1) {$ctx1.fill(self,"tearDown",{},globals.MethodInheritanceTest)})},
 args: [],
 source: "tearDown\x0a\x09[ self deinstallTop ] on: Error do: [ ].\x0a\x09[ self deinstallMiddle ] on: Error do: [ ].\x0a\x09[ self deinstallBottom ] on: Error do: [ ]",
@@ -7762,9 +7638,8 @@ function $Object(){return globals.Object||(typeof Object=="undefined"?nil:Object
 return smalltalk.withContext(function($ctx1) { 
 o=_st($Object())._new();
 _st(o)._basicAt_put_("func",(function(){
-return smalltalk.withContext(function($ctx2) {
 return "hello";
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+}));
 $ctx1.sendIdx["basicAt:put:"]=1;
 _st(o)._basicAt_put_("func2",(function(a){
 return smalltalk.withContext(function($ctx2) {

+ 9 - 10
st/Kernel-Tests.st → js/Kernel-Tests.st

@@ -108,17 +108,16 @@ testExceptionSemantics
 
 testNewWithValues
 <
-	function theTestPrototype() {this.name = "theTestPrototype";}
-	function theTestConstructor(arg1, arg2, arg3) {}
-	theTestConstructor.prototype = new theTestPrototype;
+	function TestConstructor(arg1, arg2, arg3) {}
+	TestConstructor.prototype.name = 'theTestPrototype';
 
-	var theWrappedConstructor = _st(theTestConstructor);
-	var theResult = theWrappedConstructor._newWithValues_([1, 2, 3 ]);
-	self._assert_equals_(Object.getPrototypeOf(theResult).name, 'theTestPrototype');
+	var wrappedConstructor = _st(TestConstructor);
+	var result = wrappedConstructor._newWithValues_([1, 2, 3 ]);
+	self._assert_(result instanceof TestConstructor);
+	self._assert_equals_(result.name, 'theTestPrototype');
 
 	"newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made."
-	function constructionShouldFail() {var anotherResult = theWrappedConstructor._newWithValues_('This is so wrong');}
-	self._should_raise_(_st(constructionShouldFail), globals.Error);
+	self._should_raise_(function () {wrappedConstructor._newWithValues_('single argument');}, globals.Error);
 >
 !
 
@@ -1263,9 +1262,9 @@ testReversed
 
 testSort
 	| array |
-	array := #(3 1 4 5 2). 
+	array := #(10 1 5). 
 	array sort.
-	self assert: array equals: #(1 2 3 4 5)
+	self assert: array equals: #(1 5 10)
 ! !
 
 !ArrayTest class methodsFor: 'fixture'!

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


+ 2 - 4
js/SUnit-Tests.js

@@ -407,16 +407,14 @@ return smalltalk.withContext(function($ctx1) {
 self._should_raise_((function(){
 return smalltalk.withContext(function($ctx2) {
 return self._async_((function(){
-return smalltalk.withContext(function($ctx3) {
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}));
 $ctx2.sendIdx["async:"]=1;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
 self._timeout_((0));
 self._shouldnt_raise_((function(){
 return smalltalk.withContext(function($ctx2) {
 return self._async_((function(){
-return smalltalk.withContext(function($ctx3) {
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,4)})}));
+}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}),$Error());
 self._finished();
 return self}, function($ctx1) {$ctx1.fill(self,"testAsyncNeedsTimeout",{},globals.SUnitAsyncTest)})},

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


+ 2 - 4
js/SUnit.js

@@ -321,9 +321,8 @@ return smalltalk.withContext(function($ctx2) {
 _st(aBlock)._value();
 return false;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_(anExceptionClass,(function(ex){
-return smalltalk.withContext(function($ctx2) {
 return true;
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})})));
+})));
 return self}, function($ctx1) {$ctx1.fill(self,"should:raise:",{aBlock:aBlock,anExceptionClass:anExceptionClass},globals.TestCase)})},
 args: ["aBlock", "anExceptionClass"],
 source: "should: aBlock raise: anExceptionClass\x0a\x09self assert: ([ aBlock value. false ]\x0a\x09\x09on: anExceptionClass\x0a\x09\x09do: [ :ex | true ])",
@@ -344,9 +343,8 @@ return smalltalk.withContext(function($ctx2) {
 _st(aBlock)._value();
 return true;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_(anExceptionClass,(function(ex){
-return smalltalk.withContext(function($ctx2) {
 return false;
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})})));
+})));
 return self}, function($ctx1) {$ctx1.fill(self,"shouldnt:raise:",{aBlock:aBlock,anExceptionClass:anExceptionClass},globals.TestCase)})},
 args: ["aBlock", "anExceptionClass"],
 source: "shouldnt: aBlock raise: anExceptionClass\x0a\x09self assert: ([ aBlock value. true ]\x0a\x09\x09on: anExceptionClass\x0a\x09\x09do: [ :ex | false ])",

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


+ 2 - 4
js/Spaces.js

@@ -264,8 +264,7 @@ self._deny_(_st(self["@space"])._isConnected());
 self._should_raise_((function(){
 return smalltalk.withContext(function($ctx2) {
 return _st(self["@space"])._do_((function(){
-return smalltalk.withContext(function($ctx3) {
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$ObjectSpaceConnectionError());
 return self}, function($ctx1) {$ctx1.fill(self,"testConnection",{},globals.ObjectSpaceTest)})},
 args: [],
@@ -306,9 +305,8 @@ var $2,$1;
 _st(self["@space"])._whenReadyDo_((function(){
 return smalltalk.withContext(function($ctx2) {
 result=_st(self["@space"])._do_((function(){
-return smalltalk.withContext(function($ctx3) {
 return smalltalk;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+}));
 result;
 $2=_st(result)._class();
 $ctx2.sendIdx["class"]=1;

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


+ 3 - 3
package.json

@@ -33,12 +33,12 @@
     "test": "grunt amberc:amber_test_runner && node ./test/amber_test_runner.js"
   },
   "dependencies": {
-    "es6-promise": "~0.1.1"
+    "es6-promise": "~0.1.1",
+    "amdefine": "0.0.8"
   },
   "devDependencies": {
     "pegjs": "~0.8.0",
     "grunt": "~0.4.0",
-    "grunt-contrib-jshint": "~0.3.0",
-    "amdefine": "0.0.8"
+    "grunt-contrib-jshint": "~0.3.0"
   }
 }

+ 3 - 3
support/amber.js

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

+ 3 - 4
support/boot.js

@@ -93,6 +93,7 @@ define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (requ
 	}
 
 	var globals = {};
+    globals.SmalltalkSettings = {};
 	var api = Object.create(globals);
 	var brikz = new Brikz(api);
 
@@ -880,6 +881,8 @@ define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (requ
 				} catch(error) {
 					handleError(error);
 					st.thisContext = null;
+					// Rethrow the error in any case.
+					throw error;
 				}
 			}
 		};
@@ -935,10 +938,6 @@ define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (requ
 				error = wrappedError(error);
 			}
 			globals.ErrorHandler._handleError_(error);
-			// Throw the exception anyway, as we want to stop
-			// the execution to avoid infinite loops
-			// Update: do not throw the exception. It's really annoying.
-			// throw error;
 		}
 
 		/* Handle thisContext pseudo variable */

+ 37 - 7
support/helpers.js

@@ -1,6 +1,10 @@
 define("amber/helpers", ["amber_vm/smalltalk", "amber_vm/globals", "require"], function (vm, globals, require) {
     var exports = Object.create(globals);
 
+    var storage = (function (global) {
+        return 'localStorage' in global && global.localStorage;
+    })(new Function('return this')());
+
     // API
 
     exports.popupHelios = function () {
@@ -14,6 +18,39 @@ define("amber/helpers", ["amber_vm/smalltalk", "amber_vm/globals", "require"], f
         value: globals,
         enumerable: true, configurable: true, writable: false
     });
+    exports.initialize = function (options) {
+        var settings = globals.SmalltalkSettings;
+        function mixinToSettings(source) {
+            Object.keys(source).forEach(function (key) {
+                settings[key] = source[key];
+            });
+        }
+        settings['transport.defaultAmdNamespace'] = vm.defaultAmdNamespace;
+        if (storage) {
+            var fromStorage;
+            try {
+                fromStorage = JSON.parse(storage.getItem('amber.SmalltalkSettings'));
+            } catch (ex) {
+                // pass
+            }
+            mixinToSettings(fromStorage || {});
+            if (typeof window !== "undefined") {
+                requirejs(['jquery'], function ($) {
+                    $(window).on('beforeunload', function () {
+                       storage.setItem('amber.SmalltalkSettings', JSON.stringify(globals.SmalltalkSettings));
+                    });
+                });
+            }
+        }
+        if (exports.defaultAmdNamespace) {
+            console.warn("`smalltalk.defaultAmdNamespace = 'namespace';` is deprecated. Please use `smalltalk.initialize({'transport.defaultAmdNamespace': 'namespace'});` instead.");
+            settings['transport.defaultAmdNamespace'] = settings['transport.defaultAmdNamespace'] || exports.defaultAmdNamespace;
+        }
+        mixinToSettings(options || {});
+        console.warn("smalltalk.ClassName is deprecated. Please use smalltalk.globals.ClassName instead.");
+        globals.SmalltalkSettings = settings;
+        return vm.initialize();
+    };
 
     // Backward compatibility, deprecated
 
@@ -22,13 +59,6 @@ define("amber/helpers", ["amber_vm/smalltalk", "amber_vm/globals", "require"], f
         enumerable: true, configurable: true, writable: false
     });
     exports.defaultAmdNamespace = null;
-    exports.initialize = function () {
-        console.warn("smalltalk.defaultAmdNamespace is deprecated. Please use smalltalk.vm.defaultAmdNamespace instead.");
-        console.warn("smalltalk.initialize is deprecated. Please  use smalltalk.vm.initialize instead.");
-        console.warn("smalltalk.ClassName is deprecated. Please  use smalltalk.globals.ClassName instead.");
-        vm.defaultAmdNamespace = exports.defaultAmdNamespace || vm.defaultAmdNamespace;
-        return vm.initialize();
-    };
 
     // Exports
 

+ 189 - 64
support/parser.js

@@ -170,13 +170,7 @@ globals.SmalltalkParser = (function() {
         peg$c83 = function(selector, arg) {return [selector, [arg]];},
         peg$c84 = function(selector) {return [selector, []];},
         peg$c85 = function(expression) {return expression;},
-        peg$c86 = function(first, others) {
-                             var result = [first];
-                             for(var i = 0; i < others.length; i++) {
-                                 result.push(others[i]);
-                             }
-                             return result;
-                         },
+        peg$c86 = function(first, others) { return [first].concat(others); },
         peg$c87 = ":=",
         peg$c88 = { type: "literal", value: ":=", description: "\":=\"" },
         peg$c89 = function(variable, expression) {
@@ -323,6 +317,9 @@ globals.SmalltalkParser = (function() {
                                      ._arguments_(pattern[1])
                                      ._nodes_([sequence]);
                          },
+        peg$c136 = function(send) { return send._selector() === "->" },
+        peg$c137 = function(send) { return [send._receiver(), send._arguments()[0]]; },
+        peg$c138 = function(first, others) { return first.concat.apply(first, others); },
 
         peg$currPos          = 0,
         peg$reportedPos      = 0,
@@ -494,7 +491,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsestart() {
       var s0;
 
-      var key    = peg$currPos * 56 + 0,
+      var key    = peg$currPos * 59 + 0,
           cached = peg$cache[key];
 
       if (cached) {
@@ -512,7 +509,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseseparator() {
       var s0, s1;
 
-      var key    = peg$currPos * 56 + 1,
+      var key    = peg$currPos * 59 + 1,
           cached = peg$cache[key];
 
       if (cached) {
@@ -551,7 +548,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsecomments() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 2,
+      var key    = peg$currPos * 59 + 2,
           cached = peg$cache[key];
 
       if (cached) {
@@ -676,7 +673,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsews() {
       var s0, s1;
 
-      var key    = peg$currPos * 56 + 3,
+      var key    = peg$currPos * 59 + 3,
           cached = peg$cache[key];
 
       if (cached) {
@@ -705,7 +702,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseidentifier() {
       var s0, s1, s2, s3;
 
-      var key    = peg$currPos * 56 + 4,
+      var key    = peg$currPos * 59 + 4,
           cached = peg$cache[key];
 
       if (cached) {
@@ -761,7 +758,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsekeyword() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 5,
+      var key    = peg$currPos * 59 + 5,
           cached = peg$cache[key];
 
       if (cached) {
@@ -800,7 +797,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseselector() {
       var s0, s1, s2, s3;
 
-      var key    = peg$currPos * 56 + 6,
+      var key    = peg$currPos * 59 + 6,
           cached = peg$cache[key];
 
       if (cached) {
@@ -856,7 +853,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseclassName() {
       var s0, s1, s2, s3;
 
-      var key    = peg$currPos * 56 + 7,
+      var key    = peg$currPos * 59 + 7,
           cached = peg$cache[key];
 
       if (cached) {
@@ -912,7 +909,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsestring() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 8,
+      var key    = peg$currPos * 59 + 8,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1010,7 +1007,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsesymbol() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 9,
+      var key    = peg$currPos * 59 + 9,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1049,7 +1046,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebareSymbol() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 10,
+      var key    = peg$currPos * 59 + 10,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1085,7 +1082,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsenumber() {
       var s0, s1;
 
-      var key    = peg$currPos * 56 + 11,
+      var key    = peg$currPos * 59 + 11,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1118,7 +1115,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsenumberExp() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 12,
+      var key    = peg$currPos * 59 + 12,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1171,7 +1168,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsehex() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 13,
+      var key    = peg$currPos * 59 + 13,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1246,7 +1243,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsefloat() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 14,
+      var key    = peg$currPos * 59 + 14,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1348,7 +1345,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseinteger() {
       var s0, s1, s2, s3;
 
-      var key    = peg$currPos * 56 + 15,
+      var key    = peg$currPos * 59 + 15,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1411,7 +1408,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseliteralArray() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 16,
+      var key    = peg$currPos * 59 + 16,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1450,7 +1447,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebareLiteralArray() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 17,
+      var key    = peg$currPos * 59 + 17,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1489,7 +1486,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseliteralArrayRest() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 18,
+      var key    = peg$currPos * 59 + 18,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1587,7 +1584,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsedynamicArray() {
       var s0, s1, s2, s3, s4, s5, s6;
 
-      var key    = peg$currPos * 56 + 19,
+      var key    = peg$currPos * 59 + 19,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1668,7 +1665,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsedynamicDictionary() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 20,
+      var key    = peg$currPos * 59 + 20,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1687,7 +1684,7 @@ globals.SmalltalkParser = (function() {
       if (s1 !== peg$FAILED) {
         s2 = peg$parsews();
         if (s2 !== peg$FAILED) {
-          s3 = peg$parseexpressions();
+          s3 = peg$parseassociations();
           if (s3 === peg$FAILED) {
             s3 = peg$c37;
           }
@@ -1734,7 +1731,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsepseudoVariable() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 21,
+      var key    = peg$currPos * 59 + 21,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1800,7 +1797,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseparseTimeLiteral() {
       var s0;
 
-      var key    = peg$currPos * 56 + 22,
+      var key    = peg$currPos * 59 + 22,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1830,7 +1827,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseruntimeLiteral() {
       var s0;
 
-      var key    = peg$currPos * 56 + 23,
+      var key    = peg$currPos * 59 + 23,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1854,7 +1851,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseliteral() {
       var s0;
 
-      var key    = peg$currPos * 56 + 24,
+      var key    = peg$currPos * 59 + 24,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1875,7 +1872,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsevariable() {
       var s0, s1;
 
-      var key    = peg$currPos * 56 + 25,
+      var key    = peg$currPos * 59 + 25,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1899,7 +1896,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsekeywordPair() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 26,
+      var key    = peg$currPos * 59 + 26,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1944,7 +1941,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebinarySelector() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 27,
+      var key    = peg$currPos * 59 + 27,
           cached = peg$cache[key];
 
       if (cached) {
@@ -1989,7 +1986,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsekeywordPattern() {
       var s0, s1, s2, s3, s4, s5, s6;
 
-      var key    = peg$currPos * 56 + 28,
+      var key    = peg$currPos * 59 + 28,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2076,7 +2073,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebinaryPattern() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 29,
+      var key    = peg$currPos * 59 + 29,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2121,7 +2118,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseunaryPattern() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 30,
+      var key    = peg$currPos * 59 + 30,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2154,7 +2151,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseexpression() {
       var s0;
 
-      var key    = peg$currPos * 56 + 31,
+      var key    = peg$currPos * 59 + 31,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2181,7 +2178,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseexpressionList() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 32,
+      var key    = peg$currPos * 59 + 32,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2232,7 +2229,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseexpressions() {
       var s0, s1, s2, s3;
 
-      var key    = peg$currPos * 56 + 33,
+      var key    = peg$currPos * 59 + 33,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2270,7 +2267,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseassignment() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 34,
+      var key    = peg$currPos * 59 + 34,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2327,7 +2324,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseret() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 35,
+      var key    = peg$currPos * 59 + 35,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2393,7 +2390,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsetemps() {
       var s0, s1, s2, s3, s4, s5, s6;
 
-      var key    = peg$currPos * 56 + 36,
+      var key    = peg$currPos * 59 + 36,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2491,7 +2488,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseblockParamList() {
       var s0, s1, s2, s3, s4, s5, s6;
 
-      var key    = peg$currPos * 56 + 37,
+      var key    = peg$currPos * 59 + 37,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2611,7 +2608,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsesubexpression() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 38,
+      var key    = peg$currPos * 59 + 38,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2674,7 +2671,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsestatements() {
       var s0, s1, s2, s3, s4, s5, s6, s7;
 
-      var key    = peg$currPos * 56 + 39,
+      var key    = peg$currPos * 59 + 39,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2842,7 +2839,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsesequence() {
       var s0;
 
-      var key    = peg$currPos * 56 + 40,
+      var key    = peg$currPos * 59 + 40,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2863,7 +2860,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsestSequence() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 41,
+      var key    = peg$currPos * 59 + 41,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2914,7 +2911,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseblock() {
       var s0, s1, s2, s3, s4, s5, s6, s7;
 
-      var key    = peg$currPos * 56 + 42,
+      var key    = peg$currPos * 59 + 42,
           cached = peg$cache[key];
 
       if (cached) {
@@ -2995,7 +2992,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseoperand() {
       var s0;
 
-      var key    = peg$currPos * 56 + 43,
+      var key    = peg$currPos * 59 + 43,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3019,7 +3016,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseunaryMessage() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 44,
+      var key    = peg$currPos * 59 + 44,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3073,7 +3070,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseunaryTail() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 45,
+      var key    = peg$currPos * 59 + 45,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3121,7 +3118,7 @@ globals.SmalltalkParser = (function() {
     function peg$parseunarySend() {
       var s0, s1, s2, s3;
 
-      var key    = peg$currPos * 56 + 46,
+      var key    = peg$currPos * 59 + 46,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3163,7 +3160,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebinaryMessage() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 47,
+      var key    = peg$currPos * 59 + 47,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3211,7 +3208,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebinaryTail() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 48,
+      var key    = peg$currPos * 59 + 48,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3247,7 +3244,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsebinarySend() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 49,
+      var key    = peg$currPos * 59 + 49,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3283,7 +3280,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsekeywordMessage() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 50,
+      var key    = peg$currPos * 59 + 50,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3355,7 +3352,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsekeywordSend() {
       var s0, s1, s2;
 
-      var key    = peg$currPos * 56 + 51,
+      var key    = peg$currPos * 59 + 51,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3388,7 +3385,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsemessage() {
       var s0;
 
-      var key    = peg$currPos * 56 + 52,
+      var key    = peg$currPos * 59 + 52,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3412,7 +3409,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsecascade() {
       var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
 
-      var key    = peg$currPos * 56 + 53,
+      var key    = peg$currPos * 59 + 53,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3541,7 +3538,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsejsStatement() {
       var s0, s1, s2, s3, s4;
 
-      var key    = peg$currPos * 56 + 54,
+      var key    = peg$currPos * 59 + 54,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3639,7 +3636,7 @@ globals.SmalltalkParser = (function() {
     function peg$parsemethod() {
       var s0, s1, s2, s3, s4, s5;
 
-      var key    = peg$currPos * 56 + 55,
+      var key    = peg$currPos * 59 + 55,
           cached = peg$cache[key];
 
       if (cached) {
@@ -3696,6 +3693,134 @@ globals.SmalltalkParser = (function() {
       return s0;
     }
 
+    function peg$parseassociationSend() {
+      var s0, s1, s2;
+
+      var key    = peg$currPos * 59 + 56,
+          cached = peg$cache[key];
+
+      if (cached) {
+        peg$currPos = cached.nextPos;
+        return cached.result;
+      }
+
+      s0 = peg$currPos;
+      s1 = peg$parsebinarySend();
+      if (s1 !== peg$FAILED) {
+        peg$reportedPos = peg$currPos;
+        s2 = peg$c136(s1);
+        if (s2) {
+          s2 = peg$c112;
+        } else {
+          s2 = peg$c1;
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c137(s1);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c1;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c1;
+      }
+
+      peg$cache[key] = { nextPos: peg$currPos, result: s0 };
+
+      return s0;
+    }
+
+    function peg$parseassociationList() {
+      var s0, s1, s2, s3, s4;
+
+      var key    = peg$currPos * 59 + 57,
+          cached = peg$cache[key];
+
+      if (cached) {
+        peg$currPos = cached.nextPos;
+        return cached.result;
+      }
+
+      s0 = peg$currPos;
+      s1 = peg$parsews();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 46) {
+          s2 = peg$c47;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c48); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsews();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseassociationSend();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c85(s4);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c1;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c1;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c1;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c1;
+      }
+
+      peg$cache[key] = { nextPos: peg$currPos, result: s0 };
+
+      return s0;
+    }
+
+    function peg$parseassociations() {
+      var s0, s1, s2, s3;
+
+      var key    = peg$currPos * 59 + 58,
+          cached = peg$cache[key];
+
+      if (cached) {
+        peg$currPos = cached.nextPos;
+        return cached.result;
+      }
+
+      s0 = peg$currPos;
+      s1 = peg$parseassociationSend();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$parseassociationList();
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$parseassociationList();
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c138(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c1;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c1;
+      }
+
+      peg$cache[key] = { nextPos: peg$currPos, result: s0 };
+
+      return s0;
+    }
+
     peg$result = peg$startRuleFunction();
 
     if (peg$result !== peg$FAILED && peg$currPos === input.length) {

+ 8 - 8
support/parser.pegjs

@@ -47,7 +47,7 @@ dynamicArray   = "{" ws expressions:expressions? ws "."? "}" {
                             ._source_(text())
                             ._nodes_(expressions || []);
                  }
-dynamicDictionary = "#{" ws expressions: expressions? ws "}" {
+dynamicDictionary = "#{" ws expressions: associations? ws "}" {
                         return globals.DynamicDictionaryNode._new()
                                ._position_((line()).__at(column()))
                                ._source_(text())
@@ -99,13 +99,7 @@ unaryPattern   = ws selector:unarySelector {return [selector, []];}
 expression     = assignment / cascade / keywordSend / binarySend
 
 expressionList = ws "." ws expression:expression {return expression;}
-expressions    = first:expression others:expressionList* {
-                     var result = [first];
-                     for(var i = 0; i < others.length; i++) {
-                         result.push(others[i]);
-                     }
-                     return result;
-                 }
+expressions    = first:expression others:expressionList* { return [first].concat(others); }
 
 assignment     = variable:variable ws ':=' ws expression:expression {
                      return globals.AssignmentNode._new()
@@ -263,3 +257,9 @@ method         = ws pattern:(keywordPattern / binaryPattern / unaryPattern) ws s
                              ._nodes_([sequence]);
                  }
 
+
+associationSend     = send:binarySend & { return send._selector() === "->" } { return [send._receiver(), send._arguments()[0]]; }
+
+associationList = ws "." ws expression:associationSend {return expression;}
+associations    = first:associationSend others:associationList* { return first.concat.apply(first, others); }
+

Неке датотеке нису приказане због велике количине промена