Page 1 of 1

Auto Color Active Tab (ACAT) Path based per Pane Tab Colorization v0.61

Posted: 06 Jul 2026 16:33
by SomeGuy63
Auto Color Active Tab (ACAT)
Goal is to set the Background and Text color only for the Active Tab for each pane based on per pane Path rules.
Path coloring should color all subfolders as well when accessed via Active tab and rule is matched, this will override any custom tab color (it will not be restored only reset back to default).
Path rules should perform a best match based on path length regardless of rule order.
Longest real path rule always wins as best match if multiple rules cover the same path.
Script should not touch color of a tab set outside script for which no script rules exist.
For any tab colorized by the script the script should also handle reset of tab back to XYplorer configured default colors on backgrounding or path not matched.
Script should remove color and reset to default if tab path changes to a path with no rule.
Script should remove color and reset to default if active tab in current pane changes to another tab
Script should gracefully handle proper colorization and reseting to default colors of tabs when moved between panes.
Script should gracefully handle proper colorization and default color resets for new/cloned/copied/etc tabs including cross pane.
Script should not reset color of a tab set outside script for which no script rules exist.

Known issues:
Copying or cloning a tab from a pane with matching color rules to a pane without matching color rules may leave the copied/cloned tab colorized instead of resetting to default.
--

Please report any bugs found. Currently I have no planned feature releases (bug fixes are always ongoing).

Possible (not guaranteed) Future Feature updates:
Exclusion Path list to prevent autocolor of specified subfolder tabs when broad rule applies. (ex: user has a broad rule for C: but does not want that colorization to occur for c:\temp)

Note: below colors are just me testing/extreme example purposes and not indicative of any planned color palette.

v0.1 - Initial
v0.2 - Usability update - Rules no longer need to be pre-sorted, uses best match.
v0.3 - Resolved issues with Environment Variables, Special Folders, and RapidAccess path color reset functions.
v0.4 - TabID based tracking of tab Colorization to ensure only ActiveTab in each pane that matches rule is colorized by script.
v0.41 - Adding missing null check causing unwanted tab color reset
v0.5 - Resolved issue moving tabs between panes.
v0.51 - Removed redundant trim call, added comments
v0.6 - Properly set tab colors back to default when copying/cloning a colorized tab from a pane with matching rules to a pane with no matching rules.
v0.61 - reverted 2 rules meant to deal with copying/cloned tabs retaining color as it caused inadvertent color resets of manually colored tabs

Setup:
Navigate to Configuration > General > Custom Event Actions > Changing Locations > After painting the file list and set it to 'Run script'
Navigate to Configuration > General > Custom Event Actions > Changing Locations > After painting the file list and set script as per below (or save below to a file and use a load command (eg: load "ACAT.xys";) in the event)
Adjust the rules path list as needed (it needs it, that is an extremely wild color setup)

Code: Select all

/*
******************************************************************************
@Author  : Someguy63
@Created : 2026-07-05 14:00:00
@Modified: 2026-07-10 19:50:00
@Function: CEA After painting file list, Auto colors current/active tab based on Path and pane.
@Name    : Auto Color Active Tab (ACAT)
@Tags    : tab, CEA, color
@Version : v0.61
******************************************************************************
*/
/*
Auto Color Active Tab (ACAT)
Goal is to set the Background and Text color only for the Active Tab for each pane based on per pane Path rules.
Path coloring should color all subfolders as well when accessed via Active tab and rule is matched, this will override any custom tab color (it will not be restored only reset back to default).
Path rules should perform a best match based on path length regardless of rule order.
Longest real path rule always wins as best match if multiple rules cover the same path.
Script should not touch color of a tab set outside script for which no script rules exist.
For any tab colorized by the script the script should also handle reset of tab back to XYplorer configured default colors on backgrounding or path not matched.
Script should remove color and reset to default if tab path changes to a path with no rule.
Script should remove color and reset to default if active tab in current pane changes to another tab
Script should gracefully handle proper colorization and reseting to default colors of tabs when moved between panes.
Script should gracefully handle proper colorization and default color resets for new/cloned/copied/etc tabs including cross pane.
Script should not reset color of a tab set outside script for which no script rules exist.
*/

/* Testing Rules */
/* My Rules */
/*
*/

// Only path and pipes are required. No value = Set Default Color for Colors and All Panes for no specifed pane
// PATH|TabBackgroundColor|TabTextColor|Pane
  $rules = <<<RULES
  C:\Windows|800000|c0c000|1             // Set C:\Windows Tab background & text colors on Pane 1
  C:\Windows|c0c000|800000|2             // Set C:\Windows Tab background & text colors on Pane 2
  \\Server\music|202020|FFFFFF|          // Set Music Folder on Server Tab background & text colors on both panes
  C:|70704b|88bff6|1                     // Set C: Tab background & text colors on Pane 1
  //C:|70704b|ffffff|1                   // Disabled rule
  C:|70704b|e9b3a9|2                     // Set C: Tab background & text colors on Pane 2
  D:|||                                  // Set D: Default background and text color for both panes
  E:||5151d|2                            // Set E: Tab text color, reset background to default on Pane 2
  F:\temp|5150d||1                       // Set F:\Temp Tab background color, reset text color to default on Pane 1
  %AppData%|408040|FFFFFF|               // Set %AppData% Tab background & text colors on both panes
  Desktop|305080|FFFFFF|                 // Set Desktop Tab background & text colors on both panes
  Desktop\Test|3050ff|FFFF00|1           // Set Desktop\Test Tab background & text colors on Pane 1
  N:\TemP|800000|c0c000|2                // Set N:\Temp Tab background color & text color on Pane 2
  C:\Windows\System32|800000|c0c000|2    // Set C:\Windows\System32 Tab background & text colors on Pane 2
  C:\Windows\System32|c0c000|800000|1    // Set C:\Windows\System32 Tab background & text colors on Pane 1
  RULES;
  
  $rules = regexreplace($rules, "(^[ \t]+|[ ]*?//.*?$)");  //Cleanup Leading whitespace and trailing comments

  perm $p_ACATColorizedTabs;  //track Colorized TabIDs between script runs
  if ($p_ACATColorizedTabs == "") {
    $p_ACATColorizedTabs = "|||";
  }
  perm $p_ACATLastTabs;  //track Last Active IDs between script runs
  if ($p_ACATLastTabs == "") {
    $p_ACATLastTabs = "|||||";
  }

  $pane = get("pane");
  $path = pathreal(<curpath>);
  $curTabID = tab("get", "ID");

  $matched = 0;
  $bestLen = -1;
  $bestTabColor = "";
  $bestTextColor = "";
  $bestMatch = "NoMatch";
  $bestMatched = 0;

  $tab1ID = gettoken($p_ACATColorizedTabs, 1, "|");
  $tab2ID = gettoken($p_ACATColorizedTabs, 2, "|");
  $tab1Path = gettoken($p_ACATColorizedTabs, 3, "|");
  $tab2Path = gettoken($p_ACATColorizedTabs, 4, "|");
  $lastActive1ID = gettoken($p_ACATLastTabs, 1, "|");
  $lastActive2ID = gettoken($p_ACATLastTabs, 2, "|");
  $lastActive1Path = gettoken($p_ACATLastTabs, 3, "|");
  $lastActive2Path = gettoken($p_ACATLastTabs, 4, "|");
  $last1Matched = gettoken($p_ACATLastTabs, 5, "|");
  $last2Matched = gettoken($p_ACATLastTabs, 6, "|");
  $tab1Valid = isTabValid($tab1ID);
  $tab2Valid = isTabValid($tab2ID);
  $lastActive1Valid = isTabValid($lastActive1ID);
  $lastActive2Valid = isTabValid($lastActive2ID);
  
  $debug = "Current $pane -- T1 $tab1Valid $tab1ID $tab1Path -- T2 $tab2Valid $tab2ID $tab2Path -- Cur $curTabID $path -- $p_ACATColorizedTabs -- $p_ACATLastTabs $lastActive1Valid $lastActive2Valid";
  //echo "Values - $debug";
  
  function isTabValid($cID) {                   // return if the tabID supplied is valid for current Pane
    $tabCount = tab("get","c");
    for ($i = 1; $i <= $tabCount; $i++) {    // TabID may be stale on Tab Move to new pane
      $check = tab("get","ID",$i);           // So loop through all current pane tabs
      if ($check == $cID) {                  // If ID exists
        return 1;
      }
    }
    return 0;
  }
  
  function resetByTabID($tID) {
      $check = isTabValid($tID);           // So loop through all current pane tabs
      //echo "Reset Request: TabID: $tID  Valid: $check";
      if ($check) {                  // If ID exists, then reset color
        tab("backcolor","000000",,$tID);  // REMOVE FOR RELEASE
        tab("textcolor","000000",,$tID);  // REMOVE FOR RELEASE
        $pane = get("pane"); //echo "$pane - $tID - $p_ACATColorizedTabs";  // REMOVE FOR RELEASE
        tab("backcolor","",,$tID);
        tab("textcolor","",,$tID);
      }
    }
  }

  // Loop through rules finding best match based on longest path (easiest part of the script)
  foreach($line, $rules, "<crlf>", "e") {
    if ($line == "") { continue; }
    $rulePath  = gettoken($line, 1, "|");
    $tabColor  = gettoken($line, 2, "|");
    $textColor = gettoken($line, 3, "|");
    $rulePane = gettoken($line, 4, "|");
    $rulePath = pathreal($rulePath);
    if (strpos($path, $rulePath) == 0) {
      if ("" == $rulePane || $pane == $rulePane) {
        $matched = 1;
        $len = strlen($rulePath);
        if ($len > $bestLen) {
          $bestLen = $len;
          $bestTabColor = $tabColor;
          $bestTextColor = $textColor;
          $bestMatch = $line;
          $bestMatched = 1;
        }
      }
    }
  }


  //echo "Before Reset Rules - $debug";
  // Rule 1px = Move tab to new pane
  // We're using the window of Tab2 Path being invalid to do the resets for both Pane 1 & Pane 2 move action
  if ( $pane == 2 && $tab2ID != $curTabID && $tab2ID != "" && !$tab2Valid && $path != $tab2Path && $tab2Path == $lastActive1Path && !$last1Matched) {
    $p_ACATColorizedTabs = "|$tab2ID||$tab2Path";
    //echo "rule 1p1 switch -- $debug";
    #802;  // Switch to Pane 1
    resetByTabID($lastActive1ID);
    #802;  // Switch to back to Pane 2
  }
  if ( $pane == 2 && $tab2ID != $curTabID && $tab1ID != "" && !$tab1Valid  && $path == $tab1Path) {
    $p_ACATColorizedTabs = "$tab1ID||$tab1Path|";
    //echo "rule 1p2 switch -- $debug";
    resetByTabID($curTabID);
  }
  // Rule 2px = change active tab in current pane
  if ( $pane == 1 && $tab1ID != "" && $tab1ID != $curTabID && $tab1Valid ) {
    $p_ACATColorizedTabs = "|$tab2ID||$tab2Path";
    //echo "rule 2p1 switch -- $debug";
    resetByTabID($tab1ID);
  }
  if ( $pane == 2 && $tab2ID != "" && $tab2ID != $curTabID && $tab2Valid ) {
    $p_ACATColorizedTabs = "$tab1ID||$tab1Path|";
    //echo "rule 2p2 switch -- $debug";
    resetByTabID($tab2ID);
  }
  // Rule 3px = Change path on current tab in current pane
  if ( $pane == 1 && $tab1ID != "" && $tab1ID == $curTabID && !$matched ) {
    $p_ACATColorizedTabs = "|$tab2ID||$tab2Path";
    //echo "rule 3p1 switch -- $debug";
    resetByTabID($tab1ID);
  }
  if ( $pane == 2 && $tab2ID != "" && $tab2ID == $curTabID && !$matched ) {
    $p_ACATColorizedTabs = "$tab1ID||$tab1Path|";
    //echo "rule 3p2 switch -- $debug";
    resetByTabID($tab2ID);
  }
/*
  // Rule 4px = Copy/Clone Tab to new pane
*/
  //echo "After Reset Rules - $debug";

  // Update our perm Tab data quads
  if ($pane == 1) {
    $p_ACATLastTabs = "$curTabID|$lastActive2ID|$path|$lastActive2Path|$matched|$last2Matched";
    if ($matched) {
      $p_ACATColorizedTabs = "$curTabID|$tab2ID|$path|$tab2Path";
    }
  }
  if ($pane == 2) {
    $p_ACATLastTabs = "$lastActive1ID|$curTabID|$lastActive1Path|$path|$last1Matched|$matched";
    if ($matched) {
      $p_ACATColorizedTabs = "$tab1ID|$curTabID|$tab1Path|$path";
    }
  }

  // Set the Tab background & text color based on match from above
  if ($bestMatched && $bestMatched) {
    tab("backcolor", $bestTabColor);
    tab("textcolor", $bestTextColor);
  }
  //echo "Rule: $bestMatch $matched - $debug";

/*
******************************************************************************
Known issues:
Copying or cloning a tab from a pane with matching color rules to a pane without matching color rules may leave the copied/cloned tab colorized instead of resetting to default.
******************************************************************************
*/

Re: Autocolor Active Tab based on Path with per pane support. v0.3

Posted: 06 Jul 2026 23:30
by highend
You are aware that the syntax is wrong?

Code: Select all

tab("backcolor","",,$prevTab);

Resetting color, e.g.:

Code: Select all

  // Reset curr tab color if no rule matches
  if (!regexmatches($rules, "^" . regexreplace($path, "([\\^$.+()\[{])", "\$1") . "\|")) {
    tab("backcolor", "");
    tab("textcolor", "");
    end true;
  }

Re: Autocolor Active Tab based on Path with per pane support. v0.3

Posted: 07 Jul 2026 01:27
by SomeGuy63
highend wrote: 06 Jul 2026 23:30 You are aware that the syntax is wrong?

Code: Select all

tab("backcolor","",,$prevTab);
Really? The code for that works as expected and the syntax I used came right from the Help file. The usage there gets fed the TabID of the Previously Active tab.
Syntax
tab([operation], [data], [index], [ID], [flags])
highend wrote: 06 Jul 2026 23:30 Resetting color, e.g.:

Code: Select all

  // Reset curr tab color if no rule matches
  if (!regexmatches($rules, "^" . regexreplace($path, "([\\^$.+()\[{])", "\$1") . "\|")) {
    tab("backcolor", "");
    tab("textcolor", "");
    end true;
  }
Thank you, yes that would work for reseting current non-matched tab.
Except the intent is to not reset every tab, only those changed by visiting the tab and having been previously been updated by the rules of the script.

Somewhat moot as in v0.4 I am rewriting the code to store a value for the tabid when it colors a tab, and then remove that stored value when it un-colors the tab.
Thus it will be more robust and overcome the left-over tab color when cloning a tab and current tab changed to a non-matched rule issue.
Probably later tonight or tomorrow.

Re: Autocolor Active Tab based on Path with per pane support. v0.3

Posted: 07 Jul 2026 01:34
by highend
Interesting, the help file says:

Code: Select all

"textcolor", "backcolor" = sets the custom text/background color of a tab
data: color value in hexadecimal format (RRGGBB) (if empty then any custom color is removed)
index: tab to color (if missing then current tab)
return: index of the affected tab
If that really does work, the docs are imho misleading here...

Re: AutoColor Active Tab (ACAT) Path based per Pane Tab Colorization v0.4

Posted: 07 Jul 2026 03:42
by SomeGuy63
I just treated index as one example of a matching method. Also the examples below show use of the ID in other options like close but the text for close only mentions index.

Well, there it is fully functional, all known issues resolved by using TabID tracking rather than relying on previous path matching.
Tried moving tab between Panes and found another issue.
Script Error on Move Tab to Other Pane

Resolved v0.5