Merge branch 'master' of ssh://git.eclipse.org/gitroot/e4/org.eclipse.orion.client
diff --git a/bundles/org.eclipse.orion.client.core/static/js/editorFeatures.js b/bundles/org.eclipse.orion.client.core/static/js/editorFeatures.js
index a749df8..57fa3be 100644
--- a/bundles/org.eclipse.orion.client.core/static/js/editorFeatures.js
+++ b/bundles/org.eclipse.orion.client.core/static/js/editorFeatures.js
@@ -87,54 +87,57 @@
 
 	for (var i=0; i<actionReferences.length; i++) {
 		serviceRegistry.getService(actionReferences[i]).then(function(service) {
-			service.info().then(function(info) {
-				var editorWidget = editor.getEditorWidget();
-				var command = new eclipse.Command({
-					name: info.name,
-					image: info.img,
-					id: info.name,
-					callback: dojo.hitch(editor, function(editor) {
-						// command service will provide editor parameter but editor widget callback will not
-						var editorWidget = editor ? editor.getEditorWidget() : this.getEditorWidget();
-						var text = editorWidget.getText();
-						var selection = editorWidget.getSelection();
-						service.run(editorWidget.getText(selection.start,selection.end),text,selection).then(function(result){
-							if (result.text) {
-								editorWidget.setText(result.text);
-								if (result.selection) {
-									editorWidget.setSelection(result.selection.start, result.selection.end);
-									editorWidget.focus();
-								}
-							} else {
-								if (typeof result === 'string') {
-									editorWidget.setText(result, selection.start, selection.end);
-									editorWidget.setSelection(selection.start, selection.end);
-									editorWidget.focus();
-								}
+			var info = {};
+			var propertyNames = actionReferences[i].getPropertyNames();
+			for (var j = 0; j < propertyNames.length; j++) {
+				info[propertyNames[j]] = actionReferences[i].getProperty(propertyNames[j]);
+			}
+			var editorWidget = editor.getEditorWidget();
+			var command = new eclipse.Command({
+				name: info.name,
+				image: info.img,
+				id: info.name,
+				callback: dojo.hitch(editor, function(editor) {
+					// command service will provide editor parameter but editor widget callback will not
+					var editorWidget = editor ? editor.getEditorWidget() : this.getEditorWidget();
+					var text = editorWidget.getText();
+					var selection = editorWidget.getSelection();
+					service.run(editorWidget.getText(selection.start,selection.end),text,selection).then(function(result){
+						if (result.text) {
+							editorWidget.setText(result.text);
+							if (result.selection) {
+								editorWidget.setSelection(result.selection.start, result.selection.end);
+								editorWidget.focus();
 							}
-						});
-						
-					})});
-				commandService.addCommand(command, "dom");
-				if (info.img) {
-					// image will be placed on toolbar
-					commandService.registerCommandContribution(command.id, i, toolbarId, "eclipse.editorActions.contributed.images");
-				} else {
-					// if there is no image it will be grouped in a "More..." menu button
-					commandService.registerCommandContribution(command.id, i, toolbarId, "eclipse.editorActions.contributed.noImages");
-				}
-				// We must regenerate the command toolbar everytime we process an extension because
-				// this is asynchronous and we probably have already populated the toolbar.
-				// In the editor, we generate page level commands to the banner.
-				eclipse.globalCommandUtils.generateDomCommandsInBanner(commandService, editor);
+						} else {
+							if (typeof result === 'string') {
+								editorWidget.setText(result, selection.start, selection.end);
+								editorWidget.setSelection(selection.start, selection.end);
+								editorWidget.focus();
+							}
+						}
+					});
+					
+				})});
+			commandService.addCommand(command, "dom");
+			if (info.img) {
+				// image will be placed on toolbar
+				commandService.registerCommandContribution(command.id, i, toolbarId, "eclipse.editorActions.contributed.images");
+			} else {
+				// if there is no image it will be grouped in a "More..." menu button
+				commandService.registerCommandContribution(command.id, i, toolbarId, "eclipse.editorActions.contributed.noImages");
+			}
+			// We must regenerate the command toolbar everytime we process an extension because
+			// this is asynchronous and we probably have already populated the toolbar.
+			// In the editor, we generate page level commands to the banner.
+			eclipse.globalCommandUtils.generateDomCommandsInBanner(commandService, editor);
 
-				if (info.key) {
-					// add it to the editor as a keybinding
-					KB.prototype = eclipse.KeyBinding.prototype;
-					editorWidget.setKeyBinding(new KB(info.key), command.id);
-					editorWidget.setAction(command.id, command.callback);
-				}
-			});
+			if (info.key) {
+				// add it to the editor as a keybinding
+				KB.prototype = eclipse.KeyBinding.prototype;
+				editorWidget.setKeyBinding(new KB(info.key), command.id);
+				editorWidget.setAction(command.id, command.callback);
+			}
 		});
 	}
 };
diff --git a/bundles/org.eclipse.orion.client.core/static/js/fileCommands.js b/bundles/org.eclipse.orion.client.core/static/js/fileCommands.js
index 21c0be1..c7d2c9c 100644
--- a/bundles/org.eclipse.orion.client.core/static/js/fileCommands.js
+++ b/bundles/org.eclipse.orion.client.core/static/js/fileCommands.js
@@ -536,90 +536,95 @@
 
 	for (var i=0; i<commandsReferences.length; i++) {
 		serviceRegistry.getService(commandsReferences[i]).then(function(service) {
-			service.info().then(function(info) {
-				var commandOptions = {
-					name: info.name,
-					image: info.image,
-					id: info.id,
-					tooltip: info.tooltip,
-					visibleWhen: dojo.hitch(info, function(items){
-						if(dojo.isArray(items)){
-							if ((this.forceSingleItem || this.href) && items.length !== 1) {
-								return false;
-							}
-							if(!this.forceSingleItem && items.length < 1){
-								return false;
-							}
-						} else{
-							items = [items];
+			var info = {};
+			var propertyNames = commandsReferences[i].getPropertyNames();
+			for (var j = 0; j < propertyNames.length; j++) {
+				info[propertyNames[j]] = commandsReferences[i].getProperty(propertyNames[j]);
+			}
+
+			var commandOptions = {
+				name: info.name,
+				image: info.image,
+				id: info.id,
+				tooltip: info.tooltip,
+				visibleWhen: dojo.hitch(info, function(items){
+					if(dojo.isArray(items)){
+						if ((this.forceSingleItem || this.href) && items.length !== 1) {
+							return false;
 						}
-						
-						if(!this.validationProperties){
-							return true;
+						if(!this.forceSingleItem && items.length < 1){
+							return false;
 						}
-						
-						for(var i in items){
-							if(!validateSingleItem(items[i], this.validationProperties)){
-								return false;
-							}
-						}
+					} else{
+						items = [items];
+					}
+					
+					if(!this.validationProperties){
 						return true;
-						
-					})
-				};
-				if (info.href) {
-					commandOptions.hrefCallback = dojo.hitch(info, function(items){
-						var item = dojo.isArray(items) ? items[0] : items;
-						var shallowItemClone = eclipse.fileCommandUtils._cloneItemWithoutChildren(item);
-						if(service.run) {
-							return service.run(shallowItemClone);
+					}
+					
+					for(var i in items){
+						if(!validateSingleItem(items[i], this.validationProperties)){
+							return false;
 						}
-					});
-				} else {
-					commandOptions.callback = dojo.hitch(info, function(items){
-						var shallowItemsClone;
-						if (this.forceSingleItem) {
-							var item = dojo.isArray() ? items[0] : items;
-							shallowItemsClone = eclipse.fileCommandUtils._cloneItemWithoutChildren(item);
-						} else {
-							if (dojo.isArray(items)) {
-								shallowItemsClone = [];
-								for (var j = 0; j<items.length; j++) {
-									shallowItemsClone.push(eclipse.fileCommandUtils._cloneItemWithoutChildren(items[j]));
-								}
-							} else {
-								shallowItemsClone = eclipse.fileCommandUtils._cloneItemWithoutChildren(items);
+					}
+					return true;
+					
+				})
+			};
+			if (info.href) {
+				commandOptions.hrefCallback = dojo.hitch(info, function(items){
+					var item = dojo.isArray(items) ? items[0] : items;
+					var shallowItemClone = eclipse.fileCommandUtils._cloneItemWithoutChildren(item);
+					if(service.run) {
+						return service.run(shallowItemClone);
+					}
+				});
+			} else {
+				commandOptions.callback = dojo.hitch(info, function(items){
+					var shallowItemsClone;
+					if (this.forceSingleItem) {
+						var item = dojo.isArray() ? items[0] : items;
+						shallowItemsClone = eclipse.fileCommandUtils._cloneItemWithoutChildren(item);
+					} else {
+						if (dojo.isArray(items)) {
+							shallowItemsClone = [];
+							for (var j = 0; j<items.length; j++) {
+								shallowItemsClone.push(eclipse.fileCommandUtils._cloneItemWithoutChildren(items[j]));
 							}
+						} else {
+							shallowItemsClone = eclipse.fileCommandUtils._cloneItemWithoutChildren(items);
 						}
-						if(service.run) {
-							service.run(shallowItemsClone);
-						}
-					});
-				}
-				var command = new eclipse.Command(commandOptions);
-				var extensionGroupCreated = false;
-				var selectionGroupCreated = false;
-				if (info.forceSingleItem || info.href) {
-					// single items go in the local actions column, grouped in their own unnamed group to get a separator
-					commandService.addCommand(command, "object");
-					if (!extensionGroupCreated) {
-						extensionGroupCreated = true;
-						commandService.addCommandGroup("eclipse.fileCommandExtensions", 1000, null, fileGroup);
 					}
-					commandService.registerCommandContribution(command.id, i, null, fileGroup + "/eclipse.fileCommandExtensions");
-				} else {  
-					// items based on selection are added to the selections toolbar, grouped in their own unnamed group to get a separator
-					// TODO would we also want to add these to the menu above so that they are available for single selections?  
-					// For now we do not do this to reduce clutter, but we may revisit this.
-					commandService.addCommand(command, "dom");
-					if (!selectionGroupCreated) {
-						selectionGroupCreated = true;
-						commandService.addCommandGroup("eclipse.bulkFileCommandExtensions", 1000, null, selectionGroup);
+					if(service.run) {
+						service.run(shallowItemsClone);
 					}
-					commandService.registerCommandContribution(command.id, i, selectionToolbarId, selectionGroup + "/eclipse.bulkFileCommandExtensions");
+				});
+			}
+			var command = new eclipse.Command(commandOptions);
+			var extensionGroupCreated = false;
+			var selectionGroupCreated = false;
+			if (info.forceSingleItem || info.href) {
+				// single items go in the local actions column, grouped in their own unnamed group to get a separator
+				commandService.addCommand(command, "object");
+				if (!extensionGroupCreated) {
+					extensionGroupCreated = true;
+					commandService.addCommandGroup("eclipse.fileCommandExtensions", 1000, null, fileGroup);
 				}
+				commandService.registerCommandContribution(command.id, i, null, fileGroup + "/eclipse.fileCommandExtensions");
+			} else {  
+				// items based on selection are added to the selections toolbar, grouped in their own unnamed group to get a separator
+				// TODO would we also want to add these to the menu above so that they are available for single selections?  
+				// For now we do not do this to reduce clutter, but we may revisit this.
+				commandService.addCommand(command, "dom");
+				if (!selectionGroupCreated) {
+					selectionGroupCreated = true;
+					commandService.addCommandGroup("eclipse.bulkFileCommandExtensions", 1000, null, selectionGroup);
+				}
+				commandService.registerCommandContribution(command.id, i, selectionToolbarId, selectionGroup + "/eclipse.bulkFileCommandExtensions");
+			}

 			eclipse.fileCommandUtils.updateNavTools(serviceRegistry, explorer, toolbarId, selectionToolbarId, explorer.treeRoot);
 			explorer.updateCommands();
-		});
-	});}
+		});

+	}
 };
diff --git a/bundles/org.eclipse.orion.client.core/static/plugins/commentPlugin.html b/bundles/org.eclipse.orion.client.core/static/plugins/commentPlugin.html
index b9117ee..f768e45 100644
--- a/bundles/org.eclipse.orion.client.core/static/plugins/commentPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/static/plugins/commentPlugin.html
@@ -15,17 +15,14 @@
 			var provider = new eclipse.PluginProvider();
 			// testing that command service handles image-less actions properly
 			provider.registerServiceProvider("editorAction", {
-				info : function() {
-					return {
-						name : "Comment",
-						key : [ "m", true, true ] // ctrl+shift+m
-					};
-				},
 				run : function(selectedText, text, selection) { 
 					return {text: text.substring(0,selection.start) + "/*" + text.substring(selection.start,selection.end) + "*/" + text.substring(selection.end),
 					selection: {start:selection.start,end:selection.end+4}}; 
 				}
-			}, {name : "Comment"});
+			}, {
+				name : "Comment",
+				key : [ "m", true, true ] // ctrl+shift+m
+			});
 			provider.connect();
 		};
 	</script>
diff --git a/bundles/org.eclipse.orion.client.core/static/plugins/lowerPlugin.html b/bundles/org.eclipse.orion.client.core/static/plugins/lowerPlugin.html
index d68e82f..d4b54ad 100644
--- a/bundles/org.eclipse.orion.client.core/static/plugins/lowerPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/static/plugins/lowerPlugin.html
@@ -14,17 +14,14 @@
 		window.onload = function() {
 			var provider = new eclipse.PluginProvider();
 			provider.registerServiceProvider("editorAction", {
-				info : function() {
-					return {
-						name : "Lowercase",
-						img : "/images/gear.gif",
-						key : [ "u", true, true ] // ctrl+shift+u
-					};
-				},
 				run : function(text) {
 					return text.toLowerCase();
 				}
-			}, {name : "Lowercase", img : "/images/gear.gif"});
+			}, {
+				name : "Lowercase",
+				img : "/images/gear.gif",
+				key : [ "u", true, true ] // ctrl+shift+u
+			});
 			provider.connect();
 		};
 	</script>
diff --git a/bundles/org.eclipse.orion.client.core/static/plugins/sampleCommandsPlugin.html b/bundles/org.eclipse.orion.client.core/static/plugins/sampleCommandsPlugin.html
index 533807d..d24298a 100644
--- a/bundles/org.eclipse.orion.client.core/static/plugins/sampleCommandsPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/static/plugins/sampleCommandsPlugin.html
@@ -8,45 +8,31 @@
 		window.onload = function() {
 			var provider = new eclipse.PluginProvider();
 			provider.registerServiceProvider("fileCommands", {
-				info : function() {
-					return {
-						image: "/profile/images/create_user.gif",
-						name: "Run Code on Single Item",
-						id: "sample.commands.sample1",
-						forceSingleItem: true,
-						tooltip: "Run plugin code only on single file/dir"
-					};
-				},
 				run : function(item) {
 					window.alert("Running code on: " + item.Location);
 				}
+			}, {
+				image: "/profile/images/create_user.gif",
+				name: "Run Code on Single Item",
+				id: "sample.commands.sample1",
+				forceSingleItem: true,
+				tooltip: "Run plugin code only on single file/dir"
 			});
 			provider.registerServiceProvider("fileCommands", {
-				info : function() {
-					return {
-						image: "/profile/images/create_user.gif",
-						name: "Open HTML Raw",
-						id: "sample.commands.sample2",
-						forceSingleItem: true,
-						href: true,
-						validationProperties: {"Name":"*.html"},
-						tooltip: "Link to raw html on server"
-					};
-				},
 				run : function(item) {
 					return item.Location;
 				}
+			}, {
+				image: "/profile/images/create_user.gif",
+				name: "Open HTML Raw",
+				id: "sample.commands.sample2",
+				forceSingleItem: true,
+				href: true,
+				validationProperties: {"Name":"*.html"},
+				tooltip: "Link to raw html on server"
 			});
 			
 			provider.registerServiceProvider("fileCommands", {
-				info : function() {
-					return {
-						image: "/profile/images/create_user.gif",
-						name: "Bulk Item Command",
-						id: "sample.commands.sample3",
-						tooltip: "Bulk command operates on selections"
-					};
-				},
 				run : function(items) {
 					var locations = [];
 					for (var i = 0; i<items.length; i++) {
@@ -54,6 +40,11 @@
 					}
 					window.alert("Bulk operation on: " + locations);
 				}
+			}, {
+				image: "/profile/images/create_user.gif",
+				name: "Bulk Item Command",
+				id: "sample.commands.sample3",
+				tooltip: "Bulk command operates on selections"
 			});
 				
 			provider.connect();
diff --git a/bundles/org.eclipse.orion.client.core/static/plugins/unittestPlugin.html b/bundles/org.eclipse.orion.client.core/static/plugins/unittestPlugin.html
index 7ca7fd2..6a03edb 100644
--- a/bundles/org.eclipse.orion.client.core/static/plugins/unittestPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/static/plugins/unittestPlugin.html
@@ -8,18 +8,16 @@
 		window.onload = function() {
 			var provider = new eclipse.PluginProvider();
 			provider.registerServiceProvider("fileCommands", {
-				info : function() {
-					return {
-						name: "Run as Unit Test",
-						id: "eclipse.runUnitTest",
-						tooltip: "Run as Unit Test",
-						validationProperties: {"Name":"*.html"},
-						href: true,
-						forceSingleItem: true};
-				},
 				run: function(item) {
 					return "/unittest.html#" + item.Location;
 				}
+			}, {
+				name: "Run as Unit Test",
+				id: "eclipse.runUnitTest",
+				tooltip: "Run as Unit Test",
+				validationProperties: {"Name":"*.html"},
+				href: true,
+				forceSingleItem: true
 			});
 			provider.connect();
 		};
diff --git a/bundles/org.eclipse.orion.client.core/static/plugins/upperPlugin.html b/bundles/org.eclipse.orion.client.core/static/plugins/upperPlugin.html
index 0006b36..b95322d 100644
--- a/bundles/org.eclipse.orion.client.core/static/plugins/upperPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/static/plugins/upperPlugin.html
@@ -14,17 +14,14 @@
 		window.onload = function() {
 			var provider = new eclipse.PluginProvider();
 			provider.registerServiceProvider("editorAction", {
-				info : function() {
-					return {
-						name : "UPPERCASE",
-						img : "/images/gear.gif",
-						key : [ "u", true ]
-					};
-				},
 				run : function(text) {
 					return text.toUpperCase();
 				}
-			}, {name : "UPPERCASE", img : "/images/gear.gif"});
+			}, {
+				name : "UPPERCASE",
+				img : "/images/gear.gif",
+				key : [ "u", true ]
+			});
 			provider.connect();
 		};
 	</script>
diff --git a/bundles/org.eclipse.orion.client.git/static/plugins/gitPlugin.html b/bundles/org.eclipse.orion.client.git/static/plugins/gitPlugin.html
index f97d4f9..f731769 100644
--- a/bundles/org.eclipse.orion.client.git/static/plugins/gitPlugin.html
+++ b/bundles/org.eclipse.orion.client.git/static/plugins/gitPlugin.html
@@ -8,18 +8,16 @@
 		window.onload = function() {
 			var provider = new eclipse.PluginProvider();
 			provider.registerServiceProvider("fileCommands", {
-				info : function() {
-					return {
-						name: "Git Status",
-						id: "eclipse.git.status",
-						tooltip: "Go to Git Status",
-						validationProperties: {"Git":"*", "Directory":"true"},
-						href: true,
-						forceSingleItem: true};
-				},
 				run: function(item) {
 					return "/git-status.html#" + item.Git.StatusLocation;
 				}
+			}, {
+				name: "Git Status",
+				id: "eclipse.git.status",
+				tooltip: "Go to Git Status",
+				validationProperties: {"Git":"*", "Directory":"true"},
+				href: true,
+				forceSingleItem: true
 			});
 			provider.connect();
 		};