big refactor looking a lot better now

This commit is contained in:
Peter Cottle 2013-07-28 12:12:00 -07:00
parent e422bdb181
commit 0aadae766f
12 changed files with 1539 additions and 1355 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

1
build/bundle.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -439,7 +439,7 @@
For a much easier time perusing the source, see the individual files at:
https://github.com/pcottle/learnGitBranching
-->
<script src="build/bundle.min.f16f04ad.js"></script>
<script src="build/bundle.js"></script>
<!-- The advantage of github pages: super-easy, simple, slick static hostic.
The downside? No raw logs to parse for analytics, so I have to include

View file

@ -7,8 +7,91 @@ var Errors = require('../util/errors');
var GitError = Errors.GitError;
var CommandResult = Errors.CommandResult;
var commandConfig;
var Commands = {
commit: function(engine, command) {
execute: function(name, engine, commandObj) {
if (!commandConfig[name]) {
throw new Error('i dont have a command for ' + name);
}
commandConfig[name].execute.call(this, engine, commandObj);
},
getRegex: function(name) {
name = name.replace(/-/g, ''); // ugh cherry-pick @____@
if (!commandConfig[name]) {
throw new Error('i dont have a regex for ' + name);
}
return commandConfig[name].regex;
},
isCommandSupported: function(name) {
return !!commandConfig[name];
},
getShortcutMap: function() {
var map = {};
this.loop(function(config, name) {
if (!config.sc) {
return;
}
map['git ' + name] = config.sc;
}, this);
return map;
},
getOptionMap: function() {
var optionMap = {};
this.loop(function(config, name) {
var displayName = config.displayName || name;
var thisMap = {};
// start all options off as disabled
_.each(config.options, function(option) {
thisMap[option] = false;
});
optionMap[displayName] = thisMap;
});
return optionMap;
},
getRegexMap: function() {
var map = {};
this.loop(function(config, name) {
var displayName = 'git ' + (config.displayName || name);
map[displayName] = config.regex;
});
return map;
},
/**
* which commands count for the git golf game
*/
getCommandsThatCount: function() {
var counted = [];
this.loop(function(config, name) {
if (config.dontCountForGolf) {
return;
}
counted.push(name);
});
return counted;
},
loop: function(callback, context) {
_.each(commandConfig, callback);
}
};
commandConfig = {
commit: {
sc: /^(gc|git ci)($|\s)/,
regex: /^git +commit($|\s)/,
options: [
'--amend',
'-a',
'-am',
'-m'
],
execute: function(engine, command) {
var commandOptions = command.getSupportedMap();
command.acceptNoGeneralArgs();
@ -54,9 +137,13 @@ var Commands = {
engine.gitVisuals
);
engine.animationQueue.thenFinish(promise);
}
},
cherrypick: function(engine, command) {
cherrypick: {
displayName: 'cherry-pick',
regex: /^git +cherry-pick($|\s)/,
execute: function(engine, command) {
var commandOptions = command.getSupportedMap();
var generalArgs = command.getGeneralArgs();
@ -79,9 +166,15 @@ var Commands = {
}, this);
engine.setupCherrypickChain(toCherrypick);
}
},
pull: function(engine, command) {
pull: {
regex: /^git +pull($|\s)/,
options: [
'--rebase'
],
execute: function(engine, command) {
if (!engine.hasOrigin()) {
throw new GitError({
msg: intl.str('git-error-origin-required')
@ -93,9 +186,12 @@ var Commands = {
engine.pull({
isRebase: commandOptions['--rebase']
});
}
},
fakeTeamwork: function(engine, command) {
fakeTeamwork: {
regex: /^git +fakeTeamwork($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
if (!engine.hasOrigin()) {
throw new GitError({
@ -118,14 +214,20 @@ var Commands = {
}
engine.fakeTeamwork(numToMake, branch);
}
},
clone: function(engine, command) {
clone: {
regex: /^git +clone *?$/,
execute: function(engine, command) {
command.acceptNoGeneralArgs();
engine.makeOrigin(engine.printTree());
}
},
fetch: function(engine, command) {
fetch: {
regex: /^git +fetch *?$/,
execute: function(engine, command) {
if (!engine.hasOrigin()) {
throw new GitError({
msg: intl.str('git-error-origin-required')
@ -133,9 +235,21 @@ var Commands = {
}
command.acceptNoGeneralArgs();
engine.fetch();
}
},
branch: function(engine, command) {
branch: {
sc: /^(gb|git br)($|\s)/,
regex: /^git +branch($|\s)/,
options: [
'-d',
'-D',
'-f',
'-a',
'-r',
'--contains'
],
execute: function(engine, command) {
var commandOptions = command.getSupportedMap();
var generalArgs = command.getGeneralArgs();
@ -183,15 +297,27 @@ var Commands = {
command.twoArgsImpliedHead(generalArgs);
engine.branch(generalArgs[0], generalArgs[1]);
}
},
add: function() {
add: {
dontCountForGolf: true,
sc: /^ga($|\s)/,
regex: /^git +add($|\s)/,
execute: function() {
throw new CommandResult({
msg: intl.str('git-error-staging')
});
}
},
reset: function(engine, command) {
reset: {
regex: /^git +reset($|\s)/,
options: [
'--hard',
'--soft'
],
execute: function(engine, command) {
var commandOptions = command.getSupportedMap();
var generalArgs = command.getGeneralArgs();
@ -217,16 +343,22 @@ var Commands = {
}
engine.reset(generalArgs[0]);
}
},
revert: function(engine, command) {
revert: {
regex: /^git +revert($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
command.validateArgBounds(generalArgs, 1, Number.MAX_VALUE);
engine.revert(generalArgs);
}
},
merge: function(engine, command) {
merge: {
regex: /^git +merge($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
command.validateArgBounds(generalArgs, 1, 1);
@ -243,9 +375,13 @@ var Commands = {
engine.animationFactory.genCommitBirthAnimation(
engine.animationQueue, newCommit, engine.gitVisuals
);
}
},
log: function(engine, command) {
log: {
dontCountForGolf: true,
regex: /^git +log($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
if (generalArgs.length == 2) {
@ -261,15 +397,26 @@ var Commands = {
command.oneArgImpliedHead(generalArgs);
engine.log(generalArgs[0]);
}
},
show: function(engine, command) {
show: {
dontCountForGolf: true,
regex: /^git +show($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
command.oneArgImpliedHead(generalArgs);
engine.show(generalArgs[0]);
}
},
rebase: function(engine, command) {
rebase: {
sc: /^gr($|\s)/,
options: [
'-i'
],
regex: /^git +rebase($|\s)/,
execute: function(engine, command) {
var commandOptions = command.getSupportedMap();
var generalArgs = command.getGeneralArgs();
@ -282,14 +429,28 @@ var Commands = {
command.twoArgsImpliedHead(generalArgs);
engine.rebase(generalArgs[0], generalArgs[1]);
}
},
status: function(engine) {
status: {
dontCountForGolf: true,
sc: /^(gst|gs|git st)($|\s)/,
regex: /^git +status($|\s)/,
execute: function(engine) {
// no parsing at all
engine.status();
}
},
checkout: function(engine, command) {
checkout: {
sc: /^(go|git co)($|\s)/,
regex: /^git +checkout($|\s)/,
options: [
'-b',
'-B',
'-'
],
execute: function(engine, command) {
var commandOptions = command.getSupportedMap();
var generalArgs = command.getGeneralArgs();
@ -335,9 +496,12 @@ var Commands = {
command.validateArgBounds(generalArgs, 1, 1);
engine.checkout(engine.crappyUnescape(generalArgs[0]));
}
},
push: function(engine, command) {
push: {
regex: /^git +push($|\s)/,
execute: function(engine, command) {
if (!engine.hasOrigin()) {
throw new GitError({
msg: intl.str('git-error-origin-required')
@ -345,9 +509,8 @@ var Commands = {
}
command.acceptNoGeneralArgs();
engine.push();
},
noComma: 123
}
}
};
module.exports = Commands;

View file

@ -1,24 +1,15 @@
var _ = require('underscore');
var intl = require('../intl');
var Commands = require('../commands');
var Errors = require('../util/errors');
var CommandProcessError = Errors.CommandProcessError;
var GitError = Errors.GitError;
var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult;
var shortcutMap = {
'git commit': /^(gc|git ci)($|\s)/,
'git add': /^ga($|\s)/,
'git checkout': /^(go|git co)($|\s)/,
'git rebase': /^gr($|\s)/,
'git branch': /^(gb|git br)($|\s)/,
'git status': /^(gst|gs|git st)($|\s)/,
'git help': /^git$/
};
var instantCommands = [
[/^git help($|\s)/, function() {
[/^(git help($|\s)|git$)/, function() {
var lines = [
intl.str('git-version'),
'<br/>',
@ -28,8 +19,7 @@ var instantCommands = [
intl.str('git-supported-commands'),
'<br/>'
];
var commands = GitOptionParser.prototype.getMasterOptionMap();
var commands = Commands.getOptionMap();
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
lines.push('git ' + command);
@ -47,59 +37,12 @@ var instantCommands = [
}]
];
var regexMap = {
// ($|\s) means that we either have to end the string
// after the command or there needs to be a space for options
'git commit': /^git +commit($|\s)/,
'git add': /^git +add($|\s)/,
'git checkout': /^git +checkout($|\s)/,
'git rebase': /^git +rebase($|\s)/,
'git reset': /^git +reset($|\s)/,
'git branch': /^git +branch($|\s)/,
'git revert': /^git +revert($|\s)/,
'git log': /^git +log($|\s)/,
'git merge': /^git +merge($|\s)/,
'git show': /^git +show($|\s)/,
'git status': /^git +status($|\s)/,
'git cherry-pick': /^git +cherry-pick($|\s)/,
'git fakeTeamwork': /^git +fakeTeamwork($|\s)/,
'git fetch': /^git +fetch *?$/,
'git pull': /^git +pull($|\s)/,
'git push': /^git +push($|\s)/,
'git clone': /^git +clone *?$/
};
/**
* Maintain this list to keep track of which commands we track
* for the "git golf" minigame
*/
var commandsThatCount = (function() {
var toCount = [
'git commit',
'git checkout',
'git rebase',
'git reset',
'git branch',
'git revert',
'git merge',
'git clone',
'git cherry-pick'
];
var whichCountMap = {};
_.each(toCount, function(method) {
if (!regexMap[method]) { throw new Error('wut no regex'); }
whichCountMap[method] = regexMap[method];
});
return whichCountMap;
})();
var parse = function(str) {
var method;
var options;
// see if we support this particular command
_.each(regexMap, function(regex, thisMethod) {
_.each(Commands.getRegexMap(), function(regex, thisMethod) {
if (regex.exec(str)) {
options = str.slice(thisMethod.length + 1);
method = thisMethod.slice('git '.length);
@ -112,7 +55,7 @@ var parse = function(str) {
// we support this command!
// parse off the options and assemble the map / general args
var parsedOptions = new GitOptionParser(method, options);
var parsedOptions = new CommandOptionParser(method, options);
return {
toSet: {
generalArgs: parsedOptions.generalArgs,
@ -125,13 +68,13 @@ var parse = function(str) {
};
/**
* GitOptionParser
* CommandOptionParser
*/
function GitOptionParser(method, options) {
function CommandOptionParser(method, options) {
this.method = method;
this.rawOptions = options;
this.supportedMap = this.getMasterOptionMap()[method];
this.supportedMap = Commands.getOptionMap()[method];
if (this.supportedMap === undefined) {
throw new Error('No option map for ' + method);
}
@ -140,61 +83,27 @@ function GitOptionParser(method, options) {
this.explodeAndSet();
}
GitOptionParser.prototype.getMasterOptionMap = function() {
// here a value of false means that we support it, even if its just a
// pass-through option. If the value is not here (aka will be undefined
// when accessed), we do not support it.
return {
commit: {
'--amend': false,
'-a': false, // warning
'-am': false, // warning
'-m': false
},
status: {},
log: {},
add: {},
'cherry-pick': {},
branch: {
'-d': false,
'-D': false,
'-f': false,
'-a': false,
'-r': false,
'--contains': false
},
checkout: {
'-b': false,
'-B': false,
'-': false
},
reset: {
'--hard': false,
'--soft': false // this will raise an error but we catch it in gitEngine
},
merge: {},
rebase: {
'-i': false // the mother of all options
},
revert: {},
show: {},
clone: {},
fetch: {},
pull: {
'--rebase': false
},
push: {},
fakeTeamwork: {}
};
};
var optionMap = {};
Commands.loop(function(config, name) {
var displayName = config.displayName || name;
if (optionMap[displayName] !== undefined) {
return;
}
GitOptionParser.prototype.explodeAndSet = function() {
var thisMap = {};
_.each(config.options, function(option) {
thisMap[option] = false;
});
optionMap[displayName] = thisMap;
});
CommandOptionParser.prototype.explodeAndSet = function() {
// TODO -- this is ugly
// split on spaces, except when inside quotes
var exploded = this.rawOptions.match(/('.*?'|".*?"|\S+)/g) || [];
for (var i = 0; i < exploded.length; i++) {
var part = exploded[i];
if (part.slice(0,1) == '-') {
// it's an option, check supportedMap
if (this.supportedMap[part] === undefined) {
@ -224,9 +133,6 @@ GitOptionParser.prototype.explodeAndSet = function() {
}
};
exports.shortcutMap = shortcutMap;
exports.commandsThatCount = commandsThatCount;
exports.instantCommands = instantCommands;
exports.parse = parse;
exports.regexMap = regexMap;

View file

@ -1732,7 +1732,7 @@ GitEngine.prototype.dispatch = function(command, deferred) {
try {
var methodName = command.get('method').replace(/-/g, '');
Commands[methodName](this, this.command);
Commands.execute(methodName, this, this.command);
} catch (err) {
this.filterError(err);
// short circuit animation by just setting error and returning

View file

@ -2,6 +2,7 @@ var _ = require('underscore');
var intl = require('../intl');
var GitCommands = require('../git/commands');
var Commands = require('../commands');
var Errors = require('../util/errors');
var GitError = Errors.GitError;
@ -26,7 +27,7 @@ DisabledMap.prototype.getInstantCommands = function() {
};
_.each(this.disabledMap, function(val, disabledCommand) {
var gitRegex = GitCommands.regexMap[disabledCommand];
var gitRegex = Commands.getRegexMap()[disabledCommand];
if (!gitRegex) {
throw new Error('wuttttt this disbaled command' + disabledCommand +
' has no regex matching');

View file

@ -10,12 +10,14 @@ var log = require('../log');
var Errors = require('../util/errors');
var Sandbox = require('../level/sandbox').Sandbox;
var Constants = require('../util/constants');
var Commands = require('../commands');
var Visualization = require('../visuals/visualization').Visualization;
var ParseWaterfall = require('../level/parseWaterfall').ParseWaterfall;
var DisabledMap = require('../level/disabledMap').DisabledMap;
var Command = require('../models/commandModel').Command;
var GitShim = require('../git/gitShim').GitShim;
var GitCommands = require('../git/commands');
var MultiView = require('../views/multiView').MultiView;
var CanvasTerminalHolder = require('../views').CanvasTerminalHolder;
@ -44,7 +46,6 @@ var Level = Sandbox.extend({
this.level = options.level;
this.gitCommandsIssued = [];
this.commandsThatCount = this.getCommandsThatCount();
this.solved = false;
this.initGoalData(options);
@ -297,11 +298,6 @@ var Level = Sandbox.extend({
});
},
getCommandsThatCount: function() {
var GitCommands = require('../git/commands');
return GitCommands.commandsThatCount;
},
undo: function() {
this.gitCommandsIssued.pop();
Level.__super__.undo.apply(this, arguments);
@ -314,7 +310,8 @@ var Level = Sandbox.extend({
}
var matched = false;
_.each(this.commandsThatCount, function(regex) {
_.each(Commands.getCommandsThatCount(), function(name) {
var regex = Commands.getRegex(name);
matched = matched || regex.test(command.get('rawStr'));
});
if (matched) {

View file

@ -1,6 +1,7 @@
var _ = require('underscore');
var GitCommands = require('../git/commands');
var Commands = require('../commands');
var SandboxCommands = require('../level/sandboxCommands');
// more or less a static class
@ -8,7 +9,7 @@ var ParseWaterfall = function(options) {
options = options || {};
this.options = options;
this.shortcutWaterfall = options.shortcutWaterfall || [
GitCommands.shortcutMap
Commands.getShortcutMap()
];
this.instantWaterfall = options.instantWaterfall || [

View file

@ -4,6 +4,7 @@ var util = require('../util');
var constants = require('../util/constants');
var intl = require('../intl');
var Commands = require('../commands');
var Errors = require('../util/errors');
var CommandProcessError = Errors.CommandProcessError;
var GitError = Errors.GitError;
@ -120,7 +121,7 @@ var getAllCommands = function() {
var allCommands = _.extend(
{},
require('../git/commands').regexMap,
require('../commands').getRegexMap(),
require('../level').regexMap,
regexMap
);

View file

@ -22,7 +22,7 @@ Origin things:
Medium things:
~~~~~~~~~~~~~~~~~~~~~~~~~~~
[ ] factor regexes and instant commands into one module
[ ] figure out what to do with instant commands (and parse waterfall and the like)
Cases to handle / things to edit
=======================
@ -42,6 +42,9 @@ Ideas for cleaning
Done things:
(I only started this on Dec 17th 2012 to get a better sense of what was done)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[x] factor out golf thing too
[x] factor regexes and instant commands into one module
[x] big command refactor to get everything in one place
[x] get demonstration view to show origin / remote -- z index ugliness
[x] get goal visualization to show origin / remote.... hrm :O
[x] MASSIVE EFFIN REFACTOR of all command options outside of git engine and into separate module