GoParallel - Jump between related folder trees

Overview:

This script adds a new command, GoParallel, which you can use in buttons, hotkeys, etc.

The GoParallel command lets you jump between two folder hierarchies while maintaining the same relative position, and optionally keeping the same things selected.

For example, say you have ==Pre-Release== and ==Live== areas, below which are different versions of the same files and folders.

You might be here, below the ==Pre-Release== branch:

  • C:\Euro Cat Simulator 2019\==Pre-Release==\Assets\3D Objects

With the click of a button, you can jump to the same place in the ==Live== branch:

  • C:\Euro Cat Simulator 2019\==Live==\Assets\3D Objects

Clicking the button again could take you back again.

If you had files or folders selected before jumping to the other branch, they can be selected for you automatically after the jump (as long as they exist in both places).

Video Example:

This video shows it in action, using POST and PROD as the two branches:

Installation:

Requires Directory Opus Pro 12.9 or above.

  • Download: GoParallel.js.txt (3.0 KB) [v1.2 26/Aug/2018]
  • Open Settings > Preferences / Toolbars / Scripts.
  • Drag GoParallel.js.txt to the list of scripts.

After doing that, you will now be able to use the GoParallel command in buttons, hotkeys, menu items, and so on.

Command Arguments:


FIND (keyword)
REPLACE (keyword)

  • The FIND and REPLACE arguments work together and apply a basic find-and-replace operation on the current folder path.

    Example 1: GoParallel FIND="John" REPLACE="Jane":

    If you are in C:\Folder for John Doe, you will go to C:\Folder for Jane Doe.

    If you want to make sure you match a whole folder component, not just part of one, be sure to put \ at the start and end of both strings.

    Example 2: GoParallel FIND="\John\" REPLACE="\Jane\":

    Nothing will happen if you are under C:\John Doe.
    But if you are under C:\John then you will go to C:\Jane.

    (You don't have to worry about whether or not there is a \ on the very end of the path. The script takes care of that.)

    If the FIND / REPLACE arguments do not apply to the path you are in then the command will fail, causing any other commands after it to be skipped.

    The arguments are not case-sensitive by default. If you want them to be, edit the script and change caseSensitive = false to true.


TOGGLE (switch)

  • Include the TOGGLE argument if you want the command to work as a toggle, going back and forth between two folders.

    Leave out the argument if you want the jump to be one-way.

    When toggling, the FIND > REPLACE conversion is tried first.
    Only if that fails will it try the reverse REPLACE > FIND conversion.

    That may be important if one folder name is a substring of the other.

    Example 3: GoParallel FIND="Pre-Release" REPLACE="Release" TOGGLE

    That will work for toggling between paths containing ...Pre-Release... and ...Release....

    Example 4: GoParallel FIND="Release" REPLACE="Pre-Release" TOGGLE

    The above example won't work properly. With the find and replace parameters the other way around, if you are below ...Pre-Release..., it will find and replace Release with Pre-Release, and try to take you to ...Pre-Pre-Release.... This is why I said above that the order may be important, but only in special cases like this.


PARENT (switch)

  • Include the PARENT argument to change what happens if the parallel folder does not exist. By default, the command will fail if the result of the find-and-replace is a path that doesn't exist. If PARENT is specified, the command will try the parent folder, then the parent of that, and so on, until it reaches a folder that exists.

    Example 5: GoParallel FIND="POST" REPLACE="PROD" TOGGLE PARENT

    If you are in C:\Project\PROD\Obj_X\Mod, the button will try going to these folders until it finds one that exists, instead of failing if the first one does not exist:

    C:\Project\POST\Obj_X\Mod
    C:\Project\POST\Obj_X
    C:\Project\POST
    C:\Project
    C:\


SELECT (switch)

  • Include the SELECT argument if you would like the command to look at what you had selected in the folder you started in and try to select the same things in the folder you end up in.

    The example button, just below, demonstrates the SELECT switch being used, along with the other arguments.


Example Button:

Here is the button which is shown in the video above:

The last line is the important one, and you should be able to understand it if you've read everything above:

GoParallel find="\PROD\" replace="\POST\" TOGGLE SELECT

The first line is something extra:

@hideifpathr:!\\(PROD|POST)($|\\)

It uses @hideifpathr to hide the button, saving space on the toolbar, when you are not in a folder which matches the regular expression after the !. Since the button toggles between \PROD\ and \POST\ branches, it will be useless if the path does not include either of those, so the button is only visible when in a suitable location.

The ($|\\) on the end of the regular expression ensures that it works both when directly below either folder, and when in a child folder, without accidentally matching folder names which start with PROD or POST (e.g. PRODUCE).


In case you want to paste the example button straight to your toolbar, here is the same button again, as an XML Button Definition:

<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none">
	<label>Prod / Post</label>
	<icon1>#getsizes</icon1>
	<function type="normal">
		<instruction>@hideifpathr:!\\(PROD|POST)($|\\)</instruction>
		<instruction />
		<instruction>// Button is hidden unless in a path with</instruction>
		<instruction>//    a component named PROD or POST.</instruction>
		<instruction />
		<instruction>// Toggle between the PROD and POST trees,</instruction>
		<instruction>//   maintaining any selection.</instruction>
		<instruction />
		<instruction>GoParallel find=&quot;\PROD\&quot; replace=&quot;\POST\&quot; TOGGLE SELECT</instruction>
	</function>
</button>

(Remember, you still need to install the add-in, as per the Installation section above. If you don't, the GoParallel command won't be recognized.)


History:

  • v1.2 (26/Aug/2018): Find and replace no longer case-sensitive by default.
  • v1.1 (14/Aug/2018): Added PARENT switch.
  • v1.0 (13/Aug/2018): Initial version.

Script Code:

If you just want to use the script, grab the download from the Installation section above.

The script code is reproduced below so people browsing the forum can find scripting techniques without having to download every script:

// This is a script for Directory Opus.
// See https://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.

function OnInit(initData)
{
	initData.name = "GoParallel";
	initData.version = "1.2";
	initData.copyright = "(c) 2018 Leo Davidson";
	initData.url = "https://resource.dopus.com/t/goparallel-jump-between-related-folder-trees/29608";
	initData.desc = "Go to a path by replacing part of the current one.";
	initData.default_enable = true;
	initData.min_version = "12.9";

	var cmd = initData.AddCommand();
	cmd.name = "GoParallel";
	cmd.method = "OnGoParallel";
	cmd.desc = "Go to a path by replacing part of the current one.";
	cmd.label = "GoParallel";
	cmd.template = "FIND/K,REPLACE/K,TOGGLE/S,SELECT/S,PARENT/S";
	cmd.hide = false;
	cmd.icon = "getsizes";
}

function OnGoParallel(scriptCmdData)
{
	var caseSensitive = false; // Change if needed.

	var cmd = scriptCmdData.func.Command;
	cmd.deselect = false;

	var args = scriptCmdData.func.args;

	if (!args.got_arg.find || !args.got_arg.replace)
		return true; // Block further commands.

	var findStr = args.find;
	var replaceStr = args.replace;

	var curPath = endSlash( DOpus.FSUtil.Resolve(scriptCmdData.func.sourcetab.path) );
	
	if (!caseSensitive)
	{
		curPath = curPath.toUpperCase();
		findStr = findStr.toUpperCase();
		replaceStr = replaceStr.toUpperCase();
	}
		
	var newPath = endSlash( curPath.replace(findStr, replaceStr) );

	if (curPath == newPath && args.toggle)
		newPath = endSlash( curPath.replace(replaceStr, findStr) );

	if (curPath == newPath)
		return true; // Block further commands.

	while ( !DOpus.FSUtil.Exists(newPath) )
	{
		var newPathObj = DOpus.FSUtil.NewPath(newPath);
		if (!args.parent || !newPathObj.Parent())
			return true; // Block further commands.
		newPath = endSlash( newPathObj );
		
		if (curPath == newPath)
			return true; // Block further commands.
	}

	// Snapshot selections before changing folders.
	var selFiles = scriptCmdData.func.sourcetab.selected_files;
	var selDirs = scriptCmdData.func.sourcetab.selected_dirs;

	cmd.RunCommand('Go PATH="' + newPath + '"');

	if (args.select)
	{
		selectItems(cmd, newPath, selFiles, false);
		selectItems(cmd, newPath, selDirs, true);
	}

	return false; // Allow further commands.
}

function selectItems(cmd, newPath, sel, isDirs)
{
	if (sel.count == 0)
		return;

	cmd.ClearFiles();

	for (var eSel = new Enumerator(sel); !eSel.atEnd(); eSel.moveNext())
	{
		var selItem = eSel.item();
		var selPath = newPath + eSel.item().name;
		cmd.AddFile(selPath);
	}

	cmd.RunCommand("Select FROMSCRIPT MAKEVISIBLE TYPE=" + (isDirs ? "dirs" : "files"));
}

function endSlash(pathString)
{
	// In case pathString is an Opus path object, ensure conversion to JSCript string.
	var res = pathString + "";

	// Add a backslash to the end of the path if there isn't one already.
	res = res.replace(/([^\\])$/, '$1\\');
	
	return res;
}
3 Likes

Hi,

Thank you very much for the help.
This solve a big part of our problem !

But in some cases, for exemple if artist is working in a sub dir /PROD/OBJ_X/MOD/
and click on the GoParallel button, this would result on an error.
Because Dopus would try to access a folder that doesn't exist, /POST/OBJ_X/MOD/ (modeling is not a post-production task)
It should go back to /POST/OBJ_X/

So I tried to edit the script, adding a test, to find out if the folder exist. :

if (newPath.notExists()){
     newPath = '/home/';
}

But it return an 0x800a138f error.

Script in the root post is updated to include a new PARENT switch which should do what you need.

I tried this and it's case sensitive and doesn't support for unicode, this could be optimized.

Hi Leo,

And thanks a lot, this work perfectly.
I will dive ine the Dopus comand tech' doc, it seems to have some interesting fonctionalities.

Also I'll have so more complex question about dopus. if it is possible to customise it even more, make a custom GUI to navigate on a given pipeline. And with the API, if it's possible to interface Dopus with some third party integration tools, like Shotgun (autodesk Shotgun software)

I'll contact you next week, right after going back to work.

Hi Leo,

I've done some modification to your code, to be able to switch within different part of our pipe to specific location, for exemple :slight_smile:

from PROD to POST or DOC, and vice versa.

@hideifpathr:!\\(1_DOC|2_PROD|3_POST)($|\\)

@ifpathr:\\(3_POST)($|\\) 
GoParallel FIND="3_POST" REPLACE="1_DOC" TOGGLE SELECT PARENT
@ifpathr:\\(2_PROD)($|\\)
GoParallel FIND="2_PROD" REPLACE="1_DOC" TOGGLE SELECT PARENT

Many thanks, this help a lot, and promise to be well adapted for our purpose.

1 Like

I've updated the root post with a new version that is not case-sensitive by default.

and doesn't support for unicode

Unicode seems to work OK here. For example, a folder named post❤test and this as the command:

GoParallel find="\prod\" replace="\post❤test\" TOGGLE SELECT PARENT

But note that Opus versions before 12.9.2 beta could not load or save buttons which contained characters outside the BMP range (UTF-16 surrogate pairs and 4-byte UTF-8 sequences). So you may have been running into that problem, rather than an issue with the script itself.

(In fact, it was trying to call the example button in the screenshots Prod :repeat: Post which meant we found & fixed that problem.)