瀏覽代碼

fixed exception on empty line; generalised commands

Markus Kahl 11 年之前
父節點
當前提交
a367c87cc1
共有 3 個文件被更改,包括 198 次插入56 次删除
  1. 85 23
      cli/js/AmberCli.js
  2. 85 23
      cli/js/amber-cli.js
  3. 28 10
      cli/st/AmberCli.st

+ 85 - 23
cli/js/AmberCli.js

@@ -1116,7 +1116,7 @@ referencedClasses: []
 smalltalk.FileServer.klass);
 
 
-smalltalk.addClass('Repl', smalltalk.Object, ['readline', 'interface', 'util', 'session', 'resultCount'], 'AmberCli');
+smalltalk.addClass('Repl', smalltalk.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 smalltalk.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1183,6 +1183,27 @@ referencedClasses: []
 }),
 smalltalk.Repl);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "clearScreen",
+category: 'private',
+fn: function (){
+var self=this;
+var esc,cls;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+esc=_st($String())._fromCharCode_((27));
+cls=_st(_st(_st(esc).__comma("[2J")).__comma(esc)).__comma("[0;0f");
+_st(_st(process)._stdout())._write_(cls);
+_st(self["@interface"])._prompt();
+return self}, function($ctx1) {$ctx1.fill(self,"clearScreen",{esc:esc,cls:cls},smalltalk.Repl)})},
+args: [],
+source: "clearScreen\x0a\x09| esc cls |\x0a\x09esc := String fromCharCode: 27.\x0a\x09cls := esc, '[2J', esc, '[0;0f'.\x0a\x09process stdout write: cls.\x0a\x09interface prompt",
+messageSends: ["fromCharCode:", ",", "write:", "stdout", "prompt"],
+referencedClasses: ["String"]
+}),
+smalltalk.Repl);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "close",
@@ -1199,6 +1220,24 @@ referencedClasses: []
 }),
 smalltalk.Repl);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commands",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@commands"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"commands",{},smalltalk.Repl)})},
+args: [],
+source: "commands\x0a\x09^ commands",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Repl);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "createInterface",
@@ -1312,18 +1351,24 @@ category: 'private',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(aString).__eq(":q");
-if(smalltalk.assert($2)){
-$1=_st(process)._exit();
-} else {
-$1=false;
+var $1;
+var $early={};
+try {
+_st(self._commands())._keysAndValuesDo_((function(names,cmd){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(names)._includes_(aString);
+if(smalltalk.assert($1)){
+_st(cmd)._value();
+throw $early=[true];
 };
-return $1;
+}, function($ctx2) {$ctx2.fillBlock({names:names,cmd:cmd},$ctx1)})}));
+return false;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"executeCommand:",{aString:aString},smalltalk.Repl)})},
 args: ["aString"],
-source: "executeCommand: aString\x0a\x09\x22Tries to process the given string as a command. Returns true if it was a command, false if not.\x22\x0a\x09^ aString = ':q'\x0a\x09\x09ifTrue: [process exit]\x0a\x09\x09ifFalse: [false]",
-messageSends: ["ifTrue:ifFalse:", "exit", "="],
+source: "executeCommand: aString\x0a\x09\x22Tries to process the given string as a command. Returns true if it was a command, false if not.\x22\x0a\x09self commands keysAndValuesDo: [:names :cmd |\x0a\x09\x09(names includes: aString) ifTrue: [\x0a\x09\x09\x09cmd value.\x0a\x09\x09\x09^ true]].\x0a\x09^ false",
+messageSends: ["keysAndValuesDo:", "ifTrue:", "value", "includes:", "commands"],
 referencedClasses: []
 }),
 smalltalk.Repl);
@@ -1340,10 +1385,11 @@ smalltalk.Object.fn.prototype._initialize.apply(_st(self), []);
 self["@session"]=_st($DoIt())._new();
 self["@readline"]=_st(require)._value_("readline");
 self["@util"]=_st(require)._value_("util");
+self._setupCommands();
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.Repl)})},
 args: [],
-source: "initialize\x0a\x09super initialize.\x0a\x09session := DoIt new.\x0a\x09readline := require value: 'readline'.\x0a\x09util := require value: 'util'",
-messageSends: ["initialize", "new", "value:"],
+source: "initialize\x0a\x09super initialize.\x0a\x09session := DoIt new.\x0a\x09readline := require value: 'readline'.\x0a\x09util := require value: 'util'.\x0a\x09self setupCommands",
+messageSends: ["initialize", "new", "value:", "setupCommands"],
 referencedClasses: ["DoIt"]
 }),
 smalltalk.Repl);
@@ -1437,7 +1483,6 @@ selector: "onKeyPress:",
 category: 'private',
 fn: function (key){
 var self=this;
-function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=_st(_st(key)._ctrl())._and_((function(){
@@ -1445,19 +1490,13 @@ return smalltalk.withContext(function($ctx2) {
 return _st(_st(key)._name()).__eq("l");
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 if(smalltalk.assert($1)){
-var esc,cls;
-esc=_st($String())._fromCharCode_((27));
-esc;
-cls=_st(_st(_st(esc).__comma("[2J")).__comma(esc)).__comma("[0;0f");
-cls;
-_st(_st(process)._stdout())._write_(cls);
-_st(self["@interface"])._prompt();
+self._clearScreen();
 };
 return self}, function($ctx1) {$ctx1.fill(self,"onKeyPress:",{key:key},smalltalk.Repl)})},
 args: ["key"],
-source: "onKeyPress: key\x0a\x09(key ctrl and: [key name = 'l']) ifTrue: [ | esc cls |\x0a\x09\x09esc := String fromCharCode: 27.\x0a\x09\x09cls := esc, '[2J', esc, '[0;0f'.\x0a\x09\x09process stdout write: cls.\x0a\x09\x09interface prompt]",
-messageSends: ["ifTrue:", "fromCharCode:", ",", "write:", "stdout", "prompt", "and:", "=", "name", "ctrl"],
-referencedClasses: ["String"]
+source: "onKeyPress: key\x0a\x09(key ctrl and: [key name = 'l'])\x0a\x09\x09ifTrue: [self clearScreen]",
+messageSends: ["ifTrue:", "clearScreen", "and:", "=", "name", "ctrl"],
+referencedClasses: []
 }),
 smalltalk.Repl);
 
@@ -1616,6 +1655,29 @@ referencedClasses: []
 }),
 smalltalk.Repl);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "setupCommands",
+category: 'initialization',
+fn: function (){
+var self=this;
+function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
+return smalltalk.withContext(function($ctx1) { 
+self["@commands"]=_st($Dictionary())._from_([_st([":q"]).__minus_gt((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(process)._exit();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})})),_st([""]).__minus_gt((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self["@interface"])._prompt();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))]);
+return self}, function($ctx1) {$ctx1.fill(self,"setupCommands",{},smalltalk.Repl)})},
+args: [],
+source: "setupCommands\x0a\x09commands := Dictionary from: {\x0a\x09\x09{':q'} -> [process exit].\x0a\x09\x09{''} -> [interface prompt]}",
+messageSends: ["from:", "->", "exit", "prompt"],
+referencedClasses: ["Dictionary"]
+}),
+smalltalk.Repl);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "setupHotkeys",

+ 85 - 23
cli/js/amber-cli.js

@@ -35571,7 +35571,7 @@ referencedClasses: []
 smalltalk.FileServer.klass);
 
 
-smalltalk.addClass('Repl', smalltalk.Object, ['readline', 'interface', 'util', 'session', 'resultCount'], 'AmberCli');
+smalltalk.addClass('Repl', smalltalk.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 smalltalk.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -35638,6 +35638,27 @@ referencedClasses: []
 }),
 smalltalk.Repl);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "clearScreen",
+category: 'private',
+fn: function (){
+var self=this;
+var esc,cls;
+function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
+return smalltalk.withContext(function($ctx1) { 
+esc=_st($String())._fromCharCode_((27));
+cls=_st(_st(_st(esc).__comma("[2J")).__comma(esc)).__comma("[0;0f");
+_st(_st(process)._stdout())._write_(cls);
+_st(self["@interface"])._prompt();
+return self}, function($ctx1) {$ctx1.fill(self,"clearScreen",{esc:esc,cls:cls},smalltalk.Repl)})},
+args: [],
+source: "clearScreen\x0a\x09| esc cls |\x0a\x09esc := String fromCharCode: 27.\x0a\x09cls := esc, '[2J', esc, '[0;0f'.\x0a\x09process stdout write: cls.\x0a\x09interface prompt",
+messageSends: ["fromCharCode:", ",", "write:", "stdout", "prompt"],
+referencedClasses: ["String"]
+}),
+smalltalk.Repl);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "close",
@@ -35654,6 +35675,24 @@ referencedClasses: []
 }),
 smalltalk.Repl);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commands",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@commands"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"commands",{},smalltalk.Repl)})},
+args: [],
+source: "commands\x0a\x09^ commands",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Repl);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "createInterface",
@@ -35767,18 +35806,24 @@ category: 'private',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(aString).__eq(":q");
-if(smalltalk.assert($2)){
-$1=_st(process)._exit();
-} else {
-$1=false;
+var $1;
+var $early={};
+try {
+_st(self._commands())._keysAndValuesDo_((function(names,cmd){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(names)._includes_(aString);
+if(smalltalk.assert($1)){
+_st(cmd)._value();
+throw $early=[true];
 };
-return $1;
+}, function($ctx2) {$ctx2.fillBlock({names:names,cmd:cmd},$ctx1)})}));
+return false;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"executeCommand:",{aString:aString},smalltalk.Repl)})},
 args: ["aString"],
-source: "executeCommand: aString\x0a\x09\x22Tries to process the given string as a command. Returns true if it was a command, false if not.\x22\x0a\x09^ aString = ':q'\x0a\x09\x09ifTrue: [process exit]\x0a\x09\x09ifFalse: [false]",
-messageSends: ["ifTrue:ifFalse:", "exit", "="],
+source: "executeCommand: aString\x0a\x09\x22Tries to process the given string as a command. Returns true if it was a command, false if not.\x22\x0a\x09self commands keysAndValuesDo: [:names :cmd |\x0a\x09\x09(names includes: aString) ifTrue: [\x0a\x09\x09\x09cmd value.\x0a\x09\x09\x09^ true]].\x0a\x09^ false",
+messageSends: ["keysAndValuesDo:", "ifTrue:", "value", "includes:", "commands"],
 referencedClasses: []
 }),
 smalltalk.Repl);
@@ -35795,10 +35840,11 @@ smalltalk.Object.fn.prototype._initialize.apply(_st(self), []);
 self["@session"]=_st($DoIt())._new();
 self["@readline"]=_st(require)._value_("readline");
 self["@util"]=_st(require)._value_("util");
+self._setupCommands();
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.Repl)})},
 args: [],
-source: "initialize\x0a\x09super initialize.\x0a\x09session := DoIt new.\x0a\x09readline := require value: 'readline'.\x0a\x09util := require value: 'util'",
-messageSends: ["initialize", "new", "value:"],
+source: "initialize\x0a\x09super initialize.\x0a\x09session := DoIt new.\x0a\x09readline := require value: 'readline'.\x0a\x09util := require value: 'util'.\x0a\x09self setupCommands",
+messageSends: ["initialize", "new", "value:", "setupCommands"],
 referencedClasses: ["DoIt"]
 }),
 smalltalk.Repl);
@@ -35892,7 +35938,6 @@ selector: "onKeyPress:",
 category: 'private',
 fn: function (key){
 var self=this;
-function $String(){return smalltalk.String||(typeof String=="undefined"?nil:String)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 $1=_st(_st(key)._ctrl())._and_((function(){
@@ -35900,19 +35945,13 @@ return smalltalk.withContext(function($ctx2) {
 return _st(_st(key)._name()).__eq("l");
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 if(smalltalk.assert($1)){
-var esc,cls;
-esc=_st($String())._fromCharCode_((27));
-esc;
-cls=_st(_st(_st(esc).__comma("[2J")).__comma(esc)).__comma("[0;0f");
-cls;
-_st(_st(process)._stdout())._write_(cls);
-_st(self["@interface"])._prompt();
+self._clearScreen();
 };
 return self}, function($ctx1) {$ctx1.fill(self,"onKeyPress:",{key:key},smalltalk.Repl)})},
 args: ["key"],
-source: "onKeyPress: key\x0a\x09(key ctrl and: [key name = 'l']) ifTrue: [ | esc cls |\x0a\x09\x09esc := String fromCharCode: 27.\x0a\x09\x09cls := esc, '[2J', esc, '[0;0f'.\x0a\x09\x09process stdout write: cls.\x0a\x09\x09interface prompt]",
-messageSends: ["ifTrue:", "fromCharCode:", ",", "write:", "stdout", "prompt", "and:", "=", "name", "ctrl"],
-referencedClasses: ["String"]
+source: "onKeyPress: key\x0a\x09(key ctrl and: [key name = 'l'])\x0a\x09\x09ifTrue: [self clearScreen]",
+messageSends: ["ifTrue:", "clearScreen", "and:", "=", "name", "ctrl"],
+referencedClasses: []
 }),
 smalltalk.Repl);
 
@@ -36071,6 +36110,29 @@ referencedClasses: []
 }),
 smalltalk.Repl);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "setupCommands",
+category: 'initialization',
+fn: function (){
+var self=this;
+function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
+return smalltalk.withContext(function($ctx1) { 
+self["@commands"]=_st($Dictionary())._from_([_st([":q"]).__minus_gt((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(process)._exit();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})})),_st([""]).__minus_gt((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self["@interface"])._prompt();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))]);
+return self}, function($ctx1) {$ctx1.fill(self,"setupCommands",{},smalltalk.Repl)})},
+args: [],
+source: "setupCommands\x0a\x09commands := Dictionary from: {\x0a\x09\x09{':q'} -> [process exit].\x0a\x09\x09{''} -> [interface prompt]}",
+messageSends: ["from:", "->", "exit", "prompt"],
+referencedClasses: ["Dictionary"]
+}),
+smalltalk.Repl);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "setupHotkeys",

+ 28 - 10
cli/st/AmberCli.st

@@ -892,7 +892,7 @@ main
 ! !
 
 Object subclass: #Repl
-	instanceVariableNames: 'readline interface util session resultCount'
+	instanceVariableNames: 'readline interface util session resultCount commands'
 	package: 'AmberCli'!
 !Repl commentStamp!
 I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.
@@ -905,6 +905,10 @@ My runtime requirement is a functional Node.js executable with working Readline
 
 prompt
 	^'amber >> '
+!
+
+commands
+	^ commands
 ! !
 
 !Repl methodsFor: 'actions'!
@@ -947,11 +951,18 @@ initialize
 	super initialize.
 	session := DoIt new.
 	readline := require value: 'readline'.
-	util := require value: 'util'
+	util := require value: 'util'.
+	self setupCommands
 !
 
 setupHotkeys
 	process stdin on: 'keypress' do: [:s :key | key ifNotNil: [self onKeyPress: key]].
+!
+
+setupCommands
+	commands := Dictionary from: {
+		{':q'} -> [process exit].
+		{''} -> [interface prompt]}
 ! !
 
 !Repl methodsFor: 'private'!
@@ -986,9 +997,11 @@ encapsulateVariable: aString withValue: anObject in: aClass
 
 executeCommand: aString
 	"Tries to process the given string as a command. Returns true if it was a command, false if not."
-	^ aString = ':q'
-		ifTrue: [process exit]
-		ifFalse: [false]
+	self commands keysAndValuesDo: [:names :cmd |
+		(names includes: aString) ifTrue: [
+			cmd value.
+			^ true]].
+	^ false
 !
 
 instanceVariableNamesFor: aClass
@@ -1016,11 +1029,16 @@ nextResultName
 !
 
 onKeyPress: key
-	(key ctrl and: [key name = 'l']) ifTrue: [ | esc cls |
-		esc := String fromCharCode: 27.
-		cls := esc, '[2J', esc, '[0;0f'.
-		process stdout write: cls.
-		interface prompt]
+	(key ctrl and: [key name = 'l'])
+		ifTrue: [self clearScreen]
+!
+
+clearScreen
+	| esc cls |
+	esc := String fromCharCode: 27.
+	cls := esc, '[2J', esc, '[0;0f'.
+	process stdout write: cls.
+	interface prompt
 !
 
 parseAssignment: aString do: aBlock