Code: Select all
/*
******************************************************************************
@Author : IT Services & Consulting Ulf Kohlmorgen
@Created : 2021-07-01 22:24:36
@Modified: 2021-09-30 13:22:05
@Function: Everything
@Tags : search, find, everything, integration
@Version : v0.9.5
******************************************************************************
*/
/*
Original authorship / copyright
===============================
User : Marco [https://www.xyplorer.com/xyfc/memberlist.php?mode=viewprofile&u=1779]
Thread: https://www.xyplorer.com/xyfc/viewtopic.php?f=7&t=12054
Additional (example) syntax options of "es.exe":
regex: = Use a basic POSIX regular expression
case: = Case-sensitive search
wholeword: = Whole word search
count:<max> = Limit the amount of results to <max>
*/
// ========================================================================
// == DO NOT CHANGE ANYTHING BELOW IF YOU DO NOT KNOW WHAT YOU ARE DOING ==
// ========================================================================
// Handle .ini file
$iniFile = self("path") . "\" . self("base") . ".ini";
// Write .ini file if missing
if (exists($iniFile) != 1) {
$iniContent = <<<'>>>'
[General]
; Where does the "es.exe" file reside
; Default: <xypath>\..\Everything_x64
EverythingPath=<xypath>\..\Everything_x64
; Where does "Everything" store its data files
; E.g. the "Filters*.csv", "Macros*.csv", etc.
; Default: <xypath>\..\Everything_x64
; For non-portable installations this is usually
; %APPDATA%\Everything
EverythingDataPath=<xypath>\..\Everything_x64
; The base paper folder name (without .txt extension)
; Default: Everything
PaperFolderName=Everything
; En- or disable the setting of column layout and sort order
; Default: true (to disable this, use: false)
SetupColumns=true
; The columns that the paper folder will show
; Default: Name,Path,Size,Modified,Created
ColumnLayout=Name,Path,Size,Modified,Created
; Primary and secondary sort order columns
; Default: Name,Path
ColumnSortOder=Name,Path
; Automatically resize the paper folder columns
; Default: true (to disable this, use: false)
AutosizeColumns=true
; Display internal notes (switch explanations)
; Default: true (to disable this, use: false)
DisplayNotes=true
; How many last queries should be stored
; Default: 10
MaxSavedQueries=10
; Get filter and search macro names from Everything
; Your own filter macros must have this schema: "{name}<{identifier}>"
; E.g.: bat<QUERY>, office<SEARCH>, etc.
; Default: false (to enable this, use: true)
ShowMacros=false
; Split overlong macro definitions into shorter <crlf>-separated line(s)
MacroLinesLength=60
; Querying a drive at its root level (no subfolder used) can easily
; crash XYplorer (because of too many items in the search result)
; E.g.: C:\, f:C:\ or d:C:\
; Default: true (to disable this, use: false)
; If set to true, this behavior can be overriden with the " /f" switch
; at the end of the query
; E.g.: C:\ /f, f:C:\ /f or d:C:\ /f
ConfirmRootDrive=true
; The last query you've used
LastQuery=
>>>;
writefile($iniFile, $iniContent, , "tu");
}
// Get .ini file entries
$everythingPath = getkey("EverythingPath", "General", $iniFile);
$everythingDataPath = getkey("EverythingDataPath", "General", $iniFile);
$paperFolderName = getkey("PaperFolderName", "General", $iniFile);
$setupColumns = getkey("SetupColumns", "General", $iniFile);
$columnLayout = getkey("ColumnLayout", "General", $iniFile);
$autosizeColumns = getkey("AutosizeColumns", "General", $iniFile);
$columnSortOder = getkey("ColumnSortOder", "General", $iniFile);
$displayNotes = getkey("DisplayNotes", "General", $iniFile);
$maxSavedQueries = getkey("MaxSavedQueries", "General", $iniFile);
$showMacros = getkey("ShowMacros", "General", $iniFile);
$macroLinesLength = getkey("MacroLinesLength", "General", $iniFile);
$confirmRootDrive = getkey("ConfirmRootDrive", "General", $iniFile);
$lastQuery = getkey("LastQuery", "General", $iniFile);
// Validations
if ($everythingPath == "") { $everythingPath = "<xypath>\..\Everything_x64"; }
if ($everythingDataPath == "") {
$everythingDataPath = "<xypath>\..\Everything_x64";
setkey $everythingDataPath, "EverythingDataPath", "General", $iniFile;
}
if ($paperFolderName == "") { $paperFolderName = "Everything"; }
if ($columnLayout == "") { $columnLayout = "Path,Name,Size,Modified,Created"; }
if ($columnSortOder == "") { $columnSortOder = "Path,Name"; }
if ($maxSavedQueries == "" || $maxSavedQueries <= 0 || !regexmatches($maxSavedQueries, "\d+")) {
$maxSavedQueries = 10;
setkey $maxSavedQueries, "MaxSavedQueries", "General", $iniFile;
}
if ($setupColumns UnLikeI "true" && $setupColumns UnLikeI "false") { $setupColumns = "true"; }
if ($displayNotes UnLikeI "true" && $displayNotes UnLikeI "false") { $displayNotes = "true"; }
if ($autosizeColumns UnLikeI "true" && $autosizeColumns UnLikeI "false") { $autosizeColumns = "true"; }
if ($showMacros UnLikeI "true" && $showMacros UnLikeI "false") {
$showMacros = "false";
setkey $showMacros, "ShowMacros", "General", $iniFile;
}
if ($macroLinesLength == "" || $macroLinesLength <= 0 || !regexmatches($macroLinesLength, "\d+")) {
$macroLinesLength = 60;
setkey $macroLinesLength, "MacroLinesLength", "General", $iniFile;
}
if ($confirmRootDrive UnLikeI "true" && $confirmRootDrive UnLikeI "false") {
$confirmRootDrive = "true";
setkey $confirmRootDrive, "ConfirmRootDrive", "General", $iniFile;
}
$columnLayout = trim($columnLayout, ",");
$columnSortOder = trim($columnSortOder, ",");
$everythingPath = trim(resolvepath($everythingPath), "\", "R");
$everythingDataPath = trim(resolvepath($everythingDataPath), "\", "R");
$es = "$everythingPath\es.exe";
end (exists($everythingPath) != 2), quote($everythingPath) . <crlf 2> . "not found, aborted!";
end (exists($es) != 1), quote($es) . <crlf 2> . "not found, aborted!";
if (exists("$everythingPath\Everything64.exe") == 1) { $inputIcon = "$everythingPath\Everything64.exe"; }
elseif (exists("$everythingPath\Everything.exe") == 1) { $inputIcon = "$everythingPath\Everything.exe"; }
else { $inputIcon = ":qns"; }
$verTooOld = (compare(<xyver>, "22.00.0006", "v") == -1) ? true : false; }
// Display notes (or not)
$notes = "";
if ($displayNotes LikeI "true") {
$notes = <<<'>>>'
Type your search query as you would in Everything!
Additional (internal) switches and their expansions:
d: = Only directories => folder:
f: = Only files => file:
c: = Search content => content:
l: = Search only in current path => path:"<curpath>"
w: = Search in Windows search index => systemindex:
You need to prepend your query with one of these switches...
E.g.: d:<some folder name> and NOT: <some folder name> d:
<placeholder macros>
BEWARE: Drives must end with a trailing "\", otherwise it would
be unclear if it's an (internal) switch or a drive!
E.g. use: C:\ but NOT C:
>>>;
if ($verTooOld) { $notes = regexreplace($notes, "^[ \t]+"); }
else { $notes = regexreplace($notes, "^[ ]{12}"); }
// Modify notes if necessary
$msgPlaceholderMacros = "<placeholder macros>";
if ($showMacros) {
$macros = getMacros($everythingDataPath, $msgPlaceholderMacros, $macroLinesLength);
if ($macros) {
$notes = replace($notes, $msgPlaceholderMacros, $macros);
}
}
$notes = replace($notes, $msgPlaceholderMacros . <crlf 2>);
}
// Show query window as often as necessary
$editQuery = "<Manage query list>";
$lastQuery = formatlist(replace($lastQuery, "<::>", <crlf>), "e", <crlf>);
while (true) {
$fstLastQuery = gettoken($lastQuery, 1, <crlf>, "t");
// Add an $editQuery entry on last position
$lastQuery .= (($lastQuery) ? <crlf> . $editQuery : $editQuery);
// Display the query window
$query = showDialog($notes, $fstLastQuery, $lastQuery, $inputIcon);
// If anything apart from $editQuery was chosen from the drop-down list
if ($query UnLikeI $editQuery) { break; }
// Remove $editQuery entry again and edit the list
$lastQuery = formatlist($lastQuery, "F", <crlf>, "!" . $editQuery);
$lastQuery = input("Stored queries", , $lastQuery, "m", $lastQuery, 600, 600);
$lastQuery = formatlist($lastQuery, "e", <crlf>);
}
// Make sure that the $editQuery entry doesn't get saved
$lastQuery = formatlist($lastQuery, "F", <crlf>, "!" . $editQuery);
// Save query (limited to $maxSavedQueries)
$escQuery = regexreplace($query, "([\\.+*|?(){\[^$])", "\$1");
$lastQuery = regexreplace($lastQuery, "^" . $escQuery . "(\r?\n|$)");
$lastQuery = trim($query . <crlf> . $lastQuery, <crlf>);
if (gettoken($lastQuery, "count", <crlf>) > $maxSavedQueries) {
$lastQuery = gettoken($lastQuery, $maxSavedQueries, <crlf>, , 1);
}
$lastQuery = replace($lastQuery, <crlf>, "<::>");
setkey $lastQuery, "LastQuery", "General", $iniFile;
// Make sure a query for a drive at its root level is allowed
if (regexmatches($query, "^(f:|d:)?[ ]*?([a-z]:\\)([ ]+?/f)?$")) {
if ($confirmRootDrive LikeI "true" && !regexmatches($query, "/f$")) {
$msg = <<<>>>
You are trying to query a drive at its root level.
ConfirmRootDrive is set to true in the .ini file
and you did not use the override switch " /f".
Do you really want to execute this query?
>>>;
$msg = regexreplace($msg, "^[ \t]+");
if (!confirm($msg, , 2)) { end true; }
}
}
// Begin execution time
$start = now("yyyy-mm-dd hh:nn:ss.ffff");
// Eval switches
// Expand "d:" -> "folder:"
if (regexmatches($query, "(^[ ]*?|[ ]+?)d:[^\\]")) { $query = regexreplace($query, "[ ]*?d:", " folder:"); }
// Expand "f:" -> "file:"
if (regexmatches($query, "(^[ ]*?|[ ]+?)f:[^\\]")) { $query = regexreplace($query, "[ ]*?f:", " file:"); }
// Expand "c:" -> "content:"
// We can't use "utf16(be)content" here, it is not supported by "es.exe"!
// "es.exe" does support macros (defined via "Search - Organize Filters...")
if (regexmatches($query, "(^[ ]*?|[ ]+?)c:[^\\]")) { $query = regexreplace($query, "[ ]*?c:", " content:"); }
// Expand "l:" -> "$query path:""$curPath"""
// It allows searching even when a paper folder is currently displayed (in this case, it searches everywhere!)
$curPath = (<curpath> LikeI "*paper:*") ? "*" : property("#ResolveJunctionsAll", <curpath>);
if (regexmatches($query, "(^[ ]*?|[ ]+?)l:[^\\]?")) { $query = regexreplace($query, "[ ]*?l:", " path:""$curPath"" "); }
// Expand "w:" -> "systemindex:"
if (regexmatches($query, "(^[ ]*?|[ ]+?)w:[^\\]?")) {
$result = regexreplace(runret("sc query wsearch"), "([\s\S]+?)(state[ ]+?:[ ]+?)(\d+)([\s\S]+)", "$3");
end ($result != 4), "Windows search service not running, aborted!";
$query = regexreplace($query, "[ ]*?w:", " systemindex:");
}
// Smart mode
//$query = regexreplace($query, '\b-(?!([riwps]|n (?!\d))\b)', '"-"');
// Escape characters but only if:
// The "regex:" modifier is not found AND no double quote(s) are found
if (!regexmatches($query, "\bregex:") && !regexmatches($query, "[""]")) {
// Original query | Escaped query | Result
// D:\Temp\archive\d&e | D:\Temp\archive\d^&e | OK
// "D:\Temp\archive\d&e" | "D:\Temp\archive\d^&e" | NOT OK, no result(s)
$query = regexreplace($query, "(<|>|&|\||\^)", "^$1");
}
// Process query
$result = runret("""cmd"" /c chcp 65001 >NUL && ""$es"" $query", "%TEMP%", "65001");
// No match(es)
if (!$result) {
if (regexmatches($query, "path:")) {
msg "No match(es) found...<crlf 2>Maybe location awareness is responsible for this result?";
} else {
msg "No match(es) found...";
}
// Match(es)
} else {
// Open a new paper folder or reuse the existing one
if (<curpath> UnLikeI "*paper:*") { tab("new"); }
paperfolder("paper:$paperFolderName", $result, , "nl");
// Only setup columns if enabled
if ($setupColumns LikeI "true") {
// Setup the visible columns and autosize them if configured
$columns = concatenateEntries($columnLayout, "+");
$flags = 0;
if ($autosizeColumns LikeI "true") { $flags = 16; }
setcolumns($columns, $flags);
// Set (primary and secondary) sort order(s)
$cntSortOrderColumns = gettoken($columnSortOder, "count", ",", "t");
if ($cntSortOrderColumns > 2) { $columnSortOder = gettoken($columnSortOder, 2, ",", "t", 1); }
$i = 0;
while ($j++ < $cntSortOrderColumns) {
$column = gettoken($columnSortOder, $j, ",", "t");
sortby $column, "a", $i;
$i++;
}
}
// End execution time
$diff = round(datediff($start, now("yyyy-mm-dd hh:nn:ss.ffff"), "us") / 1000);
if ($diff < 0) { $diff *= -1; }
status "Query: $query [Time: " . $diff . " ms]";
}
// FUNCTIONS
// =========
function concatenateEntries($list, $prefix="", $sep=",") {
$newList = "";
foreach($entry, $list, $sep, "e") {
$entry = trim($entry);
if ($prefix != "") { $entry = $prefix . $entry; }
$newList .= $entry . $sep;
}
return trim($newList, $sep);
}
// Get filter + search macros from Everything
function getMacros($path, $noteStrToReplace, $macroLinesLength) {
$notes = "";
$filterFile = gettoken(listfolder($path, "Filters*.csv", 1), 1, "|");
if ($filterFile) {
$msgFilterMacros = "Filter macro(s): ";
// Get either an empty string or a <crlf>-separated list of items
$genMacros = replace(getMacrosFromFile($filterFile, "Macro"), <crlf>, ", ");
$ownMacros = replace(getMacrosFromFile($filterFile, "Macro", true), <crlf>, ", ");
if ($genMacros) {
$notes .= $msgFilterMacros . splitString($genMacros, $macroLinesLength, , strlen($msgFilterMacros) . <crlf>);
}
if ($ownMacros) {
if ($genMacros) {
$notes .= <crlf> . strrepeat(" ", strlen($msgFilterMacros)) . splitString($ownMacros, $macroLinesLength, , strlen($msgFilterMacros) . <crlf>);
} else {
$notes .= $msgFilterMacros . splitString($ownMacros, $macroLinesLength, , strlen($msgFilterMacros) . <crlf>);
}
}
}
$macrosFile = gettoken(listfolder($path, "Macros*.csv", 1), 1, "|");
if ($macrosFile) {
$msgSearchMacros = "Search macro(s): ";
$macros = replace(getMacrosFromFile($macrosFile, "Name"), <crlf>, ", ");
if ($macros) {
if ($genMacros || $ownMacros) {
$notes .= <crlf>;
}
$notes .= $msgSearchMacros . splitString($macros, $macroLinesLength, , strlen($msgSearchMacros) . <crlf>);
}
}
return $notes;
}
// Get macros from a specific file
function getMacrosFromFile($file, $colName, $ownMacros=false) {
// Search macros: https://www.voidtools.com/forum/viewtopic.php?f=12&t=9795&p=35397#macro
// Filters column: Name,...,16:=Macro,17:=Key
// Macros column : Name,Search
$content = trim(readfile($file, , , 65001), <crlf>);
$idMacro = gettokenindex($colName, gettoken($content, 1, <crlf>), ",", "i");
$macros = "";
while ($i++ < gettoken($content, "count", <crlf>)) {
$line = trim(gettoken($content, $i, <crlf>));
// Skip column definition
if ($i == 1) { continue; }
$macro = trim(gettoken($line, $idMacro, ",", "t"), '"');
// Our own macros are set up like this: bat<QUERY>
if ($macro) {
if ($ownMacros) {
if (strpos($macro, "<") != -1) {
$macros .= gettoken($macro, 1, "<", "t") . <crlf>;
}
} else {
// Don't try to process own macros here!
if (strpos($macro, "<") == -1) {
$macros .= $macro . <crlf>;
}
}
}
}
return formatlist($macros, "sed", <crlf>);
}
// Split an already separated string into multiple lines with a maximum length
function splitString($string, $maxLen=20, $sep=", ", $prefixSpaces=0) {
if ($maxLen >= strlen($string)) { return $string; }
if (strpos($string, $sep) == -1) { return $string; }
$newStr = "";
while ($string) {
$tmpStr = ""; $nextStr = ""; $i = 0;
while ($i++ < gettoken($string, "count", $sep)) {
// Check if string + the next token would exceed our $maxLen...
if (strlen($nextStr) >= $maxLen) { break; }
$tmpStr .= gettoken($string, $i, $sep) . $sep;
$nextStr = $tmpStr . gettoken($string, $i + 1, $sep);
wait;
}
$tmpStr = trim($tmpStr, $sep, "R");
if (!$newStr) {
$newStr .= $tmpStr . <crlf>;
} else {
$newStr .= strrepeat(" ", $prefixSpaces) . $tmpStr . <crlf>;
}
$string = trim(replace($string, $tmpStr, , 1, 1, 1), $sep, "L");
wait;
}
return trim($newStr, <crlf>);
}
// Show query dialog
function showDialog($notes, $fstLastQuery, $lastQuery, $inputIcon) {
// "e" for the style is accepted without an error even in older instances than "22.00.0006"
// v22.10.0002 is required for [items] as a drop-down field
// v22.10.0005 is required for [icon] (all possible internal & external ones lik png, jpg, gif, ico, and exe as well)
if (compare(<xyver>, "22.10.0005", "v") == -1) {
$query = trim(input("Everything", $notes, ($fstLastQuery) ? $fstLastQuery : "<query>", "e"));
} else {
$query = trim(input("Everything", $notes, ($fstLastQuery) ? $fstLastQuery : "<query>", "e", 7:=$lastQuery, 8:=$inputIcon));
}
end ($query == ""), "No query entered, aborted!";
return $query;
}