add "context" arg to custom Types parse() API, with lastParseTimestamp and cwd values
diff --git a/bundles/org.eclipse.orion.client.ui/web/orion/widgets/Shell.js b/bundles/org.eclipse.orion.client.ui/web/orion/widgets/Shell.js
index 9439b45..90e1289 100644
--- a/bundles/org.eclipse.orion.client.ui/web/orion/widgets/Shell.js
+++ b/bundles/org.eclipse.orion.client.ui/web/orion/widgets/Shell.js
@@ -124,6 +124,18 @@
 				if (!command.params) {
 					command.params = command.parameters;
 				}
+				var fn = function(exec) {
+					return function(args, context) {
+						var result = exec(args, context);
+						this.registeredTypes.forEach(function(current) {
+							current.prototype.lastParseTimestamp = 0;
+						});
+						return result;
+					}.bind(this);
+				}.bind(this);
+				if (command.exec) {
+					command.exec = fn(command.exec);
+				}
 				mGCLI.addCommand(command);
 			},
 			/**
@@ -148,51 +160,61 @@
 			 * @param {orion.shell.ParameterType} type the parameter type to register in the Shell
 			 */
 			registerType: function(type) {
-				function NewType(typeSpec) {
-					this.typeSpec = typeSpec;
-				}
-
-				NewType.prototype = Object.create(CustomType.prototype);
-				NewType.prototype.name = type.getName();
-				NewType.prototype.parse = function(arg) {
-					return type.parse(arg, this.typeSpec).then(function(completion) {
-						var status = mTypes.Status.VALID;
-						if (completion.status) {
-							switch (completion.status) {
-								case orion.shell.CompletionStatus.ERROR:
-									status = mTypes.Status.ERROR;
-									break;
-								case orion.shell.CompletionStatus.PARTIAL:
-									status = mTypes.Status.INCOMPLETE;
-									break;
+				var NewType = (function(type) {
+					function NewType(typeSpec) {
+						this.typeSpec = typeSpec;
+					}
+					NewType.prototype = Object.create(CustomType.prototype);
+					NewType.prototype.name = type.getName();
+					NewType.prototype.lastParseTimestamp = 0;
+					NewType.prototype.parse = function(arg) {
+						var prototype = Object.getPrototypeOf(this);
+						var lastParseTimestamp = prototype.lastParseTimestamp;
+						prototype.lastParseTimestamp = Math.round(new Date().getTime() / 1000);
+						return type.parse(arg, this.typeSpec, {lastParseTimestamp: lastParseTimestamp}).then(function(completion) {
+							var status = mTypes.Status.VALID;
+							if (completion.status) {
+								switch (completion.status) {
+									case orion.shell.CompletionStatus.ERROR:
+										status = mTypes.Status.ERROR;
+										break;
+									case orion.shell.CompletionStatus.PARTIAL:
+										status = mTypes.Status.INCOMPLETE;
+										break;
+								}
 							}
-						}
-						var predictionsPromise = mPromise.defer();
-						predictionsPromise.resolve(completion.predictions);
-						return new mTypes.Conversion(completion.value, arg, status, completion.message, predictionsPromise.promise);
-					});
-				};
-				NewType.prototype.lookup = function() {
-					return type.parse(new mArgument.Argument(), this.typeSpec).then(function(completion) {
-						return completion.predictions;
-					});
-				};
-				if (type.stringify) {
-					NewType.prototype.stringify = function(arg) {
-						return type.stringify(arg, this.typeSpec);
+							var predictionsPromise = mPromise.defer();
+							predictionsPromise.resolve(completion.predictions);
+							return new mTypes.Conversion(completion.value, arg, status, completion.message, predictionsPromise.promise);
+						});
 					};
-				}
-				if (type.increment) {
-					NewType.prototype.increment = function(arg) {
-						return type.increment(arg, this.typeSpec);
+					NewType.prototype.lookup = function() {
+						var prototype = Object.getPrototypeOf(this);
+						var lastParseTimestamp = prototype.lastParseTimestamp;
+						prototype.lastParseTimestamp = Math.round(new Date().getTime() / 1000);
+						return type.parse(new mArgument.Argument(), this.typeSpec, {lastParseTimestamp: lastParseTimestamp}).then(function(completion) {
+							return completion.predictions;
+						});
 					};
-				}
-				if (type.decrement) {
-					NewType.prototype.decrement = function(arg) {
-						return type.decrement(arg, this.typeSpec);
-					};
-				}
+					if (type.stringify) {
+						NewType.prototype.stringify = function(arg) {
+							return type.stringify(arg, this.typeSpec);
+						};
+					}
+//					if (type.increment) {
+//						NewType.prototype.increment = function(arg) {
+//							return type.increment(arg, this.typeSpec);
+//						};
+//					}
+//					if (type.decrement) {
+//						NewType.prototype.decrement = function(arg) {
+//							return type.decrement(arg, this.typeSpec);
+//						};
+//					}
+					return NewType;
+				}(type));
 				mTypes.registerType(NewType);
+				this.registeredTypes.push(NewType);
 			},
 			/**
 			 * Sets focus to the Shell's input area.
@@ -215,6 +237,8 @@
 				// TODO
 			},
 			_init: function(input, output) {
+				this.registeredTypes = [];
+
 				var outputDiv = document.createElement("div"); //$NON-NLS-0$
 				outputDiv.id = "gcli-display"; //$NON-NLS-0$
 				outputDiv.style.height = "100%"; //$NON-NLS-0$
diff --git a/bundles/org.eclipse.orion.client.ui/web/shell/shellPage.js b/bundles/org.eclipse.orion.client.ui/web/shell/shellPage.js
index b0fcb3a..af49d99 100644
--- a/bundles/org.eclipse.orion.client.ui/web/shell/shellPage.js
+++ b/bundles/org.eclipse.orion.client.ui/web/shell/shellPage.js
@@ -69,6 +69,47 @@
 		return CommandResult;

 	}());

 

+	var ContributedType = (function() {

+		function ContributedType(name, parseFn, stringifyFn) {

+			this.name = name;

+			this.parseFn = parseFn;

+			this.stringifyFn = stringifyFn;

+		}

+		ContributedType.prototype = {

+			getName: function() {

+				return this.name;

+			},

+			parse: function(arg, typeSpec, params) {

+				var promise = new Deferred();

+				this.parseFn(arg, typeSpec, params).then(

+					function(result) {

+						promise.resolve(result);

+					},

+					function(error) {

+						promise.reject(error);

+					}

+				);

+				return promise;

+			},

+			stringify: function(arg, typeSpec) {

+				if (!this.stringifyFn) {

+					return arg.name;

+				}

+				var promise = new Deferred();

+				this.stringifyFn(arg, typeSpec).then(

+					function(result) {

+						promise.resolve(result);

+					},

+					function(error) {

+						promise.reject(error);

+					}

+				);

+				return promise;

+			}

+		};

+		return ContributedType;

+	}());

+

 	/* model and renderer for displaying services */

 

 	var ServicesModel = (function() {

@@ -796,9 +837,10 @@
 		if (typeof(service) !== "function") { //$NON-NLS-0$

 			return undefined;

 		}

-		return function(args, typeSpec) {

+		return function(args, typeSpec, context) {

 			var promise = new Deferred();

-			service(args, typeSpec).then(

+			context.cwd = getCWD();

+			service(args, typeSpec, context).then(

 				function(result) {

 					promise.resolve(result);

 				},

@@ -815,7 +857,7 @@
 		serviceRegistry = core.serviceRegistry;

 		preferences = core.preferences;

 

-		var commandRegistry = new mCommandRegistry.CommandRegistry({ });

+		var commandRegistry = new mCommandRegistry.CommandRegistry({});

 		fileClient = new mFileClient.FileClient(serviceRegistry);

 		var searcher = new mSearchClient.Searcher({serviceRegistry: serviceRegistry, commandService: commandRegistry, fileService: fileClient});

 		var operationsClient = new mOperationsClient.OperationsClient(serviceRegistry);

@@ -1044,47 +1086,7 @@
 			var ref = allReferences[i];

 			var service = serviceRegistry.getService(ref);

 			if (service) {

-				var type = (function(name, parseFn, stringifyFn) {

-					return {

-						getName: function() {

-							return name;

-						},

-						parse: function(arg, typeSpec) {

-							var promise = new Deferred();

-							parseFn(arg, typeSpec).then(

-								function(result) {

-									promise.resolve(result);

-								},

-								function(error) {

-									promise.reject(error);

-								}

-							);

-							return promise;

-						},

-						stringify: function(arg, typeSpec) {

-							if (!stringifyFn) {

-								return arg.name;

-							}

-							var promise = new Deferred();

-							stringifyFn(arg, typeSpec).then(

-								function(result) {

-									promise.resolve(result);

-								},

-								function(error) {

-									promise.reject(error);

-								}

-							);

-							return promise;

-						}

-					};

-				}(ref.getProperty("name"), contributedFunc(service.parse), contributedFunc(service.stringify))); //$NON-NLS-0$

-

-//				if (service.increment) {

-//					type.increment = service.increment;

-//				}

-//				if (service.decrement) {

-//					type.decrement = service.decrement;

-//				}

+				var type = new ContributedType(ref.getProperty("name"), contributedFunc(service.parse), contributedFunc(service.stringify)); //$NON-NLS-0$

 				shell.registerType(type);

 			}

 		}