YAYYYyyy giatn refactor

This commit is contained in:
Peter Cottle 2012-12-27 14:48:04 -08:00
parent 171e4c8351
commit d497bea70c
7 changed files with 654 additions and 451 deletions

View file

@ -10996,7 +10996,7 @@ var Errors = require('../util/errors');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
var GitOptionParser = GitCommands.GitOptionParser; var GitOptionParser = GitCommands.GitOptionParser;
var sandboxInstantCommands = require('../level/sandboxCommands').sandboxInstantCommands; var ParseWaterfall = require('../level/parseWaterfall').ParseWaterfall;
var CommandProcessError = Errors.CommandProcessError; var CommandProcessError = Errors.CommandProcessError;
var GitError = Errors.GitError; var GitError = Errors.GitError;
@ -11008,38 +11008,47 @@ var Command = Backbone.Model.extend({
status: 'inqueue', status: 'inqueue',
rawStr: null, rawStr: null,
result: '', result: '',
createTime: null,
error: null, error: null,
warnings: null, warnings: null,
parseWaterfall: new ParseWaterfall(),
generalArgs: null, generalArgs: null,
supportedMap: null, supportedMap: null,
options: null, options: null,
method: null, method: null
createTime: null
}, },
validateAtInit: function() { initialize: function(options) {
// weird things happen with defaults if you dont this.initDefaults();
// make new objects this.validateAtInit();
this.set('generalArgs', []);
this.set('supportedMap', {});
this.set('warnings', []);
if (this.get('rawStr') === null) {
throw new Error('Give me a string!');
}
if (!this.get('createTime')) {
this.set('createTime', new Date().toString());
}
this.on('change:error', this.errorChanged, this); this.on('change:error', this.errorChanged, this);
// catch errors on init // catch errors on init
if (this.get('error')) { if (this.get('error')) {
this.errorChanged(); this.errorChanged();
} }
this.parseOrCatch();
},
initDefaults: function() {
// weird things happen with defaults if you dont
// make new objects
this.set('generalArgs', []);
this.set('supportedMap', {});
this.set('warnings', []);
},
validateAtInit: function() {
if (this.get('rawStr') === null) {
throw new Error('Give me a string!');
}
if (!this.get('createTime')) {
this.set('createTime', new Date().toString());
}
}, },
setResult: function(msg) { setResult: function(msg) {
@ -11061,19 +11070,26 @@ var Command = Backbone.Model.extend({
return '<p>' + i + this.get('warnings').join('</p><p>' + i) + '</p>'; return '<p>' + i + this.get('warnings').join('</p><p>' + i) + '</p>';
}, },
initialize: function() {
this.validateAtInit();
this.parseOrCatch();
},
parseOrCatch: function() { parseOrCatch: function() {
this.expandShortcuts(this.get('rawStr'));
try { try {
this.parse(); this.processInstants();
} catch (err) { } catch (err) {
Errors.filterError(err); Errors.filterError(err);
// errorChanged() will handle status and all of that // errorChanged() will handle status and all of that
this.set('error', err); this.set('error', err);
} }
if (this.parseAll()) {
// something in our parse waterfall succeeded
return;
}
// if we reach here, this command is not supported :-/
this.set('error', new CommandProcessError({
msg: 'The command "' + this.get('rawStr') + '" isn\'t supported, sorry!'
})
);
}, },
errorChanged: function() { errorChanged: function() {
@ -11093,65 +11109,35 @@ var Command = Backbone.Model.extend({
this.set('result', this.get('error').toResult()); this.set('result', this.get('error').toResult());
}, },
parse: function() { expandShortcuts: function(str) {
str = this.get('parseWaterfall').expandAllShortcuts(str);
this.set('rawStr', str);
},
processInstants: function() {
var str = this.get('rawStr'); var str = this.get('rawStr');
// first if the string is empty, they just want a blank line // first if the string is empty, they just want a blank line
if (!str.length) { if (!str.length) {
throw new CommandResult({msg: ""}); throw new CommandResult({msg: ""});
} }
str = GitCommands.expandShortcut(str); // then instant commands that will throw
this.set('rawStr', str); this.get('parseWaterfall').processAllInstants(str);
// then check if it's one of our sandbox commands
_.each(sandboxInstantCommands, function(tuple) {
var regex = tuple[0];
var results = regex.exec(str);
if (results) {
// this will throw a result
tuple[1](results);
}
});
// see if begins with git
if (str.slice(0,3) !== 'git') {
throw new CommandProcessError({
msg: 'That command is not supported, sorry!'
});
}
// ok, we have a (probably) valid command. actually parse it
this.gitParse(str);
}, },
gitParse: function(str) { parseAll: function() {
// now slice off command part var str = this.get('rawStr');
var fullCommand = str.slice('git '.length); var results = this.get('parseWaterfall').parseAll(str);
// see if we support this particular command if (!results) {
_.each(GitCommands.getRegexMap(), function(regex, method) { // nothing parsed successfully
if (regex.exec(fullCommand)) { return false;
this.set('options', fullCommand.slice(method.length + 1));
this.set('method', method);
// we should stop iterating, but the regex will only match
// one command in practice. we could stop iterating if we used
// jqeurys for each but im using underscore (for no real reason other
// than style)
}
}, this);
if (!this.get('method')) {
throw new CommandProcessError({
msg: "Sorry, this demo does not support that git command: " + fullCommand
});
} }
// parse off the options and assemble the map / general args _.each(results.toSet, function(obj, key) {
var options = new GitOptionParser(this.get('method'), this.get('options')); this.set(key, obj);
}, this);
// steal these away so we can be completely JSON return true;
this.set('generalArgs', options.generalArgs);
this.set('supportedMap', options.supportedMap);
} }
}); });
@ -11177,44 +11163,92 @@ var GitError = Errors.GitError;
var Warning = Errors.Warning; var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult; var CommandResult = Errors.CommandResult;
var getRegexMap = function() { var shortcutMap = {
return { 'git commit': /^gc($|\s)/,
// ($|\s) means that we either have to end the string 'git add': /^ga($|\s)/,
// after the command or there needs to be a space for options 'git checkout': /^go($|\s)/,
commit: /^commit($|\s)/, 'git rebase': /^gr($|\s)/,
add: /^add($|\s)/, 'git branch': /^gb($|\s)/,
checkout: /^checkout($|\s)/, 'git status': /^gs($|\s)/,
rebase: /^rebase($|\s)/, 'git help': /^git$/
reset: /^reset($|\s)/,
branch: /^branch($|\s)/,
revert: /^revert($|\s)/,
log: /^log($|\s)/,
merge: /^merge($|\s)/,
show: /^show($|\s)/,
status: /^status($|\s)/,
'cherry-pick': /^cherry-pick($|\s)/
};
}; };
var getShortcutMap = function() { var instantCommands = [
return { [/^git help($|\s)/, function() {
'git commit': /^gc($|\s)/, var lines = [
'git add': /^ga($|\s)/, 'Git Version PCOTTLE.1.0',
'git checkout': /^go($|\s)/, '<br/>',
'git rebase': /^gr($|\s)/, 'Usage:',
'git branch': /^gb($|\s)/, _.escape('\t git <command> [<args>]'),
'git status': /^gs($|\s)/ '<br/>',
}; 'Supported commands:',
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
// format and throw
var msg = lines.join('\n');
msg = msg.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
throw new CommandResult({
msg: msg
});
}]
];
var regexMap = {
// ($|\s) means that we either have to end the string
// after the command or there needs to be a space for options
commit: /^commit($|\s)/,
add: /^add($|\s)/,
checkout: /^checkout($|\s)/,
rebase: /^rebase($|\s)/,
reset: /^reset($|\s)/,
branch: /^branch($|\s)/,
revert: /^revert($|\s)/,
log: /^log($|\s)/,
merge: /^merge($|\s)/,
show: /^show($|\s)/,
status: /^status($|\s)/,
'cherry-pick': /^cherry-pick($|\s)/
}; };
var expandShortcut = function(commandStr) { var parse = function(str) {
_.each(getShortcutMap(), function(regex, method) { // now slice off command part
var results = regex.exec(commandStr); var fullCommand = str.slice('git '.length);
if (results) { var method;
commandStr = method + ' ' + commandStr.slice(results[0].length); var options;
// see if we support this particular command
_.each(regexMap, function(regex, thisMethod) {
if (regex.exec(fullCommand)) {
options = fullCommand.slice(thisMethod.length + 1);
method = thisMethod;
} }
}); }, this);
return commandStr;
if (!method) {
return false;
}
// we support this command!
// parse off the options and assemble the map / general args
var parsedOptions = new GitOptionParser(method, options);
return {
toSet: {
generalArgs: parsedOptions.generalArgs,
supportedMap: parsedOptions.supportedMap,
method: method,
options: options
}
};
}; };
/** /**
@ -11305,13 +11339,85 @@ GitOptionParser.prototype.explodeAndSet = function() {
} }
}; };
exports.getRegexMap = getRegexMap; exports.shortcutMap = shortcutMap;
exports.expandShortcut = expandShortcut; exports.instantCommands = instantCommands;
exports.GitOptionParser = GitOptionParser; exports.parse = parse;
exports.regexMap = regexMap;
}); });
require.define("/src/js/level/sandboxCommands.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore'); require.define("/src/js/level/parseWaterfall.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var GitCommands = require('../git/commands');
var SandboxCommands = require('../level/SandboxCommands');
// more or less a static class
function ParseWaterfall(options) {
this.shortcutWaterfall = [
GitCommands.shortcutMap
];
this.instantWaterfall = [
GitCommands.instantCommands,
SandboxCommands.instantCommands
];
this.parseWaterfall = [
GitCommands.parse
];
}
ParseWaterfall.prototype.expandAllShortcuts = function(commandStr) {
_.each(this.shortcutWaterfall, function(shortcutMap) {
commandStr = this.expandShortcut(commandStr, shortcutMap);
}, this);
return commandStr;
};
ParseWaterfall.prototype.expandShortcut = function(commandStr, shortcutMap) {
_.each(shortcutMap, function(regex, method) {
var results = regex.exec(commandStr);
if (results) {
commandStr = method + ' ' + commandStr.slice(results[0].length);
}
});
return commandStr;
};
ParseWaterfall.prototype.processAllInstants = function(commandStr) {
_.each(this.instantWaterfall, function(instantCommands) {
this.processInstant(commandStr, instantCommands);
}, this);
};
ParseWaterfall.prototype.processInstant = function(commandStr, instantCommands) {
_.each(instantCommands, function(tuple) {
var regex = tuple[0];
var results = regex.exec(commandStr);
if (results) {
// this will throw a result
tuple[1](results);
}
});
};
ParseWaterfall.prototype.parseAll = function(commandStr) {
var toReturn = false;
_.each(this.parseWaterfall, function(parseFunc) {
var results = parseFunc(commandStr);
if (results) {
toReturn = results;
}
}, this);
return toReturn;
};
exports.ParseWaterfall = ParseWaterfall;
});
require.define("/src/js/level/SandboxCommands.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
var GitOptionParser = GitCommands.GitOptionParser; var GitOptionParser = GitCommands.GitOptionParser;
@ -11322,7 +11428,7 @@ var GitError = Errors.GitError;
var Warning = Errors.Warning; var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult; var CommandResult = Errors.CommandResult;
var sandboxInstantCommands = [ var instantCommands = [
[/^ls/, function() { [/^ls/, function() {
throw new CommandResult({ throw new CommandResult({
msg: "DontWorryAboutFilesInThisDemo.txt" msg: "DontWorryAboutFilesInThisDemo.txt"
@ -11333,45 +11439,6 @@ var sandboxInstantCommands = [
msg: "Directory Changed to '/directories/dont/matter/in/this/demo'" msg: "Directory Changed to '/directories/dont/matter/in/this/demo'"
}); });
}], }],
[/^git help($|\s)/, function() {
// sym link this to the blank git command
var allCommands = Command.prototype.getSandboxCommands();
// wow this is hacky :(
var equivalent = 'git';
_.each(allCommands, function(bits) {
var regex = bits[0];
if (regex.test(equivalent)) {
bits[1]();
}
});
}],
[/^git$/, function() {
var lines = [
'Git Version PCOTTLE.1.0',
'<br/>',
'Usage:',
_.escape('\t git <command> [<args>]'),
'<br/>',
'Supported commands:',
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
// format and throw
var msg = lines.join('\n');
msg = msg.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
throw new CommandResult({
msg: msg
});
}],
[/^refresh$/, function() { [/^refresh$/, function() {
var events = require('../app').getEvents(); var events = require('../app').getEvents();
@ -11391,7 +11458,7 @@ var sandboxInstantCommands = [
}] }]
]; ];
exports.sandboxInstantCommands = sandboxInstantCommands; exports.instantCommands = instantCommands;
}); });
@ -13776,7 +13843,6 @@ exports.VisEdge = VisEdge;
}); });
require.define("/src/js/level/inputWaterfall.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore'); require.define("/src/js/level/inputWaterfall.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var Backbone = require('backbone');
var Main = require('../app'); var Main = require('../app');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
@ -13832,6 +13898,7 @@ InputWaterfall.prototype.checkDisabledMap = function(command) {
try { try {
this.loopDisabledMap(command); this.loopDisabledMap(command);
} catch(err) { } catch(err) {
Errors.filterError(err);
command.set('error', err); command.set('error', err);
return true; return true;
} }
@ -13841,7 +13908,7 @@ InputWaterfall.prototype.checkDisabledMap = function(command) {
InputWaterfall.prototype.loopDisabledMap = function(command) { InputWaterfall.prototype.loopDisabledMap = function(command) {
var toTest = this.sliceGitOff(command.get('rawStr')); var toTest = this.sliceGitOff(command.get('rawStr'));
var regexMap = GitCommands.getRegexMap(); var regexMap = GitCommands.regexMap;
_.each(this.disabledMap, function(val, disabledGitCommand) { _.each(this.disabledMap, function(val, disabledGitCommand) {
disabledGitCommand = this.sliceGitOff(disabledGitCommand); disabledGitCommand = this.sliceGitOff(disabledGitCommand);
@ -14201,44 +14268,92 @@ var GitError = Errors.GitError;
var Warning = Errors.Warning; var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult; var CommandResult = Errors.CommandResult;
var getRegexMap = function() { var shortcutMap = {
return { 'git commit': /^gc($|\s)/,
// ($|\s) means that we either have to end the string 'git add': /^ga($|\s)/,
// after the command or there needs to be a space for options 'git checkout': /^go($|\s)/,
commit: /^commit($|\s)/, 'git rebase': /^gr($|\s)/,
add: /^add($|\s)/, 'git branch': /^gb($|\s)/,
checkout: /^checkout($|\s)/, 'git status': /^gs($|\s)/,
rebase: /^rebase($|\s)/, 'git help': /^git$/
reset: /^reset($|\s)/,
branch: /^branch($|\s)/,
revert: /^revert($|\s)/,
log: /^log($|\s)/,
merge: /^merge($|\s)/,
show: /^show($|\s)/,
status: /^status($|\s)/,
'cherry-pick': /^cherry-pick($|\s)/
};
}; };
var getShortcutMap = function() { var instantCommands = [
return { [/^git help($|\s)/, function() {
'git commit': /^gc($|\s)/, var lines = [
'git add': /^ga($|\s)/, 'Git Version PCOTTLE.1.0',
'git checkout': /^go($|\s)/, '<br/>',
'git rebase': /^gr($|\s)/, 'Usage:',
'git branch': /^gb($|\s)/, _.escape('\t git <command> [<args>]'),
'git status': /^gs($|\s)/ '<br/>',
}; 'Supported commands:',
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
// format and throw
var msg = lines.join('\n');
msg = msg.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
throw new CommandResult({
msg: msg
});
}]
];
var regexMap = {
// ($|\s) means that we either have to end the string
// after the command or there needs to be a space for options
commit: /^commit($|\s)/,
add: /^add($|\s)/,
checkout: /^checkout($|\s)/,
rebase: /^rebase($|\s)/,
reset: /^reset($|\s)/,
branch: /^branch($|\s)/,
revert: /^revert($|\s)/,
log: /^log($|\s)/,
merge: /^merge($|\s)/,
show: /^show($|\s)/,
status: /^status($|\s)/,
'cherry-pick': /^cherry-pick($|\s)/
}; };
var expandShortcut = function(commandStr) { var parse = function(str) {
_.each(getShortcutMap(), function(regex, method) { // now slice off command part
var results = regex.exec(commandStr); var fullCommand = str.slice('git '.length);
if (results) { var method;
commandStr = method + ' ' + commandStr.slice(results[0].length); var options;
// see if we support this particular command
_.each(regexMap, function(regex, thisMethod) {
if (regex.exec(fullCommand)) {
options = fullCommand.slice(thisMethod.length + 1);
method = thisMethod;
} }
}); }, this);
return commandStr;
if (!method) {
return false;
}
// we support this command!
// parse off the options and assemble the map / general args
var parsedOptions = new GitOptionParser(method, options);
return {
toSet: {
generalArgs: parsedOptions.generalArgs,
supportedMap: parsedOptions.supportedMap,
method: method,
options: options
}
};
}; };
/** /**
@ -14329,9 +14444,10 @@ GitOptionParser.prototype.explodeAndSet = function() {
} }
}; };
exports.getRegexMap = getRegexMap; exports.shortcutMap = shortcutMap;
exports.expandShortcut = expandShortcut; exports.instantCommands = instantCommands;
exports.GitOptionParser = GitOptionParser; exports.parse = parse;
exports.regexMap = regexMap;
}); });
require("/src/js/git/commands.js"); require("/src/js/git/commands.js");
@ -16194,7 +16310,6 @@ exports.TreeCompare = TreeCompare;
require("/src/js/git/treeCompare.js"); require("/src/js/git/treeCompare.js");
require.define("/src/js/level/inputWaterfall.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore'); require.define("/src/js/level/inputWaterfall.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var Backbone = require('backbone');
var Main = require('../app'); var Main = require('../app');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
@ -16250,6 +16365,7 @@ InputWaterfall.prototype.checkDisabledMap = function(command) {
try { try {
this.loopDisabledMap(command); this.loopDisabledMap(command);
} catch(err) { } catch(err) {
Errors.filterError(err);
command.set('error', err); command.set('error', err);
return true; return true;
} }
@ -16259,7 +16375,7 @@ InputWaterfall.prototype.checkDisabledMap = function(command) {
InputWaterfall.prototype.loopDisabledMap = function(command) { InputWaterfall.prototype.loopDisabledMap = function(command) {
var toTest = this.sliceGitOff(command.get('rawStr')); var toTest = this.sliceGitOff(command.get('rawStr'));
var regexMap = GitCommands.getRegexMap(); var regexMap = GitCommands.regexMap;
_.each(this.disabledMap, function(val, disabledGitCommand) { _.each(this.disabledMap, function(val, disabledGitCommand) {
disabledGitCommand = this.sliceGitOff(disabledGitCommand); disabledGitCommand = this.sliceGitOff(disabledGitCommand);
@ -16284,6 +16400,78 @@ exports.InputWaterfall = InputWaterfall;
}); });
require("/src/js/level/inputWaterfall.js"); require("/src/js/level/inputWaterfall.js");
require.define("/src/js/level/parseWaterfall.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var GitCommands = require('../git/commands');
var SandboxCommands = require('../level/SandboxCommands');
// more or less a static class
function ParseWaterfall(options) {
this.shortcutWaterfall = [
GitCommands.shortcutMap
];
this.instantWaterfall = [
GitCommands.instantCommands,
SandboxCommands.instantCommands
];
this.parseWaterfall = [
GitCommands.parse
];
}
ParseWaterfall.prototype.expandAllShortcuts = function(commandStr) {
_.each(this.shortcutWaterfall, function(shortcutMap) {
commandStr = this.expandShortcut(commandStr, shortcutMap);
}, this);
return commandStr;
};
ParseWaterfall.prototype.expandShortcut = function(commandStr, shortcutMap) {
_.each(shortcutMap, function(regex, method) {
var results = regex.exec(commandStr);
if (results) {
commandStr = method + ' ' + commandStr.slice(results[0].length);
}
});
return commandStr;
};
ParseWaterfall.prototype.processAllInstants = function(commandStr) {
_.each(this.instantWaterfall, function(instantCommands) {
this.processInstant(commandStr, instantCommands);
}, this);
};
ParseWaterfall.prototype.processInstant = function(commandStr, instantCommands) {
_.each(instantCommands, function(tuple) {
var regex = tuple[0];
var results = regex.exec(commandStr);
if (results) {
// this will throw a result
tuple[1](results);
}
});
};
ParseWaterfall.prototype.parseAll = function(commandStr) {
var toReturn = false;
_.each(this.parseWaterfall, function(parseFunc) {
var results = parseFunc(commandStr);
if (results) {
toReturn = results;
}
}, this);
return toReturn;
};
exports.ParseWaterfall = ParseWaterfall;
});
require("/src/js/level/parseWaterfall.js");
require.define("/src/js/level/sandboxCommands.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore'); require.define("/src/js/level/sandboxCommands.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
@ -16295,7 +16483,7 @@ var GitError = Errors.GitError;
var Warning = Errors.Warning; var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult; var CommandResult = Errors.CommandResult;
var sandboxInstantCommands = [ var instantCommands = [
[/^ls/, function() { [/^ls/, function() {
throw new CommandResult({ throw new CommandResult({
msg: "DontWorryAboutFilesInThisDemo.txt" msg: "DontWorryAboutFilesInThisDemo.txt"
@ -16306,45 +16494,6 @@ var sandboxInstantCommands = [
msg: "Directory Changed to '/directories/dont/matter/in/this/demo'" msg: "Directory Changed to '/directories/dont/matter/in/this/demo'"
}); });
}], }],
[/^git help($|\s)/, function() {
// sym link this to the blank git command
var allCommands = Command.prototype.getSandboxCommands();
// wow this is hacky :(
var equivalent = 'git';
_.each(allCommands, function(bits) {
var regex = bits[0];
if (regex.test(equivalent)) {
bits[1]();
}
});
}],
[/^git$/, function() {
var lines = [
'Git Version PCOTTLE.1.0',
'<br/>',
'Usage:',
_.escape('\t git <command> [<args>]'),
'<br/>',
'Supported commands:',
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
// format and throw
var msg = lines.join('\n');
msg = msg.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
throw new CommandResult({
msg: msg
});
}],
[/^refresh$/, function() { [/^refresh$/, function() {
var events = require('../app').getEvents(); var events = require('../app').getEvents();
@ -16364,7 +16513,7 @@ var sandboxInstantCommands = [
}] }]
]; ];
exports.sandboxInstantCommands = sandboxInstantCommands; exports.instantCommands = instantCommands;
}); });
require("/src/js/level/sandboxCommands.js"); require("/src/js/level/sandboxCommands.js");
@ -16486,7 +16635,7 @@ var Errors = require('../util/errors');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
var GitOptionParser = GitCommands.GitOptionParser; var GitOptionParser = GitCommands.GitOptionParser;
var sandboxInstantCommands = require('../level/sandboxCommands').sandboxInstantCommands; var ParseWaterfall = require('../level/parseWaterfall').ParseWaterfall;
var CommandProcessError = Errors.CommandProcessError; var CommandProcessError = Errors.CommandProcessError;
var GitError = Errors.GitError; var GitError = Errors.GitError;
@ -16498,38 +16647,47 @@ var Command = Backbone.Model.extend({
status: 'inqueue', status: 'inqueue',
rawStr: null, rawStr: null,
result: '', result: '',
createTime: null,
error: null, error: null,
warnings: null, warnings: null,
parseWaterfall: new ParseWaterfall(),
generalArgs: null, generalArgs: null,
supportedMap: null, supportedMap: null,
options: null, options: null,
method: null, method: null
createTime: null
}, },
validateAtInit: function() { initialize: function(options) {
// weird things happen with defaults if you dont this.initDefaults();
// make new objects this.validateAtInit();
this.set('generalArgs', []);
this.set('supportedMap', {});
this.set('warnings', []);
if (this.get('rawStr') === null) {
throw new Error('Give me a string!');
}
if (!this.get('createTime')) {
this.set('createTime', new Date().toString());
}
this.on('change:error', this.errorChanged, this); this.on('change:error', this.errorChanged, this);
// catch errors on init // catch errors on init
if (this.get('error')) { if (this.get('error')) {
this.errorChanged(); this.errorChanged();
} }
this.parseOrCatch();
},
initDefaults: function() {
// weird things happen with defaults if you dont
// make new objects
this.set('generalArgs', []);
this.set('supportedMap', {});
this.set('warnings', []);
},
validateAtInit: function() {
if (this.get('rawStr') === null) {
throw new Error('Give me a string!');
}
if (!this.get('createTime')) {
this.set('createTime', new Date().toString());
}
}, },
setResult: function(msg) { setResult: function(msg) {
@ -16551,19 +16709,26 @@ var Command = Backbone.Model.extend({
return '<p>' + i + this.get('warnings').join('</p><p>' + i) + '</p>'; return '<p>' + i + this.get('warnings').join('</p><p>' + i) + '</p>';
}, },
initialize: function() {
this.validateAtInit();
this.parseOrCatch();
},
parseOrCatch: function() { parseOrCatch: function() {
this.expandShortcuts(this.get('rawStr'));
try { try {
this.parse(); this.processInstants();
} catch (err) { } catch (err) {
Errors.filterError(err); Errors.filterError(err);
// errorChanged() will handle status and all of that // errorChanged() will handle status and all of that
this.set('error', err); this.set('error', err);
} }
if (this.parseAll()) {
// something in our parse waterfall succeeded
return;
}
// if we reach here, this command is not supported :-/
this.set('error', new CommandProcessError({
msg: 'The command "' + this.get('rawStr') + '" isn\'t supported, sorry!'
})
);
}, },
errorChanged: function() { errorChanged: function() {
@ -16583,65 +16748,35 @@ var Command = Backbone.Model.extend({
this.set('result', this.get('error').toResult()); this.set('result', this.get('error').toResult());
}, },
parse: function() { expandShortcuts: function(str) {
str = this.get('parseWaterfall').expandAllShortcuts(str);
this.set('rawStr', str);
},
processInstants: function() {
var str = this.get('rawStr'); var str = this.get('rawStr');
// first if the string is empty, they just want a blank line // first if the string is empty, they just want a blank line
if (!str.length) { if (!str.length) {
throw new CommandResult({msg: ""}); throw new CommandResult({msg: ""});
} }
str = GitCommands.expandShortcut(str); // then instant commands that will throw
this.set('rawStr', str); this.get('parseWaterfall').processAllInstants(str);
// then check if it's one of our sandbox commands
_.each(sandboxInstantCommands, function(tuple) {
var regex = tuple[0];
var results = regex.exec(str);
if (results) {
// this will throw a result
tuple[1](results);
}
});
// see if begins with git
if (str.slice(0,3) !== 'git') {
throw new CommandProcessError({
msg: 'That command is not supported, sorry!'
});
}
// ok, we have a (probably) valid command. actually parse it
this.gitParse(str);
}, },
gitParse: function(str) { parseAll: function() {
// now slice off command part var str = this.get('rawStr');
var fullCommand = str.slice('git '.length); var results = this.get('parseWaterfall').parseAll(str);
// see if we support this particular command if (!results) {
_.each(GitCommands.getRegexMap(), function(regex, method) { // nothing parsed successfully
if (regex.exec(fullCommand)) { return false;
this.set('options', fullCommand.slice(method.length + 1));
this.set('method', method);
// we should stop iterating, but the regex will only match
// one command in practice. we could stop iterating if we used
// jqeurys for each but im using underscore (for no real reason other
// than style)
}
}, this);
if (!this.get('method')) {
throw new CommandProcessError({
msg: "Sorry, this demo does not support that git command: " + fullCommand
});
} }
// parse off the options and assemble the map / general args _.each(results.toSet, function(obj, key) {
var options = new GitOptionParser(this.get('method'), this.get('options')); this.set(key, obj);
}, this);
// steal these away so we can be completely JSON return true;
this.set('generalArgs', options.generalArgs);
this.set('supportedMap', options.supportedMap);
} }
}); });

View file

@ -6,44 +6,92 @@ var GitError = Errors.GitError;
var Warning = Errors.Warning; var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult; var CommandResult = Errors.CommandResult;
var getRegexMap = function() { var shortcutMap = {
return { 'git commit': /^gc($|\s)/,
// ($|\s) means that we either have to end the string 'git add': /^ga($|\s)/,
// after the command or there needs to be a space for options 'git checkout': /^go($|\s)/,
commit: /^commit($|\s)/, 'git rebase': /^gr($|\s)/,
add: /^add($|\s)/, 'git branch': /^gb($|\s)/,
checkout: /^checkout($|\s)/, 'git status': /^gs($|\s)/,
rebase: /^rebase($|\s)/, 'git help': /^git$/
reset: /^reset($|\s)/,
branch: /^branch($|\s)/,
revert: /^revert($|\s)/,
log: /^log($|\s)/,
merge: /^merge($|\s)/,
show: /^show($|\s)/,
status: /^status($|\s)/,
'cherry-pick': /^cherry-pick($|\s)/
};
}; };
var getShortcutMap = function() { var instantCommands = [
return { [/^git help($|\s)/, function() {
'git commit': /^gc($|\s)/, var lines = [
'git add': /^ga($|\s)/, 'Git Version PCOTTLE.1.0',
'git checkout': /^go($|\s)/, '<br/>',
'git rebase': /^gr($|\s)/, 'Usage:',
'git branch': /^gb($|\s)/, _.escape('\t git <command> [<args>]'),
'git status': /^gs($|\s)/ '<br/>',
}; 'Supported commands:',
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
// format and throw
var msg = lines.join('\n');
msg = msg.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
throw new CommandResult({
msg: msg
});
}]
];
var regexMap = {
// ($|\s) means that we either have to end the string
// after the command or there needs to be a space for options
commit: /^commit($|\s)/,
add: /^add($|\s)/,
checkout: /^checkout($|\s)/,
rebase: /^rebase($|\s)/,
reset: /^reset($|\s)/,
branch: /^branch($|\s)/,
revert: /^revert($|\s)/,
log: /^log($|\s)/,
merge: /^merge($|\s)/,
show: /^show($|\s)/,
status: /^status($|\s)/,
'cherry-pick': /^cherry-pick($|\s)/
}; };
var expandShortcut = function(commandStr) { var parse = function(str) {
_.each(getShortcutMap(), function(regex, method) { // now slice off command part
var results = regex.exec(commandStr); var fullCommand = str.slice('git '.length);
if (results) { var method;
commandStr = method + ' ' + commandStr.slice(results[0].length); var options;
// see if we support this particular command
_.each(regexMap, function(regex, thisMethod) {
if (regex.exec(fullCommand)) {
options = fullCommand.slice(thisMethod.length + 1);
method = thisMethod;
} }
}); }, this);
return commandStr;
if (!method) {
return false;
}
// we support this command!
// parse off the options and assemble the map / general args
var parsedOptions = new GitOptionParser(method, options);
return {
toSet: {
generalArgs: parsedOptions.generalArgs,
supportedMap: parsedOptions.supportedMap,
method: method,
options: options
}
};
}; };
/** /**
@ -134,6 +182,7 @@ GitOptionParser.prototype.explodeAndSet = function() {
} }
}; };
exports.getRegexMap = getRegexMap; exports.shortcutMap = shortcutMap;
exports.expandShortcut = expandShortcut; exports.instantCommands = instantCommands;
exports.GitOptionParser = GitOptionParser; exports.parse = parse;
exports.regexMap = regexMap;

View file

@ -1,5 +1,4 @@
var _ = require('underscore'); var _ = require('underscore');
var Backbone = require('backbone');
var Main = require('../app'); var Main = require('../app');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
@ -55,6 +54,7 @@ InputWaterfall.prototype.checkDisabledMap = function(command) {
try { try {
this.loopDisabledMap(command); this.loopDisabledMap(command);
} catch(err) { } catch(err) {
Errors.filterError(err);
command.set('error', err); command.set('error', err);
return true; return true;
} }
@ -64,7 +64,7 @@ InputWaterfall.prototype.checkDisabledMap = function(command) {
InputWaterfall.prototype.loopDisabledMap = function(command) { InputWaterfall.prototype.loopDisabledMap = function(command) {
var toTest = this.sliceGitOff(command.get('rawStr')); var toTest = this.sliceGitOff(command.get('rawStr'));
var regexMap = GitCommands.getRegexMap(); var regexMap = GitCommands.regexMap;
_.each(this.disabledMap, function(val, disabledGitCommand) { _.each(this.disabledMap, function(val, disabledGitCommand) {
disabledGitCommand = this.sliceGitOff(disabledGitCommand); disabledGitCommand = this.sliceGitOff(disabledGitCommand);

View file

@ -0,0 +1,68 @@
var _ = require('underscore');
var GitCommands = require('../git/commands');
var SandboxCommands = require('../level/SandboxCommands');
// more or less a static class
function ParseWaterfall(options) {
this.shortcutWaterfall = [
GitCommands.shortcutMap
];
this.instantWaterfall = [
GitCommands.instantCommands,
SandboxCommands.instantCommands
];
this.parseWaterfall = [
GitCommands.parse
];
}
ParseWaterfall.prototype.expandAllShortcuts = function(commandStr) {
_.each(this.shortcutWaterfall, function(shortcutMap) {
commandStr = this.expandShortcut(commandStr, shortcutMap);
}, this);
return commandStr;
};
ParseWaterfall.prototype.expandShortcut = function(commandStr, shortcutMap) {
_.each(shortcutMap, function(regex, method) {
var results = regex.exec(commandStr);
if (results) {
commandStr = method + ' ' + commandStr.slice(results[0].length);
}
});
return commandStr;
};
ParseWaterfall.prototype.processAllInstants = function(commandStr) {
_.each(this.instantWaterfall, function(instantCommands) {
this.processInstant(commandStr, instantCommands);
}, this);
};
ParseWaterfall.prototype.processInstant = function(commandStr, instantCommands) {
_.each(instantCommands, function(tuple) {
var regex = tuple[0];
var results = regex.exec(commandStr);
if (results) {
// this will throw a result
tuple[1](results);
}
});
};
ParseWaterfall.prototype.parseAll = function(commandStr) {
var toReturn = false;
_.each(this.parseWaterfall, function(parseFunc) {
var results = parseFunc(commandStr);
if (results) {
toReturn = results;
}
}, this);
return toReturn;
};
exports.ParseWaterfall = ParseWaterfall;

View file

@ -9,7 +9,7 @@ var GitError = Errors.GitError;
var Warning = Errors.Warning; var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult; var CommandResult = Errors.CommandResult;
var sandboxInstantCommands = [ var instantCommands = [
[/^ls/, function() { [/^ls/, function() {
throw new CommandResult({ throw new CommandResult({
msg: "DontWorryAboutFilesInThisDemo.txt" msg: "DontWorryAboutFilesInThisDemo.txt"
@ -20,45 +20,6 @@ var sandboxInstantCommands = [
msg: "Directory Changed to '/directories/dont/matter/in/this/demo'" msg: "Directory Changed to '/directories/dont/matter/in/this/demo'"
}); });
}], }],
[/^git help($|\s)/, function() {
// sym link this to the blank git command
var allCommands = Command.prototype.getSandboxCommands();
// wow this is hacky :(
var equivalent = 'git';
_.each(allCommands, function(bits) {
var regex = bits[0];
if (regex.test(equivalent)) {
bits[1]();
}
});
}],
[/^git$/, function() {
var lines = [
'Git Version PCOTTLE.1.0',
'<br/>',
'Usage:',
_.escape('\t git <command> [<args>]'),
'<br/>',
'Supported commands:',
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
// format and throw
var msg = lines.join('\n');
msg = msg.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
throw new CommandResult({
msg: msg
});
}],
[/^refresh$/, function() { [/^refresh$/, function() {
var events = require('../app').getEvents(); var events = require('../app').getEvents();
@ -78,4 +39,4 @@ var sandboxInstantCommands = [
}] }]
]; ];
exports.sandboxInstantCommands = sandboxInstantCommands; exports.instantCommands = instantCommands;

View file

@ -6,7 +6,7 @@ var Errors = require('../util/errors');
var GitCommands = require('../git/commands'); var GitCommands = require('../git/commands');
var GitOptionParser = GitCommands.GitOptionParser; var GitOptionParser = GitCommands.GitOptionParser;
var sandboxInstantCommands = require('../level/sandboxCommands').sandboxInstantCommands; var ParseWaterfall = require('../level/parseWaterfall').ParseWaterfall;
var CommandProcessError = Errors.CommandProcessError; var CommandProcessError = Errors.CommandProcessError;
var GitError = Errors.GitError; var GitError = Errors.GitError;
@ -18,38 +18,47 @@ var Command = Backbone.Model.extend({
status: 'inqueue', status: 'inqueue',
rawStr: null, rawStr: null,
result: '', result: '',
createTime: null,
error: null, error: null,
warnings: null, warnings: null,
parseWaterfall: new ParseWaterfall(),
generalArgs: null, generalArgs: null,
supportedMap: null, supportedMap: null,
options: null, options: null,
method: null, method: null
createTime: null
}, },
validateAtInit: function() { initialize: function(options) {
// weird things happen with defaults if you dont this.initDefaults();
// make new objects this.validateAtInit();
this.set('generalArgs', []);
this.set('supportedMap', {});
this.set('warnings', []);
if (this.get('rawStr') === null) {
throw new Error('Give me a string!');
}
if (!this.get('createTime')) {
this.set('createTime', new Date().toString());
}
this.on('change:error', this.errorChanged, this); this.on('change:error', this.errorChanged, this);
// catch errors on init // catch errors on init
if (this.get('error')) { if (this.get('error')) {
this.errorChanged(); this.errorChanged();
} }
this.parseOrCatch();
},
initDefaults: function() {
// weird things happen with defaults if you dont
// make new objects
this.set('generalArgs', []);
this.set('supportedMap', {});
this.set('warnings', []);
},
validateAtInit: function() {
if (this.get('rawStr') === null) {
throw new Error('Give me a string!');
}
if (!this.get('createTime')) {
this.set('createTime', new Date().toString());
}
}, },
setResult: function(msg) { setResult: function(msg) {
@ -71,19 +80,26 @@ var Command = Backbone.Model.extend({
return '<p>' + i + this.get('warnings').join('</p><p>' + i) + '</p>'; return '<p>' + i + this.get('warnings').join('</p><p>' + i) + '</p>';
}, },
initialize: function() {
this.validateAtInit();
this.parseOrCatch();
},
parseOrCatch: function() { parseOrCatch: function() {
this.expandShortcuts(this.get('rawStr'));
try { try {
this.parse(); this.processInstants();
} catch (err) { } catch (err) {
Errors.filterError(err); Errors.filterError(err);
// errorChanged() will handle status and all of that // errorChanged() will handle status and all of that
this.set('error', err); this.set('error', err);
} }
if (this.parseAll()) {
// something in our parse waterfall succeeded
return;
}
// if we reach here, this command is not supported :-/
this.set('error', new CommandProcessError({
msg: 'The command "' + this.get('rawStr') + '" isn\'t supported, sorry!'
})
);
}, },
errorChanged: function() { errorChanged: function() {
@ -103,65 +119,35 @@ var Command = Backbone.Model.extend({
this.set('result', this.get('error').toResult()); this.set('result', this.get('error').toResult());
}, },
parse: function() { expandShortcuts: function(str) {
str = this.get('parseWaterfall').expandAllShortcuts(str);
this.set('rawStr', str);
},
processInstants: function() {
var str = this.get('rawStr'); var str = this.get('rawStr');
// first if the string is empty, they just want a blank line // first if the string is empty, they just want a blank line
if (!str.length) { if (!str.length) {
throw new CommandResult({msg: ""}); throw new CommandResult({msg: ""});
} }
str = GitCommands.expandShortcut(str); // then instant commands that will throw
this.set('rawStr', str); this.get('parseWaterfall').processAllInstants(str);
// then check if it's one of our sandbox commands
_.each(sandboxInstantCommands, function(tuple) {
var regex = tuple[0];
var results = regex.exec(str);
if (results) {
// this will throw a result
tuple[1](results);
}
});
// see if begins with git
if (str.slice(0,3) !== 'git') {
throw new CommandProcessError({
msg: 'That command is not supported, sorry!'
});
}
// ok, we have a (probably) valid command. actually parse it
this.gitParse(str);
}, },
gitParse: function(str) { parseAll: function() {
// now slice off command part var str = this.get('rawStr');
var fullCommand = str.slice('git '.length); var results = this.get('parseWaterfall').parseAll(str);
// see if we support this particular command if (!results) {
_.each(GitCommands.getRegexMap(), function(regex, method) { // nothing parsed successfully
if (regex.exec(fullCommand)) { return false;
this.set('options', fullCommand.slice(method.length + 1));
this.set('method', method);
// we should stop iterating, but the regex will only match
// one command in practice. we could stop iterating if we used
// jqeurys for each but im using underscore (for no real reason other
// than style)
}
}, this);
if (!this.get('method')) {
throw new CommandProcessError({
msg: "Sorry, this demo does not support that git command: " + fullCommand
});
} }
// parse off the options and assemble the map / general args _.each(results.toSet, function(obj, key) {
var options = new GitOptionParser(this.get('method'), this.get('options')); this.set(key, obj);
}, this);
// steal these away so we can be completely JSON return true;
this.set('generalArgs', options.generalArgs);
this.set('supportedMap', options.supportedMap);
} }
}); });

View file

@ -35,6 +35,10 @@ Big Bugs to fix:
Done things: Done things:
(I only started this on Dec 17th 2012 to get a better sense of what was done) (I only started this on Dec 17th 2012 to get a better sense of what was done)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[x] ok fuckit here is the deal. Command model has minimal logic -- it calls
to a parse waterfall that expands any shortcuts needed, handles any instant
commands, and then finally will handle the dispatching. I think this will be
really nice :D
[x] disabled map for levels [x] disabled map for levels
[x] better click events on branches and commits [x] better click events on branches and commits
[x] change to returning a promise for multiview [x] change to returning a promise for multiview