Bug 407826 - Shell link should open Shell page to an appropriate location based on the current context
diff --git a/bundles/org.eclipse.orion.client.ui/web/orion/shell/nls/root/messages.js b/bundles/org.eclipse.orion.client.ui/web/orion/shell/nls/root/messages.js
index 16de92f..204a189 100644
--- a/bundles/org.eclipse.orion.client.ui/web/orion/shell/nls/root/messages.js
+++ b/bundles/org.eclipse.orion.client.ui/web/orion/shell/nls/root/messages.js
@@ -13,6 +13,7 @@
 define({
 	"Shell": "Shell",
 	"Changed to: ": "Changed to: ",
+	"Initial directory: ": "Initial directory: ",
 	"${0} is not a directory": "${0} is not a directory",
 	"${0} was not found": "${0} was not found",
 	"Changes the current directory": "Changes the current directory",
diff --git a/bundles/org.eclipse.orion.client.ui/web/plugins/pageLinksPlugin.html b/bundles/org.eclipse.orion.client.ui/web/plugins/pageLinksPlugin.html
index 779bc21..c74a0e2 100644
--- a/bundles/org.eclipse.orion.client.ui/web/plugins/pageLinksPlugin.html
+++ b/bundles/org.eclipse.orion.client.ui/web/plugins/pageLinksPlugin.html
@@ -15,7 +15,7 @@
 		  i18n: 'requirejs/i18n',
 		  domReady: 'requirejs/domReady'
 	  }
-	});	
+	});
 
 	/*global define orion window*/
 	var VERSION = "2.0";
@@ -48,7 +48,7 @@
 			nameKey: "Shell",
 			id: "orion.shell",
 			nls: "orion/nls/messages",
-			uriTemplate: "{OrionHome}/shell/shellPage.html"
+			uriTemplate: "{OrionHome}/shell/shellPage.html#projectfor={Location}"
 		});
 		provider.registerService("orion.page.link", serviceImpl, {
 			nameKey: "Search",
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 65ad6ed..7611258 100644
--- a/bundles/org.eclipse.orion.client.ui/web/shell/shellPage.js
+++ b/bundles/org.eclipse.orion.client.ui/web/shell/shellPage.js
@@ -26,6 +26,7 @@
 	var contentTypeService, openWithCommands = [], serviceRegistry;

 	var pluginRegistry, pluginType, preferences, serviceElementCounter = 0;

 

+	var PREFIX_PROJECTFOR = "projectfor="; //$NON-NLS-0$

 	var ROOT_ORIONCONTENT = new URL(require.toUrl("file"), window.location.href).pathname; //$NON-NLS-0$

 	var PAGE_TEMPLATE = require.toUrl("shell/shellPage.html") + "#{,resource}"; //$NON-NLS-0$

 

@@ -207,12 +208,16 @@
 		return result.length > 0 ? result : null;

 	}

 

-	function setCWD(value) {

+	function setCWD(value, replace) {

 		var template = new URITemplate(PAGE_TEMPLATE);

 		var url = template.expand({

 			resource: value

 		});

-		window.location.href = url;

+		if (replace) {

+			window.location.replace(url);

+		} else {

+			window.location.href = url;

+		}

 	}

 

 	/* general functions for working with file system nodes */

@@ -288,9 +293,9 @@
 

 	/* implementations of built-in file system commands */

 

-	function getChangedToElement(dirName) {

+	function getChangedToElement(dirName, isInitial) {

 		var span = document.createElement("span"); //$NON-NLS-0$

-		span.appendChild(document.createTextNode(messages["Changed to: "]));

+		span.appendChild(document.createTextNode(isInitial ? messages["Initial directory: "] : messages["Changed to: "]));

 		var bold = document.createElement("b"); //$NON-NLS-0$

 		bold.appendChild(document.createTextNode(dirName));

 		span.appendChild(bold);

@@ -301,9 +306,9 @@
 		var node = args.directory.value[0];

 		shellPageFileService.setCurrentDirectory(node);

 		hashUpdated = true;

-		setCWD(node.Location);

+		setCWD(node.Location, false);

 		var pathString = shellPageFileService.computePathString(node);

-		return getChangedToElement(pathString);

+		return getChangedToElement(pathString, false);

 	}

 

 	function editExec(args) {

@@ -897,6 +902,7 @@
 			}

 		};

 

+		/* check the URL for a command string to seed the input field with */

 		var parameters = PageUtil.matchResourceParameters(window.location.href);

 		if (parameters.command) {

 			shell.setInputText(parameters.command);

@@ -908,16 +914,60 @@
 

 		shell.setFocusToInput();

 

+		/* check the URL for an initial folder location to open to */

+

 		shellPageFileService = new mShellPageFileService.ShellPageFileService();

-		var location = getCWD();

-		shellPageFileService.loadWorkspace(location || ROOT_ORIONCONTENT).then(

-			function(node) {

+		var defaultLocationFn = function(location, replace) {

+			var successFn = function(node) {

+				setCWD(node.Location, replace);

 				shellPageFileService.setCurrentDirectory(node);

+				var pathString = shellPageFileService.computePathString(node);

+				shell.output(getChangedToElement(pathString, true));

+			};

+			if (location) {	

+				shellPageFileService.loadWorkspace(location).then(

+					successFn,

+					function(error) {

+						shellPageFileService.loadWorkspace(ROOT_ORIONCONTENT).then(successFn);

+					}

+				);

+			} else {

+				shellPageFileService.loadWorkspace(ROOT_ORIONCONTENT).then(successFn);

 			}

-		);

-		if (!location) {

-			hashUpdated = true;

-			setCWD(ROOT_ORIONCONTENT);

+		};

+

+		if (parameters.resource && parameters.resource.indexOf(PREFIX_PROJECTFOR) === 0) {

+			/* Attempt to open to the project root of the specified resource */

+			var resourceValue = parameters.resource.substring(PREFIX_PROJECTFOR.length);

+			fileClient.read(resourceValue, true).then(

+				function(node) {

+					if (node.Directory === undefined) {

+						/*

+						 * The resource was read successfully but does not represent a file system

+						 * resource, so it cannot be used.  Revert to the default initial location.

+						 */

+						 defaultLocationFn(null, true);

+					} else if (node.Parents && node.Parents.length > 0) {

+						var projectLocation = node.Parents[node.Parents.length - 1].Location;

+						defaultLocationFn(projectLocation, true);

+					} else {

+						/*

+						 * The PREFIX_PROJECTFOR value is either a project root or is below the

+						 * level or projects, so just take it as the starting location.

+						 */

+						 defaultLocationFn(node.Location, true);

+					}

+				},

+				function(error) {

+					/*

+					 * The PREFIX_PROJECTFOR value does not refer to a valid file system

+					 * location, so open to the default location.

+					 */

+					defaultLocationFn(null, true);			

+				}

+			);

+		} else {

+			defaultLocationFn(getCWD(), false);

 		}

 

 		/* add the locally-defined types */

@@ -1160,9 +1210,16 @@
 					if (shellPageFileService.getCurrentDirectory().Location !== node.Location) {

 						shellPageFileService.setCurrentDirectory(node);

 						var buffer = shellPageFileService.computePathString(node);

-						shell.output(getChangedToElement(buffer));

-						setCWD(node.Location);

+						shell.output(getChangedToElement(buffer, false));

+						setCWD(node.Location, false);

 					}

+				},

+				function(error) {

+					/*

+					 * The hash has changed to point at an invalid resource, so reset it to

+					 * the previous current directory which was valid.

+					 */

+					setCWD(shellPageFileService.getCurrentDirectory().Location, true);

 				}

 			);

 		});

diff --git a/modules/orionode/lib/orionode.client/plugins/pageLinksPlugin.html b/modules/orionode/lib/orionode.client/plugins/pageLinksPlugin.html
index dc5da99..5e4e842 100644
--- a/modules/orionode/lib/orionode.client/plugins/pageLinksPlugin.html
+++ b/modules/orionode/lib/orionode.client/plugins/pageLinksPlugin.html
@@ -54,7 +54,7 @@
 			nameKey: "Shell",
 			id: "orion.shell",
 			nls: "orion/nls/messages",
-			uriTemplate: "{OrionHome}/shell/shellPage.html"
+			uriTemplate: "{OrionHome}/shell/shellPage.html#projectfor={Location}"
 		});
 		provider.registerService("orion.page.link", serviceImpl, {
 			nameKey: "Get Plugins",