Find-As-You-Type (FAYT) scripts let you type into the FAYT field and pass it to a script. The script can then (optionally) pass back a list of matches and perform actions, either as you type or when you push return.
This is very open-ended, and the manual doesn't include examples yet, so I've posted some here for you to play with.
These are more likely to be starting points than useful by themselves.
These scripts add entries to the Quick Keys list.
You can edit the keys and colors the same as built-in entries. (Scripts define the initial default key/color but you can change it here.)
(Download and copy to /scripts, or use the new Settings > Install Script command.)
This adds a FAYT Quick Key which runs a particular Find Files Preset (g_preset, defined at the top of the script), using whatever you type as the filename pattern.
The intent is to quickly search a pre-defined list of folders, regardless of the current location and without having to open the Find Files panel.
The search does not start until you push return.
Searches always use "Any Word" mode by default (set by g_anyWord near the top of the script), meaning the words you type can match in any order, and don't all need to match as long as at least one does. (You can prefix a word with + to say it MUST match, or with - to say it must NOT match.)
If both g_anyWord and g_needAllWords are set to true, each word you type is automatically prefixed with a + character, so that all words must be present but can be in any order. If g_anyWord is false, g_needAllWords is not used.
The Find Preset is named MySearchPreset by default, but you can edit g_preset at the top of the script to change the name. You need to create a preset with that name, and use it to define the folders you want to search. You can do that from the Tools > Find Files.
The Find Panel is also where you can edit the preset, if you need to change the list of folders or any other options, and then save out the preset again.
The menu part shows your previous searches, so you can re-run them, and a Clear option to clear the list. (This will hide the button entirely, until the history is non-empty again.)
The history is not saved to disk by default, but you can change that at the top of the script, as well as the maximum number of items it will remember.
Make a button which runs FAYTSearchExample_History LIST to get the list. Remember that it will not appear until you've done a search and have something for it to show.
You can also use FAYTSearchExample_History CLEAR if you want a standalone button that clears the list.
The dynamic history list is generated using functionality added in Directory Opus 13.15.2. More detail can be found in the 13.15.2 release notes.
Here is the script code in text format so it's easier to see how it works. This is the same as the download at the top of the example.
// This adds a FAYT Quick Key which runs a particular Find Files Preset (g_preset, below),
// adding whatever you type as the filename pattern.
// The intention is to be able to quickly search a pre-defined list of folders,
// regardless of the current location and without having to open the Find Files panel.
// The search does not start until you push return.
// A menu-button can also be added to your toolbars which lists the current and recent
// searches, and lets you clear them. The button part shows the last search and the menu
// shows previous searches so you can re-run them.
// Make a button which runs "FAYTSearchExample_History LIST" to get that.
var g_preset = "MySearchPreset";
var g_nameInternal = "FAYTSearchExample";
var g_defKey = "!";
var g_defBackColor = "#ffc6c6";
var g_defTextColor = "#000000";
var g_nameHistoryVar = g_nameInternal + "_History";
var g_nameHistoryCmd = g_nameInternal + "_History";
var g_nameHistoryLab = g_nameInternal + " History";
var g_nameHistoryClearLab = "&Clear";
var g_historyPersist = false; // Set true to save history to disk across restarts.
var g_historyLimit = 10;
// Searches always use "Any Word" mode by default, meaning the words you type can match in any order, and don't all need to match as long as
// at least one does. You can prefix a word with + to say it MUST match, or with - to say it must NOT match.
var g_anyWord = true;
// If both g_anyWord and g_needAllWords are true, each word you type is automatically prefixed with a + character. So all words must be present
// but can be in any order. If g_anyWord is false, g_needAllWords is not used.
var g_needAllWords = true;
function OnInit(initData)
{
initData.name = "FAYT Search " + g_preset;
initData.version = "1.1";
initData.copyright = "(c) 2021-2025 Leo Davidson";
initData.url = "https://resource.dopus.com/t/find-as-you-type-fayt-scripts/44736/1";
initData.desc = "";
initData.default_enable = true;
initData.min_version = "13.15.2";
initData.group = "FAYT";
}
function OnDeleteScript(deleteScriptData)
{
// Script is being deleted through the Scripts management dialog.
// Clear the history. This is mainly in case it has been configured to persist to disk.
ClearHistory();
}
function OnAddCommands(addCmdData)
{
// Search command which is run when typing into the FAYT field with our prefix.
var cmd = addCmdData.AddCommand();
cmd.name = g_nameInternal;
cmd.method = "OnFAYTSearch";
cmd.desc = "";
cmd.label = g_nameInternal;
cmd.icon = "script";
cmd.template = "";
cmd.hide = true; // Hide from button editor menus
var fayt = cmd.fayt;
fayt.enable = true;
fayt.key = g_defKey;
fayt.backcolor = g_defBackColor;
fayt.textcolor = g_defTextColor;
fayt.label = "Search " + g_preset;
// fayt.flags - optional Map of flags (flag value -> label) - need to use DOpus.Create.Map
fayt.realtime = false; // Call after return, not on every keypresss
// History command which generates a button-menu of previous searches.
cmd = addCmdData.AddCommand();
cmd.name = g_nameHistoryCmd;
cmd.method = "OnFAYTSearchHistory";
cmd.desc = "Used to show or clear history of searches made via the FAYT Search Preset script.";
cmd.label = g_nameHistoryLab;
cmd.icon = "findpresets";
cmd.template = "CLEAR/S,LIST/S,RUN/K";
cmd.dynamic_args = "LIST";
}
function OnFAYTSearch(scriptFAYTData)
{
// Called when the user types into the FAYT field with our prefix.
if (scriptFAYTData.fayt != g_nameInternal)
{
DOpus.Output('Unexpected FAYT: "' + scriptFAYTData.fayt + '"');
return;
}
if (scriptFAYTData.key != "return")
{
DOpus.Output('Unexpected FAYT: "' + scriptFAYTData.fayt + '" called unexpectedly');
return;
}
var tab = scriptFAYTData.tab;
var strQuery = scriptFAYTData.cmdline;
if (strQuery == "" || strQuery == scriptFAYTData.quickKey)
{
return;
}
RunQuery(tab, strQuery);
}
function RunQuery(tab, strQuery)
{
strQuery = strQuery.replace(/^\s*(.+?)\s*$/,"$1"); // Trim spaces from start and end.
strQuery = strQuery.replace(/"/g,""); // Remove any quote characters in the string.
if (strQuery == "")
{
return;
}
AddHistory(strQuery);
var cmdLine = 'Find PRESET="' + g_preset + '" COLLNAME="Find Results" CLEAR';
if (g_anyWord)
{
cmdLine += ' ANYWORD';
if (g_needAllWords)
{
// Prefix each word with "+".
strQuery = strQuery.split(" ");
for(var i = 0; i < strQuery.length; ++i)
{
if (strQuery[i] != "" && strQuery[i][0] != "+" && strQuery[i][0] != "-")
{
strQuery[i] = '+' + strQuery[i];
}
}
strQuery = strQuery.join(" ");
}
}
cmdLine += ' NAME="' + strQuery + '"';
var cmd = DOpus.Create.Command();
cmd.SetSourceTab(tab);
cmd.RunCommand(cmdLine);
// DOpus.Output(cmdLine);
}
function OnFAYTSearchHistory(scriptCommandData)
{
var args = scriptCommandData.func.args;
if (args.got_arg.CLEAR)
{
ClearHistory();
}
else if (args.got_arg.RUN)
{
RunQuery(scriptCommandData.func.sourcetab, args.RUN);
}
}
function OnAddButtons(addButtonsData)
{
// Make sure we're being called because of the LIST argument, otherwise bail.
if (!addButtonsData.args.got_arg.LIST)
{
return false;
}
var vecHistory = GetHistory();
// If the history is empty, emit nothing and hide the original button.
// (All we could add here is a clear button, and it's already cleared.)
if (vecHistory.empty)
{
return true;
}
// Make a menu-button with the most recent search on the button part.
var menuButton = addButtonsData.buttons.AddMenuButton();
menuButton.label = DoubleAmpersands(vecHistory(0));
menuButton.func = g_nameHistoryCmd + ' RUN="' + vecHistory(0) + '"';
menuButton.image = "#find";
menuButton.notablabel = true;
// Inherit our top-level label/image from the button that generates us.
// menuButton.showLabel = "right";
// menuButton.showImage = true;
// In the menu part of the menu-button, add the rest of the searches.
var menu = menuButton.children;
for (var i = 1; i < vecHistory.count; ++i)
{
var searchButton = menu.AddButton();
searchButton.label = DoubleAmpersands(vecHistory(i));
searchButton.func = g_nameHistoryCmd + ' RUN="' + vecHistory(i) + '"';
searchButton.image = "#find";
searchButton.notablabel = true;
// searchButton.showLabel = "right"; // Not needed as "right" is the default for labels within sub-menus.
searchButton.showImage = true;
if (i == vecHistory.count - 1)
{
searchButton.separator = true; // Separator after this button.
}
}
// Still in the menu part of the menu-button, add a Clear button.
var clearButton = menu.AddButton();
clearButton.label = g_nameHistoryClearLab; // Don't DoubleAmpersands. The label uses one as an accelerator.
clearButton.func = g_nameHistoryCmd + ' CLEAR';
clearButton.image = "#clearfilters";
clearButton.notablabel = false; // Allow tabs in label, although we don't use them normally.
// clearButton.showLabel = "right"; // Not needed as "right" is the default for labels within sub-menus.
clearButton.showImage = true;
return true;
}
function DoubleAmpersands(str)
{
return str.replace(/&/g,"&&");
}
// Helpers for managing the search history.
function ClearHistory()
{
Script.vars.Delete(g_nameHistoryVar);
Script.UpdateButtons(true); // Update our button-menu that shows the search history.
}
function GetHistory()
{
var v = Script.vars;
if (!v.Exists(g_nameHistoryVar))
{
return DOpus.Create.Vector(); // Empty.
}
return v.Get(g_nameHistoryVar);
}
function SetHistory(vecHistory)
{
var v = Script.vars;
v.Set(g_nameHistoryVar, vecHistory);
v(g_nameHistoryVar).persist = g_historyPersist; // Optionally save to disk.
Script.UpdateButtons(true); // Update our button-menu that shows the search history.
}
function AddHistory(strQuery)
{
if (g_historyLimit < 1)
{
ClearHistory();
return;
}
if (!strQuery || strQuery == "")
{
return;
}
var strQueryLower = strQuery.toLowerCase();
var vecHistoryOld = GetHistory();
var vecHistoryNew = DOpus.Create.Vector();
vecHistoryNew.push_back(strQuery);
for (var i = 0; i < vecHistoryOld.count; ++i)
{
if (vecHistoryNew.count >= g_historyLimit)
{
break;
}
var strHistItem = vecHistoryOld(i);
if (strQueryLower != strHistItem.toLowerCase())
{
vecHistoryNew.push_back(strHistItem);
}
}
SetHistory(vecHistoryNew);
}
This is in addition to the usual script config dialogs you could make in the past.
The way these flags work may be unfamiliar (unless you're a C/C++ programmer or similar), so I've made an example script to show how it's done.
This script does nothing except define 16 flags and then tell you which are turned on as you send keypresses to it. It's only useful as an example for writing your own FAYT scripts.
// Called by Directory Opus to initialize the script
function OnInit(initData)
{
initData.name = "FAYT Flags Example";
initData.version = "1.0";
initData.copyright = "(c) 2023 Leo Davidson";
// initData.url = "https://resource.dopus.com/c/buttons-scripts/16";
initData.desc = "Script example";
initData.default_enable = true;
initData.min_version = "13.0";
}
// Define these values so our script is easier to read.
var FLAG_OptA = (1<<0);
var FLAG_OptB = (1<<1);
var FLAG_OptC = (1<<2);
var FLAG_OptD = (1<<3);
var FLAG_OptE = (1<<4);
var FLAG_OptF = (1<<5);
var FLAG_OptG = (1<<6);
var FLAG_OptH = (1<<7);
var FLAG_OptI = (1<<8);
var FLAG_OptJ = (1<<9);
var FLAG_OptK = (1<<10);
var FLAG_OptL = (1<<11);
var FLAG_OptM = (1<<12);
var FLAG_OptN = (1<<13);
var FLAG_OptO = (1<<14);
var FLAG_OptP = (1<<15);
// No more allowed currently.
// Called to add commands to Opus
function OnAddCommands(addCmdData)
{
var cmd = addCmdData.AddCommand();
cmd.name = "ExampleFAYTFlagsCommand";
cmd.method = "OnExampleFAYTFlagsCommand";
cmd.desc = "";
cmd.label = "ExampleFAYTFlagsCommand";
cmd.template = "";
cmd.hide = true;
cmd.icon = "script";
var fayt = cmd.fayt;
fayt.enable = true;
fayt.key = "^";
fayt.backcolor = "#000000";
fayt.textcolor = "#909090";
fayt.label = "FAYT Flags Example";
fayt.flags = DOpus.Create.Map();
fayt.realtime = true; // Call on every keypresss
// Add a load of options named "Option A" through "Option P".
fayt.flags[FLAG_OptA] = "Option A";
fayt.flags[FLAG_OptB] = "Option B";
fayt.flags[FLAG_OptC] = "Option C";
fayt.flags[FLAG_OptD] = "Option D";
fayt.flags[FLAG_OptE] = "Option E";
fayt.flags[FLAG_OptF] = "Option F";
fayt.flags[FLAG_OptG] = "Option G";
fayt.flags[FLAG_OptH] = "Option H";
fayt.flags[FLAG_OptI] = "Option I";
fayt.flags[FLAG_OptJ] = "Option J";
fayt.flags[FLAG_OptK] = "Option K";
fayt.flags[FLAG_OptL] = "Option L";
fayt.flags[FLAG_OptM] = "Option M";
fayt.flags[FLAG_OptN] = "Option N";
fayt.flags[FLAG_OptO] = "Option O";
fayt.flags[FLAG_OptP] = "Option P";
}
function OnExampleFAYTFlagsCommand(scriptFAYTData)
{
if (scriptFAYTData.fayt != "ExampleFAYTFlagsCommand")
{
DOpus.Output('Unexpected FAYT: "' + scriptFAYTData.fayt + '"');
return;
}
// Report which options are turned on to the script log.
var letters = "";
if (scriptFAYTData.flags & FLAG_OptA) letters += "A";
if (scriptFAYTData.flags & FLAG_OptB) letters += "B";
if (scriptFAYTData.flags & FLAG_OptC) letters += "C";
if (scriptFAYTData.flags & FLAG_OptD) letters += "D";
if (scriptFAYTData.flags & FLAG_OptE) letters += "E";
if (scriptFAYTData.flags & FLAG_OptF) letters += "F";
if (scriptFAYTData.flags & FLAG_OptG) letters += "G";
if (scriptFAYTData.flags & FLAG_OptH) letters += "H";
if (scriptFAYTData.flags & FLAG_OptI) letters += "I";
if (scriptFAYTData.flags & FLAG_OptJ) letters += "J";
if (scriptFAYTData.flags & FLAG_OptK) letters += "K";
if (scriptFAYTData.flags & FLAG_OptL) letters += "L";
if (scriptFAYTData.flags & FLAG_OptM) letters += "M";
if (scriptFAYTData.flags & FLAG_OptN) letters += "N";
if (scriptFAYTData.flags & FLAG_OptO) letters += "O";
if (scriptFAYTData.flags & FLAG_OptP) letters += "P";
DOpus.Output("Flags: " + ((letters == "") ? "<none>" : letters));
}
Call me stupid but I can't understand how the 1st example works. When I start typing "$" in the FAYT I do get the "Emulator Platforms" Prompt but none of the auto expansion I see in the screenshots, and I do have typical ROM system folder names there.
Hmm, I don't know if scripts can do that, but it would definitely make sense for scripts where you'd never type anything after the selection. (FWIW, I usually use the cursor keys, as my hands are on the keyboard already.)
Good idea, we should probably come up with some standard groups for different script types, now they can arrange themselves like that.
Create a button which runs FAYTSearchExample_History LIST for that.
The button part shows the last search, so you can see what you searched for, or click it to re-run the search.
The menu part shows your previous searches, so you can re-run them, and a Clear option to clear the list. (This will hide the button entirely, until the history is non-empty again.)
The history is not saved to disk by default, but you can change that at the top of the script, as well as the maximum number of items it will remember.
The dynamic history list is generated using new functionality added in Directory Opus 13.15.2. More detail can be found in the 13.15.2 release notes.
"Any Word" mode is now the default, and can be configured by editing the top of the script.
The old behavior of doubling the initial FAYT character to get "Any Word" mode has been removed, since it turned out not to be very useful and made implementing the history list too complex.