From c2b541f908fb4f979025c36e6f631ce77722bc06 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Mon, 18 Dec 2023 02:34:15 +0000 Subject: [PATCH 01/61] Axe some types, clean some handling of defaultFilter --- src/StudioCore/ParamEditor/AutoFill.cs | 29 +++++++++---------- src/StudioCore/ParamEditor/SearchEngine.cs | 33 ++++++++++++++++++++-- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/StudioCore/ParamEditor/AutoFill.cs b/src/StudioCore/ParamEditor/AutoFill.cs index 5db81e908..5b6ce03c5 100644 --- a/src/StudioCore/ParamEditor/AutoFill.cs +++ b/src/StudioCore/ParamEditor/AutoFill.cs @@ -8,16 +8,16 @@ namespace StudioCore.ParamEditor; -internal class AutoFillSearchEngine +internal class AutoFillSearchEngine { private readonly string[] _autoFillArgs; - private readonly SearchEngine engine; + private readonly TypelessSearchEngine engine; private readonly string id; - private AutoFillSearchEngine _additionalCondition; + private AutoFillSearchEngine _additionalCondition; private bool _autoFillNotToggle; private bool _useAdditionalCondition; - internal AutoFillSearchEngine(string id, SearchEngine searchEngine) + internal AutoFillSearchEngine(string id, TypelessSearchEngine searchEngine) { this.id = id; engine = searchEngine; @@ -30,10 +30,10 @@ internal AutoFillSearchEngine(string id, SearchEngine searchEngine) internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, Func subMenu) { - return Menu(enableComplexToggles, null, enableDefault, suffix, inheritedCommand, subMenu); + return Menu(enableComplexToggles, null, enableDefault, suffix, inheritedCommand, subMenu); } - internal string Menu(bool enableComplexToggles, AutoFillSearchEngine multiStageSE, + internal string Menu(bool enableComplexToggles, AutoFillSearchEngine multiStageSE, bool enableDefault, string suffix, string inheritedCommand, Func subMenu) { var currentArgIndex = 0; @@ -52,17 +52,14 @@ internal string Menu(bool enableComplexToggles, AutoFillSearchEngine if (_useAdditionalCondition && _additionalCondition == null) { - _additionalCondition = new AutoFillSearchEngine(id + "0", engine); + _additionalCondition = new AutoFillSearchEngine(id + "0", engine); } else if (!_useAdditionalCondition) { _additionalCondition = null; } - foreach ((string, string[], string) cmd in enableDefault - ? engine.VisibleCommands().Append((null, engine.defaultFilter.args, engine.defaultFilter.wiki)) - .ToList() - : engine.VisibleCommands()) + foreach ((string, string[], string) cmd in engine.VisibleCommands(enableDefault)) { var argIndices = new int[cmd.Item2.Length]; var valid = true; @@ -177,18 +174,18 @@ internal string getCurrentStepText(bool valid, string command, int[] argIndices, internal class AutoFill { // Type hell. Can't omit the type. - private static readonly AutoFillSearchEngine + private static readonly AutoFillSearchEngine autoFillParse = new("parse", ParamAndRowSearchEngine.parse); - private static readonly AutoFillSearchEngine autoFillVse = new("vse", VarSearchEngine.vse); + private static readonly AutoFillSearchEngine autoFillVse = new("vse", VarSearchEngine.vse); - private static readonly AutoFillSearchEngine autoFillPse = + private static readonly AutoFillSearchEngine autoFillPse = new("pse", ParamSearchEngine.pse); - private static readonly AutoFillSearchEngine<(ParamBank, Param), Param.Row> autoFillRse = + private static readonly AutoFillSearchEngine autoFillRse = new("rse", RowSearchEngine.rse); - private static readonly AutoFillSearchEngine<(string, Param.Row), (PseudoColumn, Param.Column)> autoFillCse = + private static readonly AutoFillSearchEngine autoFillCse = new("cse", CellSearchEngine.cse); private static string[] _autoFillArgsGop = Enumerable diff --git a/src/StudioCore/ParamEditor/SearchEngine.cs b/src/StudioCore/ParamEditor/SearchEngine.cs index 594d5844e..91f513e93 100644 --- a/src/StudioCore/ParamEditor/SearchEngine.cs +++ b/src/StudioCore/ParamEditor/SearchEngine.cs @@ -12,8 +12,32 @@ namespace StudioCore.Editor; /* Restricted characters: colon, space, forward slash, ampersand, exclamation mark * */ -internal class SearchEngine +internal abstract class TypelessSearchEngine { + private static Dictionary> searchEngines = new(); + internal static void AddSearchEngine(SearchEngine engine) + { + if (searchEngines.ContainsKey(typeof(I))) + searchEngines.Add(typeof(I), new()); + searchEngines[typeof(I)].Add((engine, typeof(O))); + } + internal static List<(TypelessSearchEngine, Type)> GetSearchEngines(Type t) + { + return searchEngines[t]; + } + internal static List<(HalfTypedSearchEngine, Type)> GetHalfTypedSearchEngines() + { + return searchEngines[typeof(I)].Select((x, i) => ((HalfTypedSearchEngine)x.Item1, x.Item2)).ToList(); + } + public abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); + public abstract List<(string, string[])> AllCommands(); +} +internal abstract class HalfTypedSearchEngine : TypelessSearchEngine +{ +} +internal class SearchEngine : HalfTypedSearchEngine +{ + internal SearchEngineCommand defaultFilter; internal Dictionary> filterList = new(); @@ -22,6 +46,7 @@ internal class SearchEngine public SearchEngine() { Setup(); + AddSearchEngine(this); } protected void addExistsFilter() @@ -79,7 +104,7 @@ public List AvailableCommandsForHelpText() return options; } - public List<(string, string[], string)> VisibleCommands() + public override List<(string, string[], string)> VisibleCommands(bool includeDefault) { List<(string, string[], string)> options = new(); foreach (var op in filterList.Keys) @@ -90,11 +115,13 @@ public List AvailableCommandsForHelpText() options.Add((op, cmd.args, cmd.wiki)); } } + if (includeDefault) + options.Add((null, defaultFilter.args, defaultFilter.wiki)); return options; } - public List<(string, string[])> AllCommands() + public override List<(string, string[])> AllCommands() { List<(string, string[])> options = new(); foreach (var op in filterList.Keys) From 425125e6b51367bc33e6d3100a547f08ce06b4a3 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 28 Dec 2023 16:17:29 +0000 Subject: [PATCH 02/61] MEopDef --- src/StudioCore/ParamEditor/AutoFill.cs | 2 +- src/StudioCore/ParamEditor/MassParamEdit.cs | 69 ++++++++++++++------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/StudioCore/ParamEditor/AutoFill.cs b/src/StudioCore/ParamEditor/AutoFill.cs index 5b6ce03c5..d7ec609ff 100644 --- a/src/StudioCore/ParamEditor/AutoFill.cs +++ b/src/StudioCore/ParamEditor/AutoFill.cs @@ -391,7 +391,7 @@ public static string MassEditOpAutoFill() return MassEditAutoFillForOperation(MEValueOperation.valueOps, ref _autoFillArgsCop, ";", null); } - private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, + private static string MassEditAutoFillForOperation(MEOperationType ops, ref string[] staticArgs, string suffix, Func subMenu) { var currentArgIndex = 0; diff --git a/src/StudioCore/ParamEditor/MassParamEdit.cs b/src/StudioCore/ParamEditor/MassParamEdit.cs index 19c386865..675cb3d93 100644 --- a/src/StudioCore/ParamEditor/MassParamEdit.cs +++ b/src/StudioCore/ParamEditor/MassParamEdit.cs @@ -590,11 +590,24 @@ public static AddParamsAction SortRows(ParamBank bank, string paramName) } } -public class MEOperation +internal class MEOperationDef { - internal Dictionary)> operations = new(); + internal string[] argNames; + internal string wiki; + internal Func function; + internal MEOperationDef(string[] args, string tooltip, Func func) + { + argNames = args; + wiki = tooltip; + function = func; + } +} + +public class MEOperationType +{ + internal Dictionary> operations = new(); - internal MEOperation() + internal MEOperationType() { Setup(); } @@ -613,27 +626,35 @@ internal bool HandlesCommand(string command) List<(string, string[], string)> options = new(); foreach (var op in operations.Keys) { - options.Add((op, operations[op].Item1, operations[op].Item2)); + options.Add((op, operations[op].argNames, operations[op].wiki)); } return options; } + internal MEOperationDef newCmd(string[] args, string wiki, Func func) + { + return new MEOperationDef(args, wiki, func); + } + internal MEOperationDef newCmd(string wiki, Func func) + { + return new MEOperationDef(Array.Empty(), wiki, func); + } } -public class MEGlobalOperation : MEOperation +public class MEGlobalOperation : MEOperationType { public static MEGlobalOperation globalOps = new(); internal override void Setup() { - operations.Add("clear", (new string[0], "Clears clipboard param and rows", (selectionState, args) => + operations.Add("clear", newCmd(new string[0], "Clears clipboard param and rows", (selectionState, args) => { ParamBank.ClipboardParam = null; ParamBank.ClipboardRows.Clear(); return true; } )); - operations.Add("newvar", (new[] { "variable name", "value" }, + operations.Add("newvar", newCmd(new[] { "variable name", "value" }, "Creates a variable with the given value, and the type of that value", (selectionState, args) => { int asInt; @@ -654,7 +675,7 @@ internal override void Setup() return true; } )); - operations.Add("clearvars", (new string[0], "Deletes all variables", (selectionState, args) => + operations.Add("clearvars", newCmd(new string[0], "Deletes all variables", (selectionState, args) => { MassParamEdit.massEditVars.Clear(); return true; @@ -663,13 +684,13 @@ internal override void Setup() } } -public class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> +public class MERowOperation : MEOperationType<(string, Param.Row), (Param, Param.Row)> { public static MERowOperation rowOps = new(); internal override void Setup() { - operations.Add("copy", (new string[0], + operations.Add("copy", newCmd(new string[0], "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", (paramAndRow, args) => { @@ -697,7 +718,7 @@ internal override void Setup() return (p, null); } )); - operations.Add("copyN", (new[] { "count" }, + operations.Add("copyN", newCmd(new[] { "count" }, "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", (paramAndRow, args) => { @@ -730,7 +751,7 @@ internal override void Setup() return (p, null); } )); - operations.Add("paste", (new string[0], + operations.Add("paste", newCmd(new string[0], "Adds the selected rows to the primary regulation or parambnd in the selected param", (paramAndRow, args) => { @@ -753,17 +774,17 @@ internal override void Setup() } } -public class MEValueOperation : MEOperation +public class MEValueOperation : MEOperationType { public static MEValueOperation valueOps = new(); internal override void Setup() { operations.Add("=", - (new[] { "number or text" }, + newCmd(new[] { "number or text" }, "Assigns the given value to the selected values. Will attempt conversion to the value's data type", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => args[0]))); - operations.Add("+", (new[] { "number or text" }, + operations.Add("+", newCmd(new[] { "number or text" }, "Adds the number to the selected values, or appends text if that is the data type of the values", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => { @@ -776,18 +797,18 @@ internal override void Setup() return v + args[0]; }))); operations.Add("-", - (new[] { "number" }, "Subtracts the number from the selected values", + newCmd(new[] { "number" }, "Subtracts the number from the selected values", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v - double.Parse(args[0])))); operations.Add("*", - (new[] { "number" }, "Multiplies selected values by the number", + newCmd(new[] { "number" }, "Multiplies selected values by the number", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v * double.Parse(args[0])))); operations.Add("/", - (new[] { "number" }, "Divides the selected values by the number", + newCmd(new[] { "number" }, "Divides the selected values by the number", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v / double.Parse(args[0])))); operations.Add("%", - (new[] { "number" }, "Gives the remainder when the selected values are divided by the number", + newCmd(new[] { "number" }, "Gives the remainder when the selected values are divided by the number", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v % double.Parse(args[0])))); - operations.Add("scale", (new[] { "factor number", "center number" }, + operations.Add("scale", newCmd(new[] { "factor number", "center number" }, "Multiplies the difference between the selected values and the center number by the factor number", (ctx, args) => { @@ -800,10 +821,10 @@ internal override void Setup() } )); operations.Add("replace", - (new[] { "text to replace", "new text" }, + newCmd(new[] { "text to replace", "new text" }, "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v.Replace(args[0], args[1])))); - operations.Add("replacex", (new[] { "text to replace (regex)", "new text (w/ groups)" }, + operations.Add("replacex", newCmd(new[] { "text to replace (regex)", "new text (w/ groups)" }, "Interprets the selected values as text and replaces all occurances of the given regex with the replacement, supporting regex groups", (ctx, args) => { @@ -812,10 +833,10 @@ internal override void Setup() } )); operations.Add("max", - (new[] { "number" }, "Returns the larger of the current value and number", + newCmd(new[] { "number" }, "Returns the larger of the current value and number", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Max(v, double.Parse(args[0]))))); operations.Add("min", - (new[] { "number" }, "Returns the smaller of the current value and number", + newCmd(new[] { "number" }, "Returns the smaller of the current value and number", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Min(v, double.Parse(args[0]))))); } } From 053ed754808ee78706f77d7ac73de9050b62355b Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 28 Dec 2023 19:05:37 +0000 Subject: [PATCH 03/61] Generify Parse Steps --- src/StudioCore/ParamEditor/AutoFill.cs | 2 +- src/StudioCore/ParamEditor/MassParamEdit.cs | 359 +++++++++----------- src/StudioCore/ParamEditor/SearchEngine.cs | 3 +- 3 files changed, 173 insertions(+), 191 deletions(-) diff --git a/src/StudioCore/ParamEditor/AutoFill.cs b/src/StudioCore/ParamEditor/AutoFill.cs index d7ec609ff..5b6ce03c5 100644 --- a/src/StudioCore/ParamEditor/AutoFill.cs +++ b/src/StudioCore/ParamEditor/AutoFill.cs @@ -391,7 +391,7 @@ public static string MassEditOpAutoFill() return MassEditAutoFillForOperation(MEValueOperation.valueOps, ref _autoFillArgsCop, ";", null); } - private static string MassEditAutoFillForOperation(MEOperationType ops, ref string[] staticArgs, + private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, string suffix, Func subMenu) { var currentArgIndex = 0; diff --git a/src/StudioCore/ParamEditor/MassParamEdit.cs b/src/StudioCore/ParamEditor/MassParamEdit.cs index 675cb3d93..b726a1d23 100644 --- a/src/StudioCore/ParamEditor/MassParamEdit.cs +++ b/src/StudioCore/ParamEditor/MassParamEdit.cs @@ -27,6 +27,55 @@ public MassEditResult(MassEditResultType result, string info) } } +internal class MEParseException : Exception +{ + public MEParseException(string? message, int line) : base($@"{message} (line {line})") + { + } +} + +internal struct MEFilterStage +{ + internal string command; + // No arguments because this is handled separately in SearchEngine + internal MEFilterStage(string toParse, int line, string stageName, TypelessSearchEngine expectedStage) + { + command = toParse.Trim(); + if (command.Equals("")) + { + throw new MEParseException($@"Could not find {stageName} filter. Add : and one of {string.Join(", ", expectedStage.AvailableCommandsForHelpText())}", line); + } + } +} +internal struct MEOperationStage +{ + internal string command; + internal string arguments; + internal MEOperationStage(string toParse, int line, string stageName, METypelessOperation expectedOperation) + { + var stage = toParse.TrimStart().Split(' ', 2); + command = stage[0].Trim(); + arguments = stage[1]; + if (command.Equals("")) + { + throw new MEParseException($@"Could not find operation to perform. Add : and one of {string.Join(' ', expectedOperation.AllCommands().Keys)}", line); + } + if (!expectedOperation.AllCommands().ContainsKey(command)) + { + throw new MEParseException($@"Unknown {stageName} operation {command}", line); + } + } + internal string[] getArguments(int count) + { + return arguments.Split(':', count); + } +} +internal class MECommand +{ + List filters = new(); + MEOperationStage operation; +} + public static class MassParamEdit { public static Dictionary massEditVars = new(); @@ -82,37 +131,26 @@ public static void AppendParamEditAction(this List actions, Param. public class MassParamEditRegex { - private int argc; - - // Run data - private string[] argNames; // Do we want these variables? shouldn't they be contained? private ParamBank bank; - private string cellOperation; - private string cellSelector; private ParamEditorSelectionState context; private Func genericFunc; - private Func globalFunc; - - private string globalOperation; - private Func>>[] paramArgFuncs; - private string paramRowSelector; - - private string paramSelector; - private Func<(string, Param.Row), string[], (Param, Param.Row)> rowFunc; - private string rowOperation; - - private Func[], string, Param.Row, List, MassEditResult> rowOpOrCellStageFunc; + private Func>>[] paramArgFuncs; + private string[] argNames; - private string rowSelector; - private string varOperation; - - // Parsing data - private string varSelector; + private MEOperationStage globalOperationInfo; + private MEOperationStage varOperationInfo; + private MEOperationStage rowOperationInfo; + private MEOperationStage cellOperationInfo; + private MEFilterStage varStageInfo; + private MEFilterStage paramRowStageInfo; + private MEFilterStage paramStageInfo; + private MEFilterStage rowStageInfo; + private MEFilterStage cellStageInfo; public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank bank, string commandsString, ParamEditorSelectionState context) @@ -151,15 +189,43 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseVarStep(currentLine, command); + (result, actions) = ParseFilterStep(currentLine, command, "variable", VarSearchEngine.vse, ref currentEditData.varStageInfo, "var operation", (currentLine, restOfStages) => + { + return currentEditData.ParseVarOpStep(currentLine, restOfStages); + }); } else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseParamRowStep(currentLine, command); + (result, actions) = ParseFilterStep(currentLine, command, "paramrow", ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, "cell filter or row operation", (currentLine, restOfStages) => + { + if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) + { + return currentEditData.ParseRowOpStep(currentLine, restOfStages); + } + return ParseFilterStep(currentLine, restOfStages, "cell/property", CellSearchEngine.cse, ref currentEditData.cellStageInfo, "operation to perform", (currentLine, restOfStages) => + { + currentEditData.rowOpOrCellStageFunc = currentEditData.ExecCellStage; + return currentEditData.ParseCellOpStep(currentLine, restOfStages); + }); + }); } else { - (result, actions) = currentEditData.ParseParamStep(currentLine, command); + (result, actions) = ParseFilterStep(currentLine, command, "param", ParamSearchEngine.pse, ref currentEditData.paramStageInfo, "row filter", (currentLine, restOfStages) => + { + return ParseFilterStep(currentLine, restOfStages, "row", RowSearchEngine.rse, ref currentEditData.rowStageInfo, "cell filter or row operation", (currentLine, restOfStages) => + { + if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) + { + return currentEditData.ParseRowOpStep(currentLine, restOfStages); + } + return ParseFilterStep(currentLine, restOfStages, "cell/property", CellSearchEngine.cse, ref currentEditData.cellStageInfo, "operation to perform", (currentLine, restOfStages) => + { + currentEditData.rowOpOrCellStageFunc = currentEditData.ExecCellStage; + return currentEditData.ParseCellOpStep(currentLine, restOfStages); + }); + }); + }); } if (result.Type != MassEditResultType.SUCCESS) @@ -175,199 +241,105 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } catch (Exception e) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Unknown parsing error on line {currentLine}: " + e.ToString()), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, e.ToString()), null); } } - private (MassEditResult, List) ParseGlobalOpStep(int currentLine, string restOfStages) + private static (MassEditResult, List) ParseFilterStep(int currentLine, string restOfStages, string stageName, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, string expectedNextStageName, Func)> nextStageFunc) { - var opStage = restOfStages.Split(" ", 2); - globalOperation = opStage[0].Trim(); - if (!MEGlobalOperation.globalOps.operations.ContainsKey(globalOperation)) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Unknown global operation {globalOperation} (line {currentLine})"), null); - } + var stage = restOfStages.Split(":", 2); + target = new MEFilterStage(stage[0], currentLine, stageName, expectedSearchEngine); - string wiki; - (argNames, wiki, globalFunc) = MEGlobalOperation.globalOps.operations[globalOperation]; - ExecParamOperationArguments(currentLine, opStage.Length > 1 ? opStage[1] : null); - if (argc != paramArgFuncs.Length) + if (stage.Length < 2) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperation} (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {expectedNextStageName}. Check your colon placement. (line {currentLine})"), null); } - return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); + return nextStageFunc(currentLine, stage[1]); } - - private (MassEditResult, List) ParseVarStep(int currentLine, string restOfStages) + private (MassEditResult, List) ParseOpStep(int currentLine, string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target, ref string[] argNameTarget, ref Func funcTarget) { - var varstage = restOfStages.Split(":", 2); - varSelector = varstage[0].Trim(); - if (varSelector.Equals("")) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find variable filter. Add : and one of {String.Join(", ", VarSearchEngine.vse.AvailableCommandsForHelpText())} (line {currentLine})"), null); - } + target = new MEOperationStage(restOfStages, currentLine, stageName, operation); - if (varstage.Length < 2) + var meOpDef = operation.AllCommands()[target.command]; + (argNameTarget, funcTarget) = (meOpDef.argNames, meOpDef.function); + ExecParamOperationArguments(currentLine, globalOperationInfo.arguments); + if (argNameTarget.Length != paramArgFuncs.Length) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find var operation. Check your colon placement. (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); } - return ParseVarOpStep(currentLine, varstage[1]); - } - - private (MassEditResult, List) ParseVarOpStep(int currentLine, string restOfStages) - { - var operationstage = restOfStages.TrimStart().Split(" ", 2); - varOperation = operationstage[0].Trim(); - if (varOperation.Equals("") || !MEValueOperation.valueOps.operations.ContainsKey(varOperation)) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find operation to perform. Add : and one of + - * / replace (line {currentLine})"), null); - } - - string wiki; - (argNames, wiki, genericFunc) = MEValueOperation.valueOps.operations[varOperation]; - ExecParamOperationArguments(currentLine, operationstage.Length > 1 ? operationstage[1] : null); - if (argc != paramArgFuncs.Length) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {varOperation} (line {currentLine})"), null); - } - - return SandboxMassEditExecution(currentLine, partials => ExecVarStage(currentLine)); - } - - private (MassEditResult, List) ParseParamRowStep(int currentLine, string restOfStages) - { - var paramrowstage = restOfStages.Split(":", 2); - paramRowSelector = paramrowstage[0].Trim(); - if (paramRowSelector.Equals("")) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find paramrow filter. Add : and one of {String.Join(", ", ParamAndRowSearchEngine.parse.AvailableCommandsForHelpText())} (line {currentLine})"), null); - } - - if (paramrowstage.Length < 2) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find cell filter or row operation. Check your colon placement. (line {currentLine})"), null); - } - - if (MERowOperation.rowOps.HandlesCommand(paramrowstage[1].Trim().Split(" ", 2)[0])) - { - return ParseRowOpStep(currentLine, paramrowstage[1]); - } - - return ParseCellStep(currentLine, paramrowstage[1]); - } - - private (MassEditResult, List) ParseParamStep(int currentLine, string restOfStages) - { - var paramstage = restOfStages.Split(":", 2); - paramSelector = paramstage[0].Trim(); - if (paramSelector.Equals("")) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find param filter. Add : and one of {String.Join(", ", ParamSearchEngine.pse.AvailableCommandsForHelpText())} (line {currentLine})"), null); - } - - if (paramstage.Length < 2) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find row filter. Check your colon placement. (line {currentLine})"), null); - } - - return ParseRowStep(currentLine, paramstage[1]); + return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); } - private (MassEditResult, List) ParseRowStep(int currentLine, string restOfStages) + private (MassEditResult, List) ParseGlobalOpStep(int currentLine, string restOfStages) { - var rowstage = restOfStages.Split(":", 2); - rowSelector = rowstage[0].Trim(); - if (rowSelector.Equals("")) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find row filter. Add : and one of {String.Join(", ", RowSearchEngine.rse.AvailableCommandsForHelpText())} (line {currentLine})"), null); - } - - if (rowstage.Length < 2) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find cell filter or row operation to perform. Check your colon placement. (line {currentLine})"), null); - } + globalOperationInfo = new MEOperationStage(restOfStages, currentLine, "global", MEGlobalOperation.globalOps); - if (MERowOperation.rowOps.HandlesCommand(rowstage[1].Trim().Split(" ", 2)[0])) + var meOpDef = MEGlobalOperation.globalOps.operations[globalOperationInfo.command]; + (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); + ExecParamOperationArguments(currentLine, globalOperationInfo.arguments); + if (argNames.Length != paramArgFuncs.Length) { - return ParseRowOpStep(currentLine, rowstage[1]); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); } - return ParseCellStep(currentLine, rowstage[1]); + return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); } - private (MassEditResult, List) ParseCellStep(int currentLine, string restOfStages) + private (MassEditResult, List) ParseVarOpStep(int currentLine, string restOfStages) { - var cellstage = restOfStages.Split(":", 2); - cellSelector = cellstage[0].Trim(); - if (cellSelector.Equals("")) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find cell/property filter. Add : and one of {String.Join(", ", CellSearchEngine.cse.AvailableCommandsForHelpText())} or Name (0 args) (line {currentLine})"), null); - } + varOperationInfo = new MEOperationStage(restOfStages, currentLine, "var", MEValueOperation.valueOps); - if (cellstage.Length < 2) + var meOpDef = MEValueOperation.valueOps.operations[varOperationInfo.command]; + (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); + ExecParamOperationArguments(currentLine, varOperationInfo.arguments); + if (argNames.Length != paramArgFuncs.Length) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find operation to perform. Check your colon placement. (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {varOperationInfo} (line {currentLine})"), null); } - rowOpOrCellStageFunc = ExecCellStage; - return ParseCellOpStep(currentLine, cellstage[1]); + return SandboxMassEditExecution(currentLine, partials => ExecVarStage(currentLine)); } private (MassEditResult, List) ParseRowOpStep(int currentLine, string restOfStages) { var operationstage = restOfStages.TrimStart().Split(" ", 2); - rowOperation = operationstage[0].Trim(); - if (!MERowOperation.rowOps.operations.ContainsKey(rowOperation)) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Unknown row operation {rowOperation} (line {currentLine})"), null); - } + rowOperationInfo = new MEOperationStage(restOfStages, currentLine, "row", MERowOperation.rowOps); - string wiki; - (argNames, wiki, rowFunc) = MERowOperation.rowOps.operations[rowOperation]; + var meOpDef = MERowOperation.rowOps.operations[rowOperationInfo.command]; + (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); ExecParamOperationArguments(currentLine, operationstage.Length > 1 ? operationstage[1] : null); - if (argc != paramArgFuncs.Length) + if (argNames.Length != paramArgFuncs.Length) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {rowOperation} (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {rowOperationInfo} (line {currentLine})"), null); } rowOpOrCellStageFunc = ExecRowOp; return SandboxMassEditExecution(currentLine, partials => - paramRowSelector != null ? ExecParamRowStage(currentLine, partials) : ExecParamStage(currentLine, partials)); + paramRowStageInfo.command != null ? ExecParamRowStage(currentLine, partials) : ExecParamStage(currentLine, partials)); } private (MassEditResult, List) ParseCellOpStep(int currentLine, string restOfStages) { var operationstage = restOfStages.TrimStart().Split(" ", 2); - cellOperation = operationstage[0].Trim(); + cellOperationInfo = new MEOperationStage(restOfStages, currentLine, "cell/property", MEValueOperation.valueOps); - if (cellOperation.Equals("") || !MEValueOperation.valueOps.operations.ContainsKey(cellOperation)) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find operation to perform. Add : and one of + - * / replace (line {currentLine})"), null); - } - - if (!MEValueOperation.valueOps.operations.ContainsKey(cellOperation)) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Unknown cell operation {cellOperation} (line {currentLine})"), null); - } - - string wiki; - (argNames, wiki, genericFunc) = MEValueOperation.valueOps.operations[cellOperation]; + var meOpDef = MEValueOperation.valueOps.operations[cellOperationInfo.command]; + (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); ExecParamOperationArguments(currentLine, operationstage.Length > 1 ? operationstage[1] : null); - if (argc != paramArgFuncs.Length) + if (argNames.Length != paramArgFuncs.Length) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {cellOperation} (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {cellOperationInfo} (line {currentLine})"), null); } return SandboxMassEditExecution(currentLine, partials => - paramRowSelector != null ? ExecParamRowStage(currentLine, partials) : ExecParamStage(currentLine, partials)); + paramRowStageInfo.command != null ? ExecParamRowStage(currentLine, partials) : ExecParamStage(currentLine, partials)); } private void ExecParamOperationArguments(int currentLine, string opargs) { - argc = argNames.Length; - paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argc, opargs); + paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argNames.Length, opargs); } private (MassEditResult, List) SandboxMassEditExecution(int currentLine, @@ -391,10 +363,10 @@ private MassEditResult ExecGlobalOp(int currentLine) { var globalArgValues = paramArgFuncs.Select(f => f(-1, null)(-1, null)(-1, (PseudoColumn.None, null))) .ToArray(); - var result = globalFunc(context, globalArgValues); + var result = (bool)genericFunc(context, globalArgValues); if (!result) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperation} (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {currentLine})"); } return new MassEditResult(MassEditResultType.SUCCESS, ""); @@ -405,7 +377,7 @@ private MassEditResult ExecVarStage(int currentLine) ; var varArgs = paramArgFuncs .Select((func, i) => func(-1, null)(-1, null)(-1, (PseudoColumn.None, null))).ToArray(); - foreach (var varName in VarSearchEngine.vse.Search(false, varSelector, false, false)) + foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) { MassEditResult res = ExecVarOpStage(currentLine, varName, varArgs); if (res.Type != MassEditResultType.SUCCESS) @@ -423,7 +395,7 @@ private MassEditResult ExecVarOpStage(int currentLine, string var, string[] args var result = true; // Anything that practicably can go wrong if (!result) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperation} (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperationInfo} (line {currentLine})"); } return new MassEditResult(MassEditResultType.SUCCESS, ""); @@ -436,7 +408,7 @@ private MassEditResult ExecParamRowStage(int currentLine, List par paramArgFuncs.Select((func, i) => func(0, activeParam)); // technically invalid for clipboard var rowEditCount = -1; foreach ((MassEditRowSource source, Param.Row row) in ParamAndRowSearchEngine.parse.Search(context, - paramRowSelector, false, false)) + paramRowStageInfo.command, false, false)) { rowEditCount++; Func[] rowArgFunc = @@ -457,13 +429,13 @@ private MassEditResult ExecParamRowStage(int currentLine, List par private MassEditResult ExecParamStage(int currentLine, List partialActions) { var paramEditCount = -1; - var operationForPrint = rowOperation != null ? rowOperation : cellOperation; - foreach ((ParamBank b, Param p) in ParamSearchEngine.pse.Search(false, paramSelector, false, false)) + var operationForPrint = rowOperationInfo.command != null ? rowOperationInfo : cellOperationInfo; + foreach ((ParamBank b, Param p) in ParamSearchEngine.pse.Search(false, paramStageInfo.command, false, false)) { paramEditCount++; IEnumerable>> paramArgFunc = paramArgFuncs.Select((func, i) => func(paramEditCount, p)); - if (argc != paramArgFuncs.Length) + if (argNames.Length != paramArgFuncs.Length) { return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {operationForPrint} (line {currentLine})"); } @@ -484,7 +456,7 @@ private MassEditResult ExecRowStage(int currentLine, string paramname, ParamBank b, Param p, List partialActions) { var rowEditCount = -1; - foreach (Param.Row row in RowSearchEngine.rse.Search((b, p), rowSelector, false, false)) + foreach (Param.Row row in RowSearchEngine.rse.Search((b, p), rowStageInfo.command, false, false)) { rowEditCount++; Func[] rowArgFunc = @@ -503,10 +475,10 @@ private MassEditResult ExecRowOp(int currentLine, Func partialActions) { var rowArgValues = rowArgFunc.Select((argV, i) => argV(-1, (PseudoColumn.None, null))).ToArray(); - (Param? p2, Param.Row? rs) = rowFunc((paramname, row), rowArgValues); + (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); if (p2 == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperation} {String.Join(' ', rowArgValues)} on row (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo} {String.Join(' ', rowArgValues)} on row (line {currentLine})"); } if (rs != null) @@ -521,7 +493,7 @@ private MassEditResult ExecCellStage(int currentLine, Func partialActions) { var cellEditCount = -1; - foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search((paramname, row), cellSelector, + foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search((paramname, row), cellStageInfo.command, false, false)) { cellEditCount++; @@ -560,17 +532,17 @@ private MassEditResult ExecCellOp(int currentLine, string[] cellArgValues, strin if (res == null && col.Item1 == PseudoColumn.ID) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperation} {String.Join(' ', cellArgValues)} on ID ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo} {String.Join(' ', cellArgValues)} on ID ({errHelper}) (line {currentLine})"); } if (res == null && col.Item1 == PseudoColumn.Name) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperation} {String.Join(' ', cellArgValues)} on Name ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo} {String.Join(' ', cellArgValues)} on Name ({errHelper}) (line {currentLine})"); } if (res == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperation} {String.Join(' ', cellArgValues)} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo} {String.Join(' ', cellArgValues)} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); } partialActions.AppendParamEditAction(row, col, res); @@ -589,25 +561,30 @@ public static AddParamsAction SortRows(ParamBank bank, string paramName) true); //appending same params and allowing overwrite } } - -internal class MEOperationDef +internal abstract class METypelessOperationDef { internal string[] argNames; internal string wiki; - internal Func function; + internal Func function; +} +internal class MEOperationDef : METypelessOperationDef +{ internal MEOperationDef(string[] args, string tooltip, Func func) { argNames = args; wiki = tooltip; - function = func; + function = func as Func; } } - -public class MEOperationType +public abstract class METypelessOperation { - internal Dictionary> operations = new(); + internal abstract Dictionary AllCommands(); +} +public class MEOperation : METypelessOperation +{ + internal Dictionary operations = new(); - internal MEOperationType() + internal MEOperation() { Setup(); } @@ -620,6 +597,10 @@ internal bool HandlesCommand(string command) { return operations.ContainsKey(command); } + internal override Dictionary AllCommands() + { + return operations; + } public List<(string, string[], string)> AvailableCommands() { @@ -641,7 +622,7 @@ internal MEOperationDef newCmd(string wiki, Func func) } } -public class MEGlobalOperation : MEOperationType +public class MEGlobalOperation : MEOperation { public static MEGlobalOperation globalOps = new(); @@ -684,7 +665,7 @@ internal override void Setup() } } -public class MERowOperation : MEOperationType<(string, Param.Row), (Param, Param.Row)> +public class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> { public static MERowOperation rowOps = new(); @@ -774,7 +755,7 @@ internal override void Setup() } } -public class MEValueOperation : MEOperationType +public class MEValueOperation : MEOperation { public static MEValueOperation valueOps = new(); diff --git a/src/StudioCore/ParamEditor/SearchEngine.cs b/src/StudioCore/ParamEditor/SearchEngine.cs index 91f513e93..3eda7e00e 100644 --- a/src/StudioCore/ParamEditor/SearchEngine.cs +++ b/src/StudioCore/ParamEditor/SearchEngine.cs @@ -31,6 +31,7 @@ internal static void AddSearchEngine(SearchEngine engine) } public abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); public abstract List<(string, string[])> AllCommands(); + public abstract List AvailableCommandsForHelpText(); } internal abstract class HalfTypedSearchEngine : TypelessSearchEngine { @@ -84,7 +85,7 @@ public bool HandlesCommand(string command) return filterList.ContainsKey(command.Split(" ")[0]); } - public List AvailableCommandsForHelpText() + public override List AvailableCommandsForHelpText() { List options = new(); foreach (var op in filterList.Keys) From 754509ef822a8187e8efffe0d5763759b9fcdef8 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 28 Dec 2023 19:08:07 +0000 Subject: [PATCH 04/61] critical typo --- src/StudioCore/ParamEditor/SearchEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StudioCore/ParamEditor/SearchEngine.cs b/src/StudioCore/ParamEditor/SearchEngine.cs index 3eda7e00e..0839796fe 100644 --- a/src/StudioCore/ParamEditor/SearchEngine.cs +++ b/src/StudioCore/ParamEditor/SearchEngine.cs @@ -17,7 +17,7 @@ internal abstract class TypelessSearchEngine private static Dictionary> searchEngines = new(); internal static void AddSearchEngine(SearchEngine engine) { - if (searchEngines.ContainsKey(typeof(I))) + if (!searchEngines.ContainsKey(typeof(I))) searchEngines.Add(typeof(I), new()); searchEngines[typeof(I)].Add((engine, typeof(O))); } From b86303a458d779c13b0f13f9906db15cbcd07046 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 11 Jan 2024 09:34:06 +0000 Subject: [PATCH 05/61] Get rid of halftype --- src/StudioCore/ParamEditor/SearchEngine.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/StudioCore/ParamEditor/SearchEngine.cs b/src/StudioCore/ParamEditor/SearchEngine.cs index 0839796fe..246525838 100644 --- a/src/StudioCore/ParamEditor/SearchEngine.cs +++ b/src/StudioCore/ParamEditor/SearchEngine.cs @@ -25,18 +25,12 @@ internal static void AddSearchEngine(SearchEngine engine) { return searchEngines[t]; } - internal static List<(HalfTypedSearchEngine, Type)> GetHalfTypedSearchEngines() - { - return searchEngines[typeof(I)].Select((x, i) => ((HalfTypedSearchEngine)x.Item1, x.Item2)).ToList(); - } public abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); public abstract List<(string, string[])> AllCommands(); public abstract List AvailableCommandsForHelpText(); + public abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); } -internal abstract class HalfTypedSearchEngine : TypelessSearchEngine -{ -} -internal class SearchEngine : HalfTypedSearchEngine +internal class SearchEngine : TypelessSearchEngine { internal SearchEngineCommand defaultFilter; @@ -215,6 +209,11 @@ public virtual List Search(A context, List sourceSet, string command, bool return liveSet; } + + public override List<(TypelessSearchEngine, Type)> NextSearchEngines() + { + return GetSearchEngines(typeof(B)); + } } internal class SearchEngineCommand From 7e78a5806a65e0602a254dfd58957ba0518a9fd4 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 11 Jan 2024 09:40:49 +0000 Subject: [PATCH 06/61] Move massedit/search related code to its own folder. Use this commit for diff checking. --- src/StudioCore/{ParamEditor => Editor/MassEdit}/AutoFill.cs | 2 +- .../MassParamEdit.cs => Editor/MassEdit/MassEdit.cs} | 3 ++- .../{ParamEditor => Editor/MassEdit}/SearchEngine.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) rename src/StudioCore/{ParamEditor => Editor/MassEdit}/AutoFill.cs (99%) rename src/StudioCore/{ParamEditor/MassParamEdit.cs => Editor/MassEdit/MassEdit.cs} (99%) rename src/StudioCore/{ParamEditor => Editor/MassEdit}/SearchEngine.cs (99%) diff --git a/src/StudioCore/ParamEditor/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs similarity index 99% rename from src/StudioCore/ParamEditor/AutoFill.cs rename to src/StudioCore/Editor/MassEdit/AutoFill.cs index 5b6ce03c5..cf97b934c 100644 --- a/src/StudioCore/ParamEditor/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Numerics; -namespace StudioCore.ParamEditor; +namespace StudioCore.Editor.MassEdit; internal class AutoFillSearchEngine { diff --git a/src/StudioCore/ParamEditor/MassParamEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs similarity index 99% rename from src/StudioCore/ParamEditor/MassParamEdit.cs rename to src/StudioCore/Editor/MassEdit/MassEdit.cs index b726a1d23..6b679dea4 100644 --- a/src/StudioCore/ParamEditor/MassParamEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -1,12 +1,13 @@ #nullable enable using Andre.Formats; using StudioCore.Editor; +using StudioCore.ParamEditor; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -namespace StudioCore.ParamEditor; +namespace StudioCore.Editor.MassEdit; public enum MassEditResultType { diff --git a/src/StudioCore/ParamEditor/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs similarity index 99% rename from src/StudioCore/ParamEditor/SearchEngine.cs rename to src/StudioCore/Editor/MassEdit/SearchEngine.cs index 246525838..0e5d7f5a2 100644 --- a/src/StudioCore/ParamEditor/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Text.RegularExpressions; -namespace StudioCore.Editor; +namespace StudioCore.Editor.MassEdit; /* Restricted characters: colon, space, forward slash, ampersand, exclamation mark * From 58408fcd85010a698dfd90e40e667e3a764ab7af Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 11 Jan 2024 09:42:46 +0000 Subject: [PATCH 07/61] Fix build from namespace move --- src/StudioCore/Editor/EditorDecorations.cs | 1 + src/StudioCore/ParamEditor/ParamBank.cs | 1 + src/StudioCore/ParamEditor/ParamEditorScreen.cs | 1 + src/StudioCore/ParamEditor/ParamEditorView.cs | 1 + src/StudioCore/ParamEditor/ParamIO.cs | 1 + src/StudioCore/ParamEditor/ParamRowEditor.cs | 1 + 6 files changed, 6 insertions(+) diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index 212e2c918..fff730931 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -4,6 +4,7 @@ using SoulsFormats; using StudioCore.ParamEditor; using StudioCore.TextEditor; +using StudioCore.Editor.MassEdit; using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/StudioCore/ParamEditor/ParamBank.cs b/src/StudioCore/ParamEditor/ParamBank.cs index 40bed3367..52803ada6 100644 --- a/src/StudioCore/ParamEditor/ParamBank.cs +++ b/src/StudioCore/ParamEditor/ParamBank.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using SoulsFormats; using StudioCore.Editor; +using StudioCore.Editor.MassEdit; using StudioCore.Platform; using StudioCore.TextEditor; using System; diff --git a/src/StudioCore/ParamEditor/ParamEditorScreen.cs b/src/StudioCore/ParamEditor/ParamEditorScreen.cs index 618c66de3..01c9959a1 100644 --- a/src/StudioCore/ParamEditor/ParamEditorScreen.cs +++ b/src/StudioCore/ParamEditor/ParamEditorScreen.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using SoulsFormats; using StudioCore.Editor; +using StudioCore.Editor.MassEdit; using StudioCore.MsbEditor; using StudioCore.Platform; using StudioCore.TextEditor; diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index 7a811e82b..a216860c5 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -1,6 +1,7 @@ using Andre.Formats; using ImGuiNET; using StudioCore.Editor; +using StudioCore.Editor.MassEdit; using StudioCore.Platform; using System; using System.Collections.Generic; diff --git a/src/StudioCore/ParamEditor/ParamIO.cs b/src/StudioCore/ParamEditor/ParamIO.cs index d69e352fd..ac9a73ed1 100644 --- a/src/StudioCore/ParamEditor/ParamIO.cs +++ b/src/StudioCore/ParamEditor/ParamIO.cs @@ -2,6 +2,7 @@ using Andre.Formats; using SoulsFormats; using StudioCore.Editor; +using StudioCore.Editor.MassEdit; using System; using System.Collections.Generic; diff --git a/src/StudioCore/ParamEditor/ParamRowEditor.cs b/src/StudioCore/ParamEditor/ParamRowEditor.cs index 9eedda230..4c12feef6 100644 --- a/src/StudioCore/ParamEditor/ParamRowEditor.cs +++ b/src/StudioCore/ParamEditor/ParamRowEditor.cs @@ -2,6 +2,7 @@ using ImGuiNET; using SoulsFormats; using StudioCore.Editor; +using StudioCore.Editor.MassEdit; using System; using System.Collections.Generic; using System.Linq; From d48fda7758b987fdbf2080fdd06248f722d0f7a4 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 11 Jan 2024 09:46:52 +0000 Subject: [PATCH 08/61] Split operations into their own file, akin to searchengine --- .../Editor/MassEdit/EditOperation.cs | 723 ++++++++++++++++++ src/StudioCore/Editor/MassEdit/MassEdit.cs | 712 ----------------- 2 files changed, 723 insertions(+), 712 deletions(-) create mode 100644 src/StudioCore/Editor/MassEdit/EditOperation.cs diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs new file mode 100644 index 000000000..ae49b36b7 --- /dev/null +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -0,0 +1,723 @@ +#nullable enable +using Andre.Formats; +using StudioCore.Editor; +using StudioCore.ParamEditor; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace StudioCore.Editor.MassEdit; + +internal abstract class METypelessOperationDef +{ + internal string[] argNames; + internal string wiki; + internal Func function; +} +internal class MEOperationDef : METypelessOperationDef +{ + internal MEOperationDef(string[] args, string tooltip, Func func) + { + argNames = args; + wiki = tooltip; + function = func as Func; + } +} +public abstract class METypelessOperation +{ + internal abstract Dictionary AllCommands(); +} +public class MEOperation : METypelessOperation +{ + internal Dictionary operations = new(); + + internal MEOperation() + { + Setup(); + } + + internal virtual void Setup() + { + } + + internal bool HandlesCommand(string command) + { + return operations.ContainsKey(command); + } + internal override Dictionary AllCommands() + { + return operations; + } + + public List<(string, string[], string)> AvailableCommands() + { + List<(string, string[], string)> options = new(); + foreach (var op in operations.Keys) + { + options.Add((op, operations[op].argNames, operations[op].wiki)); + } + + return options; + } + internal MEOperationDef newCmd(string[] args, string wiki, Func func) + { + return new MEOperationDef(args, wiki, func); + } + internal MEOperationDef newCmd(string wiki, Func func) + { + return new MEOperationDef(Array.Empty(), wiki, func); + } +} + +public class MEGlobalOperation : MEOperation +{ + public static MEGlobalOperation globalOps = new(); + + internal override void Setup() + { + operations.Add("clear", newCmd(new string[0], "Clears clipboard param and rows", (selectionState, args) => + { + ParamBank.ClipboardParam = null; + ParamBank.ClipboardRows.Clear(); + return true; + } + )); + operations.Add("newvar", newCmd(new[] { "variable name", "value" }, + "Creates a variable with the given value, and the type of that value", (selectionState, args) => + { + int asInt; + double asDouble; + if (int.TryParse(args[1], out asInt)) + { + MassParamEdit.massEditVars[args[0]] = asInt; + } + else if (double.TryParse(args[1], out asDouble)) + { + MassParamEdit.massEditVars[args[0]] = asDouble; + } + else + { + MassParamEdit.massEditVars[args[0]] = args[1]; + } + + return true; + } + )); + operations.Add("clearvars", newCmd(new string[0], "Deletes all variables", (selectionState, args) => + { + MassParamEdit.massEditVars.Clear(); + return true; + } + )); + } +} + +public class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> +{ + public static MERowOperation rowOps = new(); + + internal override void Setup() + { + operations.Add("copy", newCmd(new string[0], + "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", + (paramAndRow, args) => + { + var paramKey = paramAndRow.Item1; + Param.Row row = paramAndRow.Item2; + if (paramKey == null) + { + throw new Exception(@"Could not locate param"); + } + + if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) + { + throw new Exception($@"Could not locate param {paramKey}"); + } + + Param p = ParamBank.PrimaryBank.Params[paramKey]; + // Only supporting single param in clipboard + if (ParamBank.ClipboardParam != paramKey) + { + ParamBank.ClipboardParam = paramKey; + ParamBank.ClipboardRows.Clear(); + } + + ParamBank.ClipboardRows.Add(new Param.Row(row, p)); + return (p, null); + } + )); + operations.Add("copyN", newCmd(new[] { "count" }, + "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", + (paramAndRow, args) => + { + var paramKey = paramAndRow.Item1; + Param.Row row = paramAndRow.Item2; + if (paramKey == null) + { + throw new Exception(@"Could not locate param"); + } + + if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) + { + throw new Exception($@"Could not locate param {paramKey}"); + } + + var count = uint.Parse(args[0]); + Param p = ParamBank.PrimaryBank.Params[paramKey]; + // Only supporting single param in clipboard + if (ParamBank.ClipboardParam != paramKey) + { + ParamBank.ClipboardParam = paramKey; + ParamBank.ClipboardRows.Clear(); + } + + for (var i = 0; i < count; i++) + { + ParamBank.ClipboardRows.Add(new Param.Row(row, p)); + } + + return (p, null); + } + )); + operations.Add("paste", newCmd(new string[0], + "Adds the selected rows to the primary regulation or parambnd in the selected param", + (paramAndRow, args) => + { + var paramKey = paramAndRow.Item1; + Param.Row row = paramAndRow.Item2; + if (paramKey == null) + { + throw new Exception(@"Could not locate param"); + } + + if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) + { + throw new Exception($@"Could not locate param {paramKey}"); + } + + Param p = ParamBank.PrimaryBank.Params[paramKey]; + return (p, new Param.Row(row, p)); + } + )); + } +} + +public class MEValueOperation : MEOperation +{ + public static MEValueOperation valueOps = new(); + + internal override void Setup() + { + operations.Add("=", + newCmd(new[] { "number or text" }, + "Assigns the given value to the selected values. Will attempt conversion to the value's data type", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => args[0]))); + operations.Add("+", newCmd(new[] { "number or text" }, + "Adds the number to the selected values, or appends text if that is the data type of the values", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => + { + double val; + if (double.TryParse(args[0], out val)) + { + return v + val; + } + + return v + args[0]; + }))); + operations.Add("-", + newCmd(new[] { "number" }, "Subtracts the number from the selected values", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v - double.Parse(args[0])))); + operations.Add("*", + newCmd(new[] { "number" }, "Multiplies selected values by the number", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v * double.Parse(args[0])))); + operations.Add("/", + newCmd(new[] { "number" }, "Divides the selected values by the number", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v / double.Parse(args[0])))); + operations.Add("%", + newCmd(new[] { "number" }, "Gives the remainder when the selected values are divided by the number", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v % double.Parse(args[0])))); + operations.Add("scale", newCmd(new[] { "factor number", "center number" }, + "Multiplies the difference between the selected values and the center number by the factor number", + (ctx, args) => + { + var opp1 = double.Parse(args[0]); + var opp2 = double.Parse(args[1]); + return MassParamEdit.WithDynamicOf(ctx, v => + { + return ((v - opp2) * opp1) + opp2; + }); + } + )); + operations.Add("replace", + newCmd(new[] { "text to replace", "new text" }, + "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v.Replace(args[0], args[1])))); + operations.Add("replacex", newCmd(new[] { "text to replace (regex)", "new text (w/ groups)" }, + "Interprets the selected values as text and replaces all occurances of the given regex with the replacement, supporting regex groups", + (ctx, args) => + { + Regex rx = new(args[0]); + return MassParamEdit.WithDynamicOf(ctx, v => rx.Replace(v, args[1])); + } + )); + operations.Add("max", + newCmd(new[] { "number" }, "Returns the larger of the current value and number", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Max(v, double.Parse(args[0]))))); + operations.Add("min", + newCmd(new[] { "number" }, "Returns the smaller of the current value and number", + (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Min(v, double.Parse(args[0]))))); + } +} + +public class MEOperationArgument +{ + public static MEOperationArgument arg = new(); + private readonly Dictionary argumentGetters = new(); + private OperationArgumentGetter defaultGetter; + + private MEOperationArgument() + { + Setup(); + } + + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>>> + func, Func shouldShow = null) + { + return new OperationArgumentGetter(args, wiki, func, shouldShow); + } + + private void Setup() + { + defaultGetter = newGetter(new string[0], "Gives the specified value", + value => (i, param) => (j, row) => (k, col) => value[0]); + argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", + empty => (i, param) => (j, row) => (k, col) => + { + return row.Get(col).ToParamEditorString(); + })); + argumentGetters.Add("field", newGetter(new[] { "field internalName" }, + "Gives the value of the given cell/field for the currently selected row and param", field => + (i, param) => + { + (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + return (j, row) => + { + var v = row.Get(col).ToParamEditorString(); + return (k, c) => v; + }; + })); + argumentGetters.Add("vanilla", newGetter(new string[0], + "Gives the value of the equivalent cell/field in the vanilla regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", + empty => + { + ParamBank bank = ParamBank.VanillaBank; + return (i, param) => + { + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + if (!bank.Params.ContainsKey(paramName)) + { + throw new Exception($@"Could not locate vanilla param for {param.ParamType}"); + } + + Param vParam = bank.Params[paramName]; + return (j, row) => + { + Param.Row vRow = vParam?[row.ID]; + if (vRow == null) + { + throw new Exception($@"Could not locate vanilla row {row.ID}"); + } + + return (k, col) => + { + if (col.Item1 == PseudoColumn.None && col.Item2 == null) + { + throw new Exception(@"Could not locate given field or property"); + } + + return vRow.Get(col).ToParamEditorString(); + }; + }; + }; + })); + argumentGetters.Add("aux", newGetter(new[] { "parambank name" }, + "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", + bankName => + { + if (!ParamBank.AuxBanks.ContainsKey(bankName[0])) + { + throw new Exception($@"Could not locate paramBank {bankName[0]}"); + } + + ParamBank bank = ParamBank.AuxBanks[bankName[0]]; + return (i, param) => + { + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + if (!bank.Params.ContainsKey(paramName)) + { + throw new Exception($@"Could not locate aux param for {param.ParamType}"); + } + + Param vParam = bank.Params[paramName]; + return (j, row) => + { + Param.Row vRow = vParam?[row.ID]; + if (vRow == null) + { + throw new Exception($@"Could not locate aux row {row.ID}"); + } + + return (k, col) => + { + if (!col.IsColumnValid()) + { + throw new Exception(@"Could not locate given field or property"); + } + + return vRow.Get(col).ToParamEditorString(); + }; + }; + }; + }, () => ParamBank.AuxBanks.Count > 0)); + argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, + "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", + field => (i, param) => + { + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + Param? vParam = ParamBank.VanillaBank.GetParamFromName(paramName); + if (vParam == null) + { + throw new Exception($@"Could not locate vanilla param for {param.ParamType}"); + } + + (PseudoColumn, Param.Column) col = vParam.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + return (j, row) => + { + Param.Row vRow = vParam?[row.ID]; + if (vRow == null) + { + throw new Exception($@"Could not locate vanilla row {row.ID}"); + } + + var v = vRow.Get(col).ToParamEditorString(); + return (k, c) => v; + }; + })); + argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, + "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", + bankAndField => + { + if (!ParamBank.AuxBanks.ContainsKey(bankAndField[0])) + { + throw new Exception($@"Could not locate paramBank {bankAndField[0]}"); + } + + ParamBank bank = ParamBank.AuxBanks[bankAndField[0]]; + return (i, param) => + { + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + if (!bank.Params.ContainsKey(paramName)) + { + throw new Exception($@"Could not locate aux param for {param.ParamType}"); + } + + Param vParam = bank.Params[paramName]; + (PseudoColumn, Param.Column) col = vParam.GetCol(bankAndField[1]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {bankAndField[1]}"); + } + + return (j, row) => + { + Param.Row vRow = vParam?[row.ID]; + if (vRow == null) + { + throw new Exception($@"Could not locate aux row {row.ID}"); + } + + var v = vRow.Get(col).ToParamEditorString(); + return (k, c) => v; + }; + }; + }, () => ParamBank.AuxBanks.Count > 0)); + argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, + "Returns the specific value specified by the exact param, row and field.", address => + { + Param param = ParamBank.PrimaryBank.Params[address[0]]; + if (param == null) + throw new Exception($@"Could not find param {address[0]}"); + var id = int.Parse(address[1]); + (PseudoColumn, Param.Column) field = param.GetCol(address[2]); + if (!field.IsColumnValid()) + throw new Exception($@"Could not find field {address[2]} in param {address[0]}"); + var row = param[id]; + if (row == null) + throw new Exception($@"Could not find row {id} in param {address[0]}"); + var value = row.Get(field).ToParamEditorString(); + return (i, param) => (j, row) => (k, col) => value; + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, + "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", + field => (i, param) => + { + (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + Type colType = col.GetColumnType(); + if (colType == typeof(string) || colType == typeof(byte[])) + { + throw new Exception($@"Cannot average field {field[0]}"); + } + + List? rows = + RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + IEnumerable vals = rows.Select((row, i) => row.Get(col)); + var avg = vals.Average(val => Convert.ToDouble(val)); + return (j, row) => (k, c) => avg.ToString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, + "Gives the median value of the cells/fields found using the given selector, for the currently selected param", + field => (i, param) => + { + (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + List? rows = + RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + IEnumerable vals = rows.Select((row, i) => row.Get(col)); + var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); + return (j, row) => (k, c) => avg.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, + "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", + field => (i, param) => + { + (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + List? rows = + RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + var avg = ParamUtils.GetParamValueDistribution(rows, col).OrderByDescending(g => g.Item2) + .First().Item1; + return (j, row) => (k, c) => avg.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, + "Gives the smallest value from the cells/fields found using the given param, row selector and field", + field => (i, param) => + { + (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + List? rows = + RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + var min = rows.Min(r => r[field[0]].Value.Value); + return (j, row) => (k, c) => min.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, + "Gives the largest value from the cells/fields found using the given param, row selector and field", + field => (i, param) => + { + (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + if (!col.IsColumnValid()) + { + throw new Exception($@"Could not locate field {field[0]}"); + } + + List? rows = + RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + var max = rows.Max(r => r[field[0]].Value.Value); + return (j, row) => (k, c) => max.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("random", newGetter( + new[] { "minimum number (inclusive)", "maximum number (exclusive)" }, + "Gives a random decimal number between the given values for each selected value", minAndMax => + { + double min; + double max; + if (!double.TryParse(minAndMax[0], out min) || !double.TryParse(minAndMax[1], out max)) + { + throw new Exception(@"Could not parse min and max random values"); + } + + if (max <= min) + { + throw new Exception(@"Random max must be greater than min"); + } + + var range = max - min; + return (i, param) => (j, row) => (k, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("randint", newGetter( + new[] { "minimum integer (inclusive)", "maximum integer (inclusive)" }, + "Gives a random integer between the given values for each selected value", minAndMax => + { + int min; + int max; + if (!int.TryParse(minAndMax[0], out min) || !int.TryParse(minAndMax[1], out max)) + { + throw new Exception(@"Could not parse min and max randint values"); + } + + if (max <= min) + { + throw new Exception(@"Random max must be greater than min"); + } + + return (i, param) => (j, row) => (k, c) => Random.Shared.NextInt64(min, max + 1).ToString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, + "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", + paramFieldRowSelector => + { + Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; + List srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), + paramFieldRowSelector[2], false, false); + var values = srcRows.Select((r, i) => r[paramFieldRowSelector[1]].Value.Value).ToArray(); + return (i, param) => + (j, row) => (k, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("paramIndex", newGetter(new string[0], + "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", + empty => (i, param) => (j, row) => (k, col) => + { + return i.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("rowIndex", newGetter(new string[0], + "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", + empty => (i, param) => (j, row) => (k, col) => + { + return j.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + argumentGetters.Add("fieldIndex", newGetter(new string[0], + "Gives an integer for the current selected cell/field, beginning at 0 and increasing by 1 for each cell/field selected", + empty => (i, param) => (j, row) => (k, col) => + { + return k.ToParamEditorString(); + }, () => CFG.Current.Param_AdvancedMassedit)); + } + + public List<(string, string[])> AllArguments() + { + List<(string, string[])> options = new(); + foreach (var op in argumentGetters.Keys) + { + options.Add((op, argumentGetters[op].args)); + } + + return options; + } + + public List<(string, string, string[])> VisibleArguments() + { + List<(string, string, string[])> options = new(); + foreach (var op in argumentGetters.Keys) + { + OperationArgumentGetter oag = argumentGetters[op]; + if (oag.shouldShow == null || oag.shouldShow()) + { + options.Add((op, oag.wiki, oag.args)); + } + } + + return options; + } + + internal Func>>[] + getContextualArguments(int argumentCount, string opData) + { + var opArgs = opData == null ? new string[0] : opData.Split(':', argumentCount); + var contextualArgs = + new Func>>[opArgs + .Length]; + for (var i = 0; i < opArgs.Length; i++) + { + contextualArgs[i] = getContextualArgument(opArgs[i]); + } + + return contextualArgs; + } + + internal Func>> + getContextualArgument(string opArg) + { + if (opArg.StartsWith('"') && opArg.EndsWith('"')) + { + return (i, p) => (j, r) => (k, c) => opArg.Substring(1, opArg.Length - 2); + } + + if (opArg.StartsWith('$')) + { + opArg = MassParamEdit.massEditVars[opArg.Substring(1)].ToString(); + } + + var arg = opArg.Split(" ", 2); + if (argumentGetters.ContainsKey(arg[0].Trim())) + { + OperationArgumentGetter getter = argumentGetters[arg[0]]; + var opArgArgs = arg.Length > 1 ? arg[1].Split(" ", getter.args.Length) : new string[0]; + if (opArgArgs.Length != getter.args.Length) + { + throw new Exception( + @$"Contextual value {arg[0]} has wrong number of arguments. Expected {opArgArgs.Length}"); + } + + for (var i = 0; i < opArgArgs.Length; i++) + { + if (opArgArgs[i].StartsWith('$')) + { + opArgArgs[i] = MassParamEdit.massEditVars[opArgArgs[i].Substring(1)].ToString(); + } + } + + return getter.func(opArgArgs); + } + + return defaultGetter.func(new[] { opArg }); + } +} + +internal class OperationArgumentGetter +{ + public string[] args; + + internal Func>>> + func; + + internal Func shouldShow; + public string wiki; + + internal OperationArgumentGetter(string[] args, string wiki, + Func>>> + func, Func shouldShow) + { + this.args = args; + this.wiki = wiki; + this.func = func; + this.shouldShow = shouldShow; + } +} diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 6b679dea4..53101ee23 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -562,715 +562,3 @@ public static AddParamsAction SortRows(ParamBank bank, string paramName) true); //appending same params and allowing overwrite } } -internal abstract class METypelessOperationDef -{ - internal string[] argNames; - internal string wiki; - internal Func function; -} -internal class MEOperationDef : METypelessOperationDef -{ - internal MEOperationDef(string[] args, string tooltip, Func func) - { - argNames = args; - wiki = tooltip; - function = func as Func; - } -} -public abstract class METypelessOperation -{ - internal abstract Dictionary AllCommands(); -} -public class MEOperation : METypelessOperation -{ - internal Dictionary operations = new(); - - internal MEOperation() - { - Setup(); - } - - internal virtual void Setup() - { - } - - internal bool HandlesCommand(string command) - { - return operations.ContainsKey(command); - } - internal override Dictionary AllCommands() - { - return operations; - } - - public List<(string, string[], string)> AvailableCommands() - { - List<(string, string[], string)> options = new(); - foreach (var op in operations.Keys) - { - options.Add((op, operations[op].argNames, operations[op].wiki)); - } - - return options; - } - internal MEOperationDef newCmd(string[] args, string wiki, Func func) - { - return new MEOperationDef(args, wiki, func); - } - internal MEOperationDef newCmd(string wiki, Func func) - { - return new MEOperationDef(Array.Empty(), wiki, func); - } -} - -public class MEGlobalOperation : MEOperation -{ - public static MEGlobalOperation globalOps = new(); - - internal override void Setup() - { - operations.Add("clear", newCmd(new string[0], "Clears clipboard param and rows", (selectionState, args) => - { - ParamBank.ClipboardParam = null; - ParamBank.ClipboardRows.Clear(); - return true; - } - )); - operations.Add("newvar", newCmd(new[] { "variable name", "value" }, - "Creates a variable with the given value, and the type of that value", (selectionState, args) => - { - int asInt; - double asDouble; - if (int.TryParse(args[1], out asInt)) - { - MassParamEdit.massEditVars[args[0]] = asInt; - } - else if (double.TryParse(args[1], out asDouble)) - { - MassParamEdit.massEditVars[args[0]] = asDouble; - } - else - { - MassParamEdit.massEditVars[args[0]] = args[1]; - } - - return true; - } - )); - operations.Add("clearvars", newCmd(new string[0], "Deletes all variables", (selectionState, args) => - { - MassParamEdit.massEditVars.Clear(); - return true; - } - )); - } -} - -public class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> -{ - public static MERowOperation rowOps = new(); - - internal override void Setup() - { - operations.Add("copy", newCmd(new string[0], - "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", - (paramAndRow, args) => - { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; - if (paramKey == null) - { - throw new Exception(@"Could not locate param"); - } - - if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) - { - throw new Exception($@"Could not locate param {paramKey}"); - } - - Param p = ParamBank.PrimaryBank.Params[paramKey]; - // Only supporting single param in clipboard - if (ParamBank.ClipboardParam != paramKey) - { - ParamBank.ClipboardParam = paramKey; - ParamBank.ClipboardRows.Clear(); - } - - ParamBank.ClipboardRows.Add(new Param.Row(row, p)); - return (p, null); - } - )); - operations.Add("copyN", newCmd(new[] { "count" }, - "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", - (paramAndRow, args) => - { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; - if (paramKey == null) - { - throw new Exception(@"Could not locate param"); - } - - if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) - { - throw new Exception($@"Could not locate param {paramKey}"); - } - - var count = uint.Parse(args[0]); - Param p = ParamBank.PrimaryBank.Params[paramKey]; - // Only supporting single param in clipboard - if (ParamBank.ClipboardParam != paramKey) - { - ParamBank.ClipboardParam = paramKey; - ParamBank.ClipboardRows.Clear(); - } - - for (var i = 0; i < count; i++) - { - ParamBank.ClipboardRows.Add(new Param.Row(row, p)); - } - - return (p, null); - } - )); - operations.Add("paste", newCmd(new string[0], - "Adds the selected rows to the primary regulation or parambnd in the selected param", - (paramAndRow, args) => - { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; - if (paramKey == null) - { - throw new Exception(@"Could not locate param"); - } - - if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) - { - throw new Exception($@"Could not locate param {paramKey}"); - } - - Param p = ParamBank.PrimaryBank.Params[paramKey]; - return (p, new Param.Row(row, p)); - } - )); - } -} - -public class MEValueOperation : MEOperation -{ - public static MEValueOperation valueOps = new(); - - internal override void Setup() - { - operations.Add("=", - newCmd(new[] { "number or text" }, - "Assigns the given value to the selected values. Will attempt conversion to the value's data type", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => args[0]))); - operations.Add("+", newCmd(new[] { "number or text" }, - "Adds the number to the selected values, or appends text if that is the data type of the values", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => - { - double val; - if (double.TryParse(args[0], out val)) - { - return v + val; - } - - return v + args[0]; - }))); - operations.Add("-", - newCmd(new[] { "number" }, "Subtracts the number from the selected values", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v - double.Parse(args[0])))); - operations.Add("*", - newCmd(new[] { "number" }, "Multiplies selected values by the number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v * double.Parse(args[0])))); - operations.Add("/", - newCmd(new[] { "number" }, "Divides the selected values by the number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v / double.Parse(args[0])))); - operations.Add("%", - newCmd(new[] { "number" }, "Gives the remainder when the selected values are divided by the number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v % double.Parse(args[0])))); - operations.Add("scale", newCmd(new[] { "factor number", "center number" }, - "Multiplies the difference between the selected values and the center number by the factor number", - (ctx, args) => - { - var opp1 = double.Parse(args[0]); - var opp2 = double.Parse(args[1]); - return MassParamEdit.WithDynamicOf(ctx, v => - { - return ((v - opp2) * opp1) + opp2; - }); - } - )); - operations.Add("replace", - newCmd(new[] { "text to replace", "new text" }, - "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v.Replace(args[0], args[1])))); - operations.Add("replacex", newCmd(new[] { "text to replace (regex)", "new text (w/ groups)" }, - "Interprets the selected values as text and replaces all occurances of the given regex with the replacement, supporting regex groups", - (ctx, args) => - { - Regex rx = new(args[0]); - return MassParamEdit.WithDynamicOf(ctx, v => rx.Replace(v, args[1])); - } - )); - operations.Add("max", - newCmd(new[] { "number" }, "Returns the larger of the current value and number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Max(v, double.Parse(args[0]))))); - operations.Add("min", - newCmd(new[] { "number" }, "Returns the smaller of the current value and number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Min(v, double.Parse(args[0]))))); - } -} - -public class MEOperationArgument -{ - public static MEOperationArgument arg = new(); - private readonly Dictionary argumentGetters = new(); - private OperationArgumentGetter defaultGetter; - - private MEOperationArgument() - { - Setup(); - } - - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func>>> - func, Func shouldShow = null) - { - return new OperationArgumentGetter(args, wiki, func, shouldShow); - } - - private void Setup() - { - defaultGetter = newGetter(new string[0], "Gives the specified value", - value => (i, param) => (j, row) => (k, col) => value[0]); - argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", - empty => (i, param) => (j, row) => (k, col) => - { - return row.Get(col).ToParamEditorString(); - })); - argumentGetters.Add("field", newGetter(new[] { "field internalName" }, - "Gives the value of the given cell/field for the currently selected row and param", field => - (i, param) => - { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - return (j, row) => - { - var v = row.Get(col).ToParamEditorString(); - return (k, c) => v; - }; - })); - argumentGetters.Add("vanilla", newGetter(new string[0], - "Gives the value of the equivalent cell/field in the vanilla regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", - empty => - { - ParamBank bank = ParamBank.VanillaBank; - return (i, param) => - { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); - if (!bank.Params.ContainsKey(paramName)) - { - throw new Exception($@"Could not locate vanilla param for {param.ParamType}"); - } - - Param vParam = bank.Params[paramName]; - return (j, row) => - { - Param.Row vRow = vParam?[row.ID]; - if (vRow == null) - { - throw new Exception($@"Could not locate vanilla row {row.ID}"); - } - - return (k, col) => - { - if (col.Item1 == PseudoColumn.None && col.Item2 == null) - { - throw new Exception(@"Could not locate given field or property"); - } - - return vRow.Get(col).ToParamEditorString(); - }; - }; - }; - })); - argumentGetters.Add("aux", newGetter(new[] { "parambank name" }, - "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", - bankName => - { - if (!ParamBank.AuxBanks.ContainsKey(bankName[0])) - { - throw new Exception($@"Could not locate paramBank {bankName[0]}"); - } - - ParamBank bank = ParamBank.AuxBanks[bankName[0]]; - return (i, param) => - { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); - if (!bank.Params.ContainsKey(paramName)) - { - throw new Exception($@"Could not locate aux param for {param.ParamType}"); - } - - Param vParam = bank.Params[paramName]; - return (j, row) => - { - Param.Row vRow = vParam?[row.ID]; - if (vRow == null) - { - throw new Exception($@"Could not locate aux row {row.ID}"); - } - - return (k, col) => - { - if (!col.IsColumnValid()) - { - throw new Exception(@"Could not locate given field or property"); - } - - return vRow.Get(col).ToParamEditorString(); - }; - }; - }; - }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, - "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", - field => (i, param) => - { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); - Param? vParam = ParamBank.VanillaBank.GetParamFromName(paramName); - if (vParam == null) - { - throw new Exception($@"Could not locate vanilla param for {param.ParamType}"); - } - - (PseudoColumn, Param.Column) col = vParam.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - return (j, row) => - { - Param.Row vRow = vParam?[row.ID]; - if (vRow == null) - { - throw new Exception($@"Could not locate vanilla row {row.ID}"); - } - - var v = vRow.Get(col).ToParamEditorString(); - return (k, c) => v; - }; - })); - argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, - "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", - bankAndField => - { - if (!ParamBank.AuxBanks.ContainsKey(bankAndField[0])) - { - throw new Exception($@"Could not locate paramBank {bankAndField[0]}"); - } - - ParamBank bank = ParamBank.AuxBanks[bankAndField[0]]; - return (i, param) => - { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); - if (!bank.Params.ContainsKey(paramName)) - { - throw new Exception($@"Could not locate aux param for {param.ParamType}"); - } - - Param vParam = bank.Params[paramName]; - (PseudoColumn, Param.Column) col = vParam.GetCol(bankAndField[1]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {bankAndField[1]}"); - } - - return (j, row) => - { - Param.Row vRow = vParam?[row.ID]; - if (vRow == null) - { - throw new Exception($@"Could not locate aux row {row.ID}"); - } - - var v = vRow.Get(col).ToParamEditorString(); - return (k, c) => v; - }; - }; - }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, - "Returns the specific value specified by the exact param, row and field.", address => - { - Param param = ParamBank.PrimaryBank.Params[address[0]]; - if (param == null) - throw new Exception($@"Could not find param {address[0]}"); - var id = int.Parse(address[1]); - (PseudoColumn, Param.Column) field = param.GetCol(address[2]); - if (!field.IsColumnValid()) - throw new Exception($@"Could not find field {address[2]} in param {address[0]}"); - var row = param[id]; - if (row == null) - throw new Exception($@"Could not find row {id} in param {address[0]}"); - var value = row.Get(field).ToParamEditorString(); - return (i, param) => (j, row) => (k, col) => value; - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, - "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", - field => (i, param) => - { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - Type colType = col.GetColumnType(); - if (colType == typeof(string) || colType == typeof(byte[])) - { - throw new Exception($@"Cannot average field {field[0]}"); - } - - List? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - IEnumerable vals = rows.Select((row, i) => row.Get(col)); - var avg = vals.Average(val => Convert.ToDouble(val)); - return (j, row) => (k, c) => avg.ToString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, - "Gives the median value of the cells/fields found using the given selector, for the currently selected param", - field => (i, param) => - { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - List? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - IEnumerable vals = rows.Select((row, i) => row.Get(col)); - var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); - return (j, row) => (k, c) => avg.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, - "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", - field => (i, param) => - { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - List? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - var avg = ParamUtils.GetParamValueDistribution(rows, col).OrderByDescending(g => g.Item2) - .First().Item1; - return (j, row) => (k, c) => avg.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, - "Gives the smallest value from the cells/fields found using the given param, row selector and field", - field => (i, param) => - { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - List? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - var min = rows.Min(r => r[field[0]].Value.Value); - return (j, row) => (k, c) => min.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, - "Gives the largest value from the cells/fields found using the given param, row selector and field", - field => (i, param) => - { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); - if (!col.IsColumnValid()) - { - throw new Exception($@"Could not locate field {field[0]}"); - } - - List? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - var max = rows.Max(r => r[field[0]].Value.Value); - return (j, row) => (k, c) => max.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("random", newGetter( - new[] { "minimum number (inclusive)", "maximum number (exclusive)" }, - "Gives a random decimal number between the given values for each selected value", minAndMax => - { - double min; - double max; - if (!double.TryParse(minAndMax[0], out min) || !double.TryParse(minAndMax[1], out max)) - { - throw new Exception(@"Could not parse min and max random values"); - } - - if (max <= min) - { - throw new Exception(@"Random max must be greater than min"); - } - - var range = max - min; - return (i, param) => (j, row) => (k, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randint", newGetter( - new[] { "minimum integer (inclusive)", "maximum integer (inclusive)" }, - "Gives a random integer between the given values for each selected value", minAndMax => - { - int min; - int max; - if (!int.TryParse(minAndMax[0], out min) || !int.TryParse(minAndMax[1], out max)) - { - throw new Exception(@"Could not parse min and max randint values"); - } - - if (max <= min) - { - throw new Exception(@"Random max must be greater than min"); - } - - return (i, param) => (j, row) => (k, c) => Random.Shared.NextInt64(min, max + 1).ToString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, - "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", - paramFieldRowSelector => - { - Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; - List srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), - paramFieldRowSelector[2], false, false); - var values = srcRows.Select((r, i) => r[paramFieldRowSelector[1]].Value.Value).ToArray(); - return (i, param) => - (j, row) => (k, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("paramIndex", newGetter(new string[0], - "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", - empty => (i, param) => (j, row) => (k, col) => - { - return i.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("rowIndex", newGetter(new string[0], - "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", - empty => (i, param) => (j, row) => (k, col) => - { - return j.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("fieldIndex", newGetter(new string[0], - "Gives an integer for the current selected cell/field, beginning at 0 and increasing by 1 for each cell/field selected", - empty => (i, param) => (j, row) => (k, col) => - { - return k.ToParamEditorString(); - }, () => CFG.Current.Param_AdvancedMassedit)); - } - - public List<(string, string[])> AllArguments() - { - List<(string, string[])> options = new(); - foreach (var op in argumentGetters.Keys) - { - options.Add((op, argumentGetters[op].args)); - } - - return options; - } - - public List<(string, string, string[])> VisibleArguments() - { - List<(string, string, string[])> options = new(); - foreach (var op in argumentGetters.Keys) - { - OperationArgumentGetter oag = argumentGetters[op]; - if (oag.shouldShow == null || oag.shouldShow()) - { - options.Add((op, oag.wiki, oag.args)); - } - } - - return options; - } - - internal Func>>[] - getContextualArguments(int argumentCount, string opData) - { - var opArgs = opData == null ? new string[0] : opData.Split(':', argumentCount); - var contextualArgs = - new Func>>[opArgs - .Length]; - for (var i = 0; i < opArgs.Length; i++) - { - contextualArgs[i] = getContextualArgument(opArgs[i]); - } - - return contextualArgs; - } - - internal Func>> - getContextualArgument(string opArg) - { - if (opArg.StartsWith('"') && opArg.EndsWith('"')) - { - return (i, p) => (j, r) => (k, c) => opArg.Substring(1, opArg.Length - 2); - } - - if (opArg.StartsWith('$')) - { - opArg = MassParamEdit.massEditVars[opArg.Substring(1)].ToString(); - } - - var arg = opArg.Split(" ", 2); - if (argumentGetters.ContainsKey(arg[0].Trim())) - { - OperationArgumentGetter getter = argumentGetters[arg[0]]; - var opArgArgs = arg.Length > 1 ? arg[1].Split(" ", getter.args.Length) : new string[0]; - if (opArgArgs.Length != getter.args.Length) - { - throw new Exception( - @$"Contextual value {arg[0]} has wrong number of arguments. Expected {opArgArgs.Length}"); - } - - for (var i = 0; i < opArgArgs.Length; i++) - { - if (opArgArgs[i].StartsWith('$')) - { - opArgArgs[i] = MassParamEdit.massEditVars[opArgArgs[i].Substring(1)].ToString(); - } - } - - return getter.func(opArgArgs); - } - - return defaultGetter.func(new[] { opArg }); - } -} - -internal class OperationArgumentGetter -{ - public string[] args; - - internal Func>>> - func; - - internal Func shouldShow; - public string wiki; - - internal OperationArgumentGetter(string[] args, string wiki, - Func>>> - func, Func shouldShow) - { - this.args = args; - this.wiki = wiki; - this.func = func; - this.shouldShow = shouldShow; - } -} From 0ff5f8981ccedccc64530ac00bb624b4281bab79 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sat, 27 Jan 2024 15:10:12 +0000 Subject: [PATCH 09/61] register operations --- src/StudioCore/Editor/MassEdit/EditOperation.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index ae49b36b7..d7cc394fd 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -26,6 +26,16 @@ internal MEOperationDef(string[] args, string tooltip, Func func } public abstract class METypelessOperation { + private static Dictionary editOperations = new(); + internal static void AddEditOperation(MEOperation engine) + { + editOperations[typeof(I)] = engine; + } + internal static METypelessOperation GetEditOperation(Type t) + { + return editOperations[t]; + } + internal abstract Dictionary AllCommands(); } public class MEOperation : METypelessOperation From 201ba5487da076303607e6c7d996e39f8c769c00 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sat, 27 Jan 2024 16:25:27 +0000 Subject: [PATCH 10/61] Name funcs --- .../Editor/MassEdit/EditOperation.cs | 12 ++++++++- src/StudioCore/Editor/MassEdit/MassEdit.cs | 25 +++++++++++++------ .../Editor/MassEdit/SearchEngine.cs | 17 +++++++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index d7cc394fd..7e23a315d 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -33,14 +33,16 @@ internal static void AddEditOperation(MEOperation engine) } internal static METypelessOperation GetEditOperation(Type t) { - return editOperations[t]; + return editOperations.GetValueOrDefault(t); } internal abstract Dictionary AllCommands(); + internal abstract string NameForHelpTexts(); } public class MEOperation : METypelessOperation { internal Dictionary operations = new(); + internal string name = "[Unnamed operation type]"; internal MEOperation() { @@ -78,6 +80,11 @@ internal MEOperationDef newCmd(string wiki, Func func) { return new MEOperationDef(Array.Empty(), wiki, func); } + + internal override string NameForHelpTexts() + { + return name; + } } public class MEGlobalOperation : MEOperation @@ -86,6 +93,7 @@ public class MEGlobalOperation : MEOperation internal override void Setup() { + name = "global"; operations.Add("clear", newCmd(new string[0], "Clears clipboard param and rows", (selectionState, args) => { ParamBank.ClipboardParam = null; @@ -129,6 +137,7 @@ public class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row internal override void Setup() { + name = "row"; operations.Add("copy", newCmd(new string[0], "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", (paramAndRow, args) => @@ -219,6 +228,7 @@ public class MEValueOperation : MEOperation internal override void Setup() { + name = "value"; operations.Add("=", newCmd(new[] { "number or text" }, "Assigns the given value to the selected values. Will attempt conversion to the value's data type", diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 53101ee23..0a0e2010a 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -190,20 +190,20 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = ParseFilterStep(currentLine, command, "variable", VarSearchEngine.vse, ref currentEditData.varStageInfo, "var operation", (currentLine, restOfStages) => + (result, actions) = ParseFilterStep(currentLine, command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (currentLine, restOfStages) => { return currentEditData.ParseVarOpStep(currentLine, restOfStages); }); } else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = ParseFilterStep(currentLine, command, "paramrow", ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, "cell filter or row operation", (currentLine, restOfStages) => + (result, actions) = ParseFilterStep(currentLine, command, ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, (currentLine, restOfStages) => { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { return currentEditData.ParseRowOpStep(currentLine, restOfStages); } - return ParseFilterStep(currentLine, restOfStages, "cell/property", CellSearchEngine.cse, ref currentEditData.cellStageInfo, "operation to perform", (currentLine, restOfStages) => + return ParseFilterStep(currentLine, restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (currentLine, restOfStages) => { currentEditData.rowOpOrCellStageFunc = currentEditData.ExecCellStage; return currentEditData.ParseCellOpStep(currentLine, restOfStages); @@ -212,15 +212,15 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } else { - (result, actions) = ParseFilterStep(currentLine, command, "param", ParamSearchEngine.pse, ref currentEditData.paramStageInfo, "row filter", (currentLine, restOfStages) => + (result, actions) = ParseFilterStep(currentLine, command, ParamSearchEngine.pse, ref currentEditData.paramStageInfo, (currentLine, restOfStages) => { - return ParseFilterStep(currentLine, restOfStages, "row", RowSearchEngine.rse, ref currentEditData.rowStageInfo, "cell filter or row operation", (currentLine, restOfStages) => + return ParseFilterStep(currentLine, restOfStages, RowSearchEngine.rse, ref currentEditData.rowStageInfo, (currentLine, restOfStages) => { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { return currentEditData.ParseRowOpStep(currentLine, restOfStages); } - return ParseFilterStep(currentLine, restOfStages, "cell/property", CellSearchEngine.cse, ref currentEditData.cellStageInfo, "operation to perform", (currentLine, restOfStages) => + return ParseFilterStep(currentLine, restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (currentLine, restOfStages) => { currentEditData.rowOpOrCellStageFunc = currentEditData.ExecCellStage; return currentEditData.ParseCellOpStep(currentLine, restOfStages); @@ -246,14 +246,23 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } } - private static (MassEditResult, List) ParseFilterStep(int currentLine, string restOfStages, string stageName, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, string expectedNextStageName, Func)> nextStageFunc) + private static (MassEditResult, List) ParseFilterStep(int currentLine, string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func)> nextStageFunc) { var stage = restOfStages.Split(":", 2); + string stageName = expectedSearchEngine.NameForHelpTexts(); target = new MEFilterStage(stage[0], currentLine, stageName, expectedSearchEngine); if (stage.Length < 2) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {expectedNextStageName}. Check your colon placement. (line {currentLine})"), null); + var esList = expectedSearchEngine.NextSearchEngines(); + var eo = expectedSearchEngine.NextOperation(); + if (esList.Any() && eo != null) + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter or {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {currentLine})"), null); + if (esList.Any()) + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter. Check your colon placement. (line {currentLine})"), null); + if (eo != null) + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find next stage to perform (no suggestions found). Check your colon placement. (line {currentLine})"), null); } return nextStageFunc(currentLine, stage[1]); diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 0e5d7f5a2..c6f3ab730 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -29,6 +29,8 @@ internal static void AddSearchEngine(SearchEngine engine) public abstract List<(string, string[])> AllCommands(); public abstract List AvailableCommandsForHelpText(); public abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); + public abstract METypelessOperation NextOperation(); + public abstract string NameForHelpTexts(); } internal class SearchEngine : TypelessSearchEngine { @@ -37,6 +39,7 @@ internal class SearchEngine : TypelessSearchEngine internal Dictionary> filterList = new(); internal Func> unpacker; + internal string name = "[unnamed search engine]"; public SearchEngine() { @@ -214,6 +217,15 @@ public virtual List Search(A context, List sourceSet, string command, bool { return GetSearchEngines(typeof(B)); } + public override METypelessOperation NextOperation() + { + return METypelessOperation.GetEditOperation(typeof(B)); + } + + public override string NameForHelpTexts() + { + return name; + } } internal class SearchEngineCommand @@ -269,6 +281,7 @@ internal class ParamAndRowSearchEngine : MultiStageSearchEngine { List<(MassEditRowSource, Param.Row)> list = new(); @@ -312,6 +325,7 @@ private ParamSearchEngine(ParamBank bank) internal override void Setup() { + name = "param"; unpacker = dummy => ParamBank.AuxBanks.Select((aux, i) => aux.Value.Params.Select((x, i) => (aux.Value, x.Value))) .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).ToList(); @@ -377,6 +391,7 @@ private RowSearchEngine(ParamBank bank) internal override void Setup() { + name = "row"; unpacker = param => new List(param.Item2.Rows); filterList.Add("modified", newCmd(new string[0], "Selects rows which do not match the vanilla version, or are added. Ignores row name", noArgs(context => @@ -831,6 +846,7 @@ internal class CellSearchEngine : SearchEngine<(string, Param.Row), (PseudoColum internal override void Setup() { + name = "cell/property"; unpacker = row => { List<(PseudoColumn, Param.Column)> list = new(); @@ -971,6 +987,7 @@ internal class VarSearchEngine : SearchEngine internal override void Setup() { + name = "variable"; unpacker = dummy => { return MassParamEdit.massEditVars.Keys.ToList(); From caabdbd5fc1d67b1c69afade0716a4a14760d9bb Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sat, 27 Jan 2024 16:35:08 +0000 Subject: [PATCH 11/61] Change type of rowsearchengine for consistency problems --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 2 +- .../Editor/MassEdit/SearchEngine.cs | 68 ++++++++++--------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 0a0e2010a..f9d991d11 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -466,7 +466,7 @@ private MassEditResult ExecRowStage(int currentLine, string paramname, ParamBank b, Param p, List partialActions) { var rowEditCount = -1; - foreach (Param.Row row in RowSearchEngine.rse.Search((b, p), rowStageInfo.command, false, false)) + foreach ((string param, Param.Row row) in RowSearchEngine.rse.Search((b, p), rowStageInfo.command, false, false)) { rowEditCount++; Func[] rowArgFunc = diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index c6f3ab730..3c6029aca 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -274,7 +274,7 @@ public override List Search(A context, List sourceSet, string command, boo } internal class ParamAndRowSearchEngine : MultiStageSearchEngine + Param.Row), (ParamBank, Param), (string, Param.Row)> { public static SearchEngine parse = new ParamAndRowSearchEngine(); @@ -301,9 +301,9 @@ internal override void Setup() exampleItem.Item1 == MassEditRowSource.Selection ? state.GetActiveParam() : ParamBank.ClipboardParam]); - sourceListGetterForMultiStage = row => row.Item2; + sourceListGetterForMultiStage = row => (null, row.Item2); searchEngineForMultiStage = RowSearchEngine.rse; - resultRetrieverForMultiStage = (row, exampleItem) => (exampleItem.Item1, row); + resultRetrieverForMultiStage = (row, exampleItem) => (exampleItem.Item1, row.Item2); } } @@ -379,7 +379,7 @@ internal override void Setup() } } -internal class RowSearchEngine : SearchEngine<(ParamBank, Param), Param.Row> +internal class RowSearchEngine : SearchEngine<(ParamBank, Param), (string, Param.Row)> { public static RowSearchEngine rse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -392,13 +392,17 @@ private RowSearchEngine(ParamBank bank) internal override void Setup() { name = "row"; - unpacker = param => new List(param.Item2.Rows); + unpacker = param => + { + string name = param.Item1.GetKeyForParam(param.Item2); + return param.Item2.Rows.Select((x, i) => (name, x)).ToList(); + }; filterList.Add("modified", newCmd(new string[0], "Selects rows which do not match the vanilla version, or are added. Ignores row name", noArgs(context => { var paramName = context.Item1.GetKeyForParam(context.Item2); HashSet cache = context.Item1.GetVanillaDiffRows(paramName); - return row => cache.Contains(row.ID); + return row => cache.Contains(row.Item2.ID); } ))); filterList.Add("added", newCmd(new string[0], "Selects rows where the ID is not found in the vanilla param", @@ -411,7 +415,7 @@ internal override void Setup() } Param vanilParam = ParamBank.VanillaBank.Params[paramName]; - return row => vanilParam[row.ID] == null; + return row => vanilParam[row.Item2.ID] == null; } ))); filterList.Add("mergeable", newCmd(new string[0], @@ -428,8 +432,8 @@ internal override void Setup() List<(HashSet, HashSet)> auxCaches = ParamBank.AuxBanks.Select(x => (x.Value.GetPrimaryDiffRows(paramName), x.Value.GetVanillaDiffRows(paramName))).ToList(); return row => - !pCache.Contains(row.ID) && - auxCaches.Where(x => x.Item2.Contains(row.ID) && x.Item1.Contains(row.ID)).Count() == 1; + !pCache.Contains(row.Item2.ID) && + auxCaches.Where(x => x.Item2.Contains(row.Item2.ID) && x.Item1.Contains(row.Item2.ID)).Count() == 1; } ), () => ParamBank.AuxBanks.Count > 0)); filterList.Add("conflicts", newCmd(new string[0], @@ -441,28 +445,28 @@ internal override void Setup() List<(HashSet, HashSet)> auxCaches = ParamBank.AuxBanks.Select(x => (x.Value.GetPrimaryDiffRows(paramName), x.Value.GetVanillaDiffRows(paramName))).ToList(); return row => - (pCache.Contains(row.ID) ? 1 : 0) + auxCaches - .Where(x => x.Item2.Contains(row.ID) && x.Item1.Contains(row.ID)).Count() > 1; + (pCache.Contains(row.Item2.ID) ? 1 : 0) + auxCaches + .Where(x => x.Item2.Contains(row.Item2.ID) && x.Item1.Contains(row.Item2.ID)).Count() > 1; } ), () => ParamBank.AuxBanks.Count > 0)); filterList.Add("id", newCmd(new[] { "row id (regex)" }, "Selects rows whose ID matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[0].ToLower()) : new Regex($@"^{args[0]}$"); - return noContext(row => rx.IsMatch(row.ID.ToString())); + return noContext(row => rx.IsMatch(row.Item2.ID.ToString())); })); filterList.Add("idrange", newCmd(new[] { "row id minimum (inclusive)", "row id maximum (inclusive)" }, "Selects rows whose ID falls in the given numerical range", (args, lenient) => { var floor = double.Parse(args[0]); var ceil = double.Parse(args[1]); - return noContext(row => row.ID >= floor && row.ID <= ceil); + return noContext(row => row.Item2.ID >= floor && row.Item2.ID <= ceil); })); filterList.Add("name", newCmd(new[] { "row name (regex)" }, "Selects rows whose Name matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[0], RegexOptions.IgnoreCase) : new Regex($@"^{args[0]}$"); - return noContext(row => rx.IsMatch(row.Name == null ? "" : row.Name)); + return noContext(row => rx.IsMatch(row.Item2.Name == null ? "" : row.Item2.Name)); })); filterList.Add("prop", newCmd(new[] { "field internalName", "field value (regex)" }, "Selects rows where the specified field has a value that matches the given regex", (args, lenient) => @@ -471,7 +475,7 @@ internal override void Setup() var field = args[0]; return noContext(row => { - Param.Cell? cq = row[field]; + Param.Cell? cq = row.Item2[field]; if (cq == null) { throw new Exception(); @@ -492,7 +496,7 @@ internal override void Setup() var ceil = double.Parse(args[2]); return noContext(row => { - Param.Cell? c = row[field]; + Param.Cell? c = row.Item2[field]; if (c == null) { throw new Exception(); @@ -514,7 +518,7 @@ internal override void Setup() .FindAll(p => bank.Params.ContainsKey(p.param)); return row => { - Param.Cell? c = row[field]; + Param.Cell? c = row.Item2[field]; if (c == null) { throw new Exception(); @@ -546,7 +550,7 @@ internal override void Setup() (PseudoColumn, Param.Column) testCol = context.Item2.GetCol(field); return row => { - (string paramName, Param.Row row) cseSearchContext = (paramName, row); + (string paramName, Param.Row row) cseSearchContext = (paramName, row.Item2); List<(PseudoColumn, Param.Column)> res = CellSearchEngine.cse.Search(cseSearchContext, new List<(PseudoColumn, Param.Column)> { testCol }, args[1], lenient, false); return res.Contains(testCol); @@ -586,12 +590,12 @@ internal override void Setup() return row => { - if (!_cache.ContainsKey(row.ID)) + if (!_cache.ContainsKey(row.Item2.ID)) { return false; } - FMG.Entry e = _cache[row.ID]; + FMG.Entry e = _cache[row.Item2.ID]; return e != null && rx.IsMatch(e.Text ?? ""); }; }; @@ -607,7 +611,7 @@ internal override void Setup() Param vparam = ParamBank.VanillaBank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); return row => { - Param.Row vrow = vparam[row.ID]; + Param.Row vrow = vparam[row.Item2.ID]; if (vrow == null) { return false; @@ -638,7 +642,7 @@ internal override void Setup() Param vparam = ParamBank.VanillaBank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); return row => { - Param.Row vrow = vparam[row.ID]; + Param.Row vrow = vparam[row.Item2.ID]; if (vrow == null) { return false; @@ -671,7 +675,7 @@ internal override void Setup() Param vparam = bank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); return row => { - Param.Row vrow = vparam[row.ID]; + Param.Row vrow = vparam[row.Item2.ID]; if (vrow == null) { return false; @@ -712,7 +716,7 @@ internal override void Setup() Param vparam = bank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); return row => { - Param.Row vrow = vparam[row.ID]; + Param.Row vrow = vparam[row.Item2.ID]; Param.Cell? c = vrow[field]; if (c == null) { @@ -743,7 +747,7 @@ internal override void Setup() throw new Exception("Could not find param " + otherParam); } - List rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, + List<(string, Param.Row)> rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, lenient, false); (PseudoColumn, Param.Column) otherFieldReal = otherParamReal.GetCol(otherField); if (!otherFieldReal.IsColumnValid()) @@ -751,7 +755,7 @@ internal override void Setup() throw new Exception("Could not find field " + otherField); } - HashSet possibleValues = rows.Select(x => x.Get(otherFieldReal).ToParamEditorString()) + HashSet possibleValues = rows.Select(x => x.Item2.Get(otherFieldReal).ToParamEditorString()) .Distinct().ToHashSet(); return param => { @@ -763,7 +767,7 @@ internal override void Setup() return row => { - var toFind = row.Get(thisFieldReal).ToParamEditorString(); + var toFind = row.Item2.Get(thisFieldReal).ToParamEditorString(); return possibleValues.Contains(toFind); }; }; @@ -780,7 +784,7 @@ internal override void Setup() var setOfDuped = distribution.Where((entry, linqi) => entry.Item2 > 1).Select((entry, linqi) => entry.Item1).ToHashSet(); return (row) => { - return !setOfDuped.Contains(row.Get(col)); + return !setOfDuped.Contains(row.Item2.Get(col)); }; }; }, () => CFG.Current.Param_AdvancedMassedit)); @@ -810,7 +814,7 @@ internal override void Setup() if (category == FmgEntryCategory.None || !FMGBank.IsLoaded) { - return row => rx.IsMatch(row.Name ?? "") || rx.IsMatch(row.ID.ToString()); + return row => rx.IsMatch(row.Item2.Name ?? "") || rx.IsMatch(row.Item2.ID.ToString()); } List fmgEntries = FMGBank.GetFmgEntriesByCategory(category, false); @@ -822,17 +826,17 @@ internal override void Setup() return row => { - if (rx.IsMatch(row.Name ?? "") || rx.IsMatch(row.ID.ToString())) + if (rx.IsMatch(row.Item2.Name ?? "") || rx.IsMatch(row.Item2.ID.ToString())) { return true; } - if (!_cache.ContainsKey(row.ID)) + if (!_cache.ContainsKey(row.Item2.ID)) { return false; } - FMG.Entry e = _cache[row.ID]; + FMG.Entry e = _cache[row.Item2.ID]; return e != null && rx.IsMatch(e.Text ?? ""); }; }; From 349a635b7504cea2620c53247a42932cdf3c505c Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sun, 28 Jan 2024 17:46:58 +0000 Subject: [PATCH 12/61] fixes for changing rowsearchengine --- src/StudioCore/Editor/EditorDecorations.cs | 6 ++--- .../Editor/MassEdit/EditOperation.cs | 24 +++++++++---------- .../ParamEditor/ParamEditorScreen.cs | 2 +- src/StudioCore/ParamEditor/ParamEditorView.cs | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index fff730931..eebe01bc5 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -556,9 +556,9 @@ public static bool PropertyRowRefsContextItems(ParamBank bank, List re ParamMetaData meta = ParamMetaData.Get(bank.Params[rt].AppliedParamdef); var maxResultsPerRefType = 15 / reftypes.Count; - List rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), + List<(string, Param.Row)> rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), _refContextCurrentAutoComplete, true, true); - foreach (Param.Row r in rows) + foreach ((string param, Param.Row r) in rows) { if (maxResultsPerRefType <= 0) { @@ -792,7 +792,7 @@ public static void DrawCalcCorrectGraph(EditorScreen screen, ParamMetaData meta, var searchTerm = pref.conditionField != null ? $@"prop {fieldName} ^{currentID}$ && prop {pref.conditionField} ^{pref.conditionValue}$" : $@"prop {fieldName} ^{currentID}$"; - return RowSearchEngine.rse.Search((bank, bank.Params[paramName]), searchTerm, false, false); + return RowSearchEngine.rse.Search((bank, bank.Params[paramName]), searchTerm, false, false).Select((x, i) => x.Item2).ToList(); } public static bool ImguiTableSeparator() diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 7e23a315d..65e474c3f 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -505,9 +505,9 @@ private void Setup() throw new Exception($@"Cannot average field {field[0]}"); } - List? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - IEnumerable vals = rows.Select((row, i) => row.Get(col)); + IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); return (j, row) => (k, c) => avg.ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -521,9 +521,9 @@ private void Setup() throw new Exception($@"Could not locate field {field[0]}"); } - List? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - IEnumerable vals = rows.Select((row, i) => row.Get(col)); + IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return (j, row) => (k, c) => avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -537,9 +537,9 @@ private void Setup() throw new Exception($@"Could not locate field {field[0]}"); } - List? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - var avg = ParamUtils.GetParamValueDistribution(rows, col).OrderByDescending(g => g.Item2) + var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; return (j, row) => (k, c) => avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -553,9 +553,9 @@ private void Setup() throw new Exception($@"Could not locate field {field[0]}"); } - List? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - var min = rows.Min(r => r[field[0]].Value.Value); + var min = rows.Min(r => r.Item2[field[0]].Value.Value); return (j, row) => (k, c) => min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, @@ -568,9 +568,9 @@ private void Setup() throw new Exception($@"Could not locate field {field[0]}"); } - List? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); - var max = rows.Max(r => r[field[0]].Value.Value); + var max = rows.Max(r => r.Item2[field[0]].Value.Value); return (j, row) => (k, c) => max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); argumentGetters.Add("random", newGetter( @@ -615,9 +615,9 @@ private void Setup() paramFieldRowSelector => { Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; - List srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), + List<(string, Param.Row)> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); - var values = srcRows.Select((r, i) => r[paramFieldRowSelector[1]].Value.Value).ToArray(); + var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, param) => (j, row) => (k, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); diff --git a/src/StudioCore/ParamEditor/ParamEditorScreen.cs b/src/StudioCore/ParamEditor/ParamEditorScreen.cs index 01c9959a1..6b9bb1fd6 100644 --- a/src/StudioCore/ParamEditor/ParamEditorScreen.cs +++ b/src/StudioCore/ParamEditor/ParamEditorScreen.cs @@ -787,7 +787,7 @@ public void OnGUI(string[] initcmd) () => RowSearchEngine.rse.Search( (ParamBank.PrimaryBank, ParamBank.PrimaryBank.Params[_activeView._selection.GetActiveParam()]), - _activeView._selection.GetCurrentRowSearchString(), true, true))) + _activeView._selection.GetCurrentRowSearchString(), true, true).Select((x, i) => x.Item2))) { _activeView._selection.AddRowToSelection(row); diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index a216860c5..f6bc53d83 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -440,7 +440,7 @@ private void ParamView_RowList(bool doFocus, bool isActiveView, float scrollTo, List rows = UICache.GetCached(_paramEditor, (_viewIndex, activeParam), () => RowSearchEngine.rse.Search((ParamBank.PrimaryBank, para), - _selection.GetCurrentRowSearchString(), true, true)); + _selection.GetCurrentRowSearchString(), true, true).Select((x, i) => x.Item2).ToList()); var enableGrouping = !CFG.Current.Param_DisableRowGrouping && ParamMetaData .Get(ParamBank.PrimaryBank.Params[activeParam].AppliedParamdef).ConsecutiveIDs; From 850f2c2de960b5dbd43f3d4e4c91fbca7602587b Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 6 Feb 2024 19:51:19 +0000 Subject: [PATCH 13/61] Compiles and = works --- .../Editor/MassEdit/EditOperation.cs | 103 ++++++++++++------ src/StudioCore/Editor/MassEdit/MassEdit.cs | 44 ++++---- 2 files changed, 90 insertions(+), 57 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 65e474c3f..93e0d3bfe 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -300,9 +300,20 @@ private MEOperationArgument() { Setup(); } - - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func>>> + private OperationArgumentGetter newGetter

(string[] args, string wiki, + Func> + func, Func shouldShow = null) + { + return new OperationArgumentGetter(args, wiki, func, shouldShow); + } + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>> + func, Func shouldShow = null) + { + return new OperationArgumentGetter(args, wiki, func, shouldShow); + } + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>>> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); @@ -310,14 +321,14 @@ private OperationArgumentGetter newGetter(string[] args, string wiki, private void Setup() { - defaultGetter = newGetter(new string[0], "Gives the specified value", + defaultGetter = newGetter(new string[0], "Gives the specified value", value => (i, param) => (j, row) => (k, col) => value[0]); - argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", + argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", empty => (i, param) => (j, row) => (k, col) => { return row.Get(col).ToParamEditorString(); })); - argumentGetters.Add("field", newGetter(new[] { "field internalName" }, + argumentGetters.Add("field", newGetter(new[] { "field internalName" }, "Gives the value of the given cell/field for the currently selected row and param", field => (i, param) => { @@ -333,7 +344,7 @@ private void Setup() return (k, c) => v; }; })); - argumentGetters.Add("vanilla", newGetter(new string[0], + argumentGetters.Add("vanilla", newGetter(new string[0], "Gives the value of the equivalent cell/field in the vanilla regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", empty => { @@ -367,7 +378,7 @@ private void Setup() }; }; })); - argumentGetters.Add("aux", newGetter(new[] { "parambank name" }, + argumentGetters.Add("aux", newGetter(new[] { "parambank name" }, "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankName => { @@ -406,7 +417,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, + argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", field => (i, param) => { @@ -435,7 +446,7 @@ private void Setup() return (k, c) => v; }; })); - argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, + argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankAndField => { @@ -473,7 +484,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, + argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, "Returns the specific value specified by the exact param, row and field.", address => { Param param = ParamBank.PrimaryBank.Params[address[0]]; @@ -489,7 +500,7 @@ private void Setup() var value = row.Get(field).ToParamEditorString(); return (i, param) => (j, row) => (k, col) => value; }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { @@ -511,7 +522,7 @@ private void Setup() var avg = vals.Average(val => Convert.ToDouble(val)); return (j, row) => (k, c) => avg.ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, "Gives the median value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { @@ -527,7 +538,7 @@ private void Setup() var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return (j, row) => (k, c) => avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { @@ -543,7 +554,7 @@ private void Setup() .First().Item1; return (j, row) => (k, c) => avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, "Gives the smallest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { @@ -558,7 +569,7 @@ private void Setup() var min = rows.Min(r => r.Item2[field[0]].Value.Value); return (j, row) => (k, c) => min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, "Gives the largest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { @@ -573,7 +584,7 @@ private void Setup() var max = rows.Max(r => r.Item2[field[0]].Value.Value); return (j, row) => (k, c) => max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("random", newGetter( + argumentGetters.Add("random", newGetter( new[] { "minimum number (inclusive)", "maximum number (exclusive)" }, "Gives a random decimal number between the given values for each selected value", minAndMax => { @@ -592,7 +603,7 @@ private void Setup() var range = max - min; return (i, param) => (j, row) => (k, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randint", newGetter( + argumentGetters.Add("randint", newGetter( new[] { "minimum integer (inclusive)", "maximum integer (inclusive)" }, "Gives a random integer between the given values for each selected value", minAndMax => { @@ -610,7 +621,7 @@ private void Setup() return (i, param) => (j, row) => (k, c) => Random.Shared.NextInt64(min, max + 1).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, + argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", paramFieldRowSelector => { @@ -621,19 +632,19 @@ private void Setup() return (i, param) => (j, row) => (k, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("paramIndex", newGetter(new string[0], + argumentGetters.Add("paramIndex", newGetter(new string[0], "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", empty => (i, param) => (j, row) => (k, col) => { return i.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("rowIndex", newGetter(new string[0], + argumentGetters.Add("rowIndex", newGetter(new string[0], "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", empty => (i, param) => (j, row) => (k, col) => { return j.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("fieldIndex", newGetter(new string[0], + argumentGetters.Add("fieldIndex", newGetter(new string[0], "Gives an integer for the current selected cell/field, beginning at 0 and increasing by 1 for each cell/field selected", empty => (i, param) => (j, row) => (k, col) => { @@ -667,27 +678,23 @@ private void Setup() return options; } - internal Func>>[] - getContextualArguments(int argumentCount, string opData) + internal object[] getContextualArguments(int argumentCount, string opData) { var opArgs = opData == null ? new string[0] : opData.Split(':', argumentCount); - var contextualArgs = - new Func>>[opArgs - .Length]; + var contextualArgs = new object[opArgs.Length]; for (var i = 0; i < opArgs.Length; i++) { - contextualArgs[i] = getContextualArgument(opArgs[i]); + contextualArgs[i] = getContextualArgumentFromArgs(opArgs[i]); } return contextualArgs; } - internal Func>> - getContextualArgument(string opArg) + internal object getContextualArgumentFromArgs(string opArg) { if (opArg.StartsWith('"') && opArg.EndsWith('"')) { - return (i, p) => (j, r) => (k, c) => opArg.Substring(1, opArg.Length - 2); + return opArg.Substring(1, opArg.Length - 2); } if (opArg.StartsWith('$')) @@ -725,14 +732,13 @@ internal class OperationArgumentGetter { public string[] args; - internal Func>>> - func; + internal Func func; internal Func shouldShow; public string wiki; internal OperationArgumentGetter(string[] args, string wiki, - Func>>> + Func func, Func shouldShow) { this.args = args; @@ -740,4 +746,33 @@ internal OperationArgumentGetter(string[] args, string wiki, this.func = func; this.shouldShow = shouldShow; } + + + +} +public static class OAGFuncExtension +{ + /*internal static object tryFold(this Func func, object newContextInput) + { + Type t = newContextInput.GetType(); + if (func.Method.GetParameters()[0].ParameterType == t) + return func(newContextInput); + return func; + }*/ + public static object tryFoldAsFunc(this object maybeFunc, int editIndex, object newContextInput) + { + if (maybeFunc is not Delegate) + return maybeFunc; + Delegate func = (Delegate)maybeFunc; + var parameters = func.Method.GetParameters(); + if (parameters.Length == 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == newContextInput.GetType()) + return func.DynamicInvoke(editIndex, newContextInput); + return func; + } + public static object assertCompleteContextOrThrow(this object maybeFunc) + { + if (maybeFunc is Delegate) + throw new Exception("Argument getter did not have enough context to complete."); + return maybeFunc; + } } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index f9d991d11..bd8cf98bc 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -138,9 +138,9 @@ public class MassParamEditRegex private ParamEditorSelectionState context; private Func genericFunc; - private Func[], string, Param.Row, List, + private Func, MassEditResult> rowOpOrCellStageFunc; - private Func>>[] paramArgFuncs; + private object[] paramArgFuncs; private string[] argNames; private MEOperationStage globalOperationInfo; @@ -371,7 +371,7 @@ private void ExecParamOperationArguments(int currentLine, string opargs) private MassEditResult ExecGlobalOp(int currentLine) { - var globalArgValues = paramArgFuncs.Select(f => f(-1, null)(-1, null)(-1, (PseudoColumn.None, null))) + var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow().ToParamEditorString()) .ToArray(); var result = (bool)genericFunc(context, globalArgValues); if (!result) @@ -384,9 +384,7 @@ private MassEditResult ExecGlobalOp(int currentLine) private MassEditResult ExecVarStage(int currentLine) { - ; - var varArgs = paramArgFuncs - .Select((func, i) => func(-1, null)(-1, null)(-1, (PseudoColumn.None, null))).ToArray(); + var varArgs = paramArgFuncs; foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) { MassEditResult res = ExecVarOpStage(currentLine, varName, varArgs); @@ -399,9 +397,9 @@ private MassEditResult ExecVarStage(int currentLine) return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecVarOpStage(int currentLine, string var, string[] args) + private MassEditResult ExecVarOpStage(int currentLine, string var, object[] args) { - MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args); + MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow().ToParamEditorString()).ToArray()); var result = true; // Anything that practicably can go wrong if (!result) { @@ -414,15 +412,15 @@ private MassEditResult ExecVarOpStage(int currentLine, string var, string[] args private MassEditResult ExecParamRowStage(int currentLine, List partialActions) { Param activeParam = bank.Params[context.GetActiveParam()]; - IEnumerable>> paramArgFunc = - paramArgFuncs.Select((func, i) => func(0, activeParam)); // technically invalid for clipboard + IEnumerable paramArgFunc = + paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(0, activeParam)); // technically invalid for clipboard var rowEditCount = -1; foreach ((MassEditRowSource source, Param.Row row) in ParamAndRowSearchEngine.parse.Search(context, paramRowStageInfo.command, false, false)) { rowEditCount++; - Func[] rowArgFunc = - paramArgFunc.Select((rowFunc, i) => rowFunc(rowEditCount, row)).ToArray(); + object[] rowArgFunc = + paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); var paramname = source == MassEditRowSource.Selection ? context.GetActiveParam() : ParamBank.ClipboardParam; @@ -443,8 +441,8 @@ private MassEditResult ExecParamStage(int currentLine, List partia foreach ((ParamBank b, Param p) in ParamSearchEngine.pse.Search(false, paramStageInfo.command, false, false)) { paramEditCount++; - IEnumerable>> paramArgFunc = - paramArgFuncs.Select((func, i) => func(paramEditCount, p)); + IEnumerable paramArgFunc = + paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(paramEditCount, p)); if (argNames.Length != paramArgFuncs.Length) { return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {operationForPrint} (line {currentLine})"); @@ -462,15 +460,15 @@ private MassEditResult ExecParamStage(int currentLine, List partia } private MassEditResult ExecRowStage(int currentLine, - IEnumerable>> paramArgFunc, + IEnumerable paramArgFunc, string paramname, ParamBank b, Param p, List partialActions) { var rowEditCount = -1; foreach ((string param, Param.Row row) in RowSearchEngine.rse.Search((b, p), rowStageInfo.command, false, false)) { rowEditCount++; - Func[] rowArgFunc = - paramArgFunc.Select((rowFunc, i) => rowFunc(rowEditCount, row)).ToArray(); + object[] rowArgFunc = + paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); MassEditResult res = rowOpOrCellStageFunc(currentLine, rowArgFunc, paramname, row, partialActions); if (res.Type != MassEditResultType.SUCCESS) { @@ -481,10 +479,10 @@ private MassEditResult ExecRowStage(int currentLine, return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecRowOp(int currentLine, Func[] rowArgFunc, string paramname, + private MassEditResult ExecRowOp(int currentLine, object[] rowArgFunc, string paramname, Param.Row row, List partialActions) { - var rowArgValues = rowArgFunc.Select((argV, i) => argV(-1, (PseudoColumn.None, null))).ToArray(); + var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow().ToParamEditorString()).ToArray(); (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); if (p2 == null) { @@ -499,7 +497,7 @@ private MassEditResult ExecRowOp(int currentLine, Func[] rowArgFunc, + private MassEditResult ExecCellStage(int currentLine, object[] rowArgFunc, string paramname, Param.Row row, List partialActions) { var cellEditCount = -1; @@ -507,7 +505,7 @@ private MassEditResult ExecCellStage(int currentLine, Func argV(cellEditCount, col)).ToArray(); + var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); MassEditResult res = ExecCellOp(currentLine, cellArgValues, paramname, row, col, partialActions); if (res.Type != MassEditResultType.SUCCESS) { @@ -518,14 +516,14 @@ private MassEditResult ExecCellStage(int currentLine, Func partialActions) { object res = null; string errHelper = null; try { - res = genericFunc(row.Get(col), cellArgValues); + res = genericFunc(row.Get(col), cellArgValues.Select((x, i) => x.assertCompleteContextOrThrow().ToParamEditorString()).ToArray()); } catch (FormatException e) { From 682287042e7f099aad25e2882f53ca34c5f163c1 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 6 Feb 2024 20:59:20 +0000 Subject: [PATCH 14/61] Error handling improvement --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index bd8cf98bc..a39f47632 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -362,7 +362,7 @@ private void ExecParamOperationArguments(int currentLine, string opargs) } catch (Exception e) { - return (new MassEditResult(MassEditResultType.OPERATIONERROR, @$"Error on line {currentLine}" + '\n' + e.ToString()), null); + return (new MassEditResult(MassEditResultType.OPERATIONERROR, @$"Error on line {currentLine}" + '\n' + e.GetBaseException().ToString()), null); } return (new MassEditResult(MassEditResultType.SUCCESS, $@"{partialActions.Count} cells affected"), @@ -486,7 +486,7 @@ private MassEditResult ExecRowOp(int currentLine, object[] rowArgFunc, string pa (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); if (p2 == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo} {String.Join(' ', rowArgValues)} on row (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {currentLine})"); } if (rs != null) @@ -527,30 +527,30 @@ private MassEditResult ExecCellOp(int currentLine, object[] cellArgValues, strin } catch (FormatException e) { - errHelper = "Type is not correct"; + errHelper = "Type is not correct. Check the operation arguments result in usable values."; } catch (InvalidCastException e) { - errHelper = "Cannot cast to correct type"; + errHelper = "Cannot cast to correct type. Check the operation arguments result in usable values."; } catch (Exception e) { - errHelper = "Unknown error"; + errHelper = $@"Unknown error ({e.Message})"; } if (res == null && col.Item1 == PseudoColumn.ID) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo} {String.Join(' ', cellArgValues)} on ID ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {String.Join(' ', cellArgValues)} on ID ({errHelper}) (line {currentLine})"); } if (res == null && col.Item1 == PseudoColumn.Name) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo} {String.Join(' ', cellArgValues)} on Name ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {String.Join(' ', cellArgValues)} on Name ({errHelper}) (line {currentLine})"); } if (res == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo} {String.Join(' ', cellArgValues)} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {String.Join(' ', cellArgValues)} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); } partialActions.AppendParamEditAction(row, col, res); From 88b77a694178d42d38d8a8336c69fef832feaff8 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 6 Feb 2024 21:19:44 +0000 Subject: [PATCH 15/61] Cont. exception handling --- .../Editor/MassEdit/EditOperation.cs | 2 +- src/StudioCore/Editor/MassEdit/MassEdit.cs | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 93e0d3bfe..1c9d27542 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -772,7 +772,7 @@ public static object tryFoldAsFunc(this object maybeFunc, int editIndex, object public static object assertCompleteContextOrThrow(this object maybeFunc) { if (maybeFunc is Delegate) - throw new Exception("Argument getter did not have enough context to complete."); + throw new MEOperationException("Argument getter did not have enough context to determine the value to use."); return maybeFunc; } } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index a39f47632..e755a10a2 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -34,6 +34,12 @@ public MEParseException(string? message, int line) : base($@"{message} (line {li { } } +internal class MEOperationException : Exception +{ + public MEOperationException(string? message) : base(message) + { + } +} internal struct MEFilterStage { @@ -533,24 +539,33 @@ private MassEditResult ExecCellOp(int currentLine, object[] cellArgValues, strin { errHelper = "Cannot cast to correct type. Check the operation arguments result in usable values."; } + catch (MEOperationException e) + { + errHelper = e.Message; + } catch (Exception e) { errHelper = $@"Unknown error ({e.Message})"; } + string errorValue = null; + if (res == null) + { + errorValue = cellArgValues.Length > 0 && cellArgValues[0] is not Delegate ? String.Join(' ', cellArgValues) : "[Undetermined value]"; + } if (res == null && col.Item1 == PseudoColumn.ID) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {String.Join(' ', cellArgValues)} on ID ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on ID ({errHelper}) (line {currentLine})"); } if (res == null && col.Item1 == PseudoColumn.Name) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {String.Join(' ', cellArgValues)} on Name ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on Name ({errHelper}) (line {currentLine})"); } if (res == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {String.Join(' ', cellArgValues)} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); } partialActions.AppendParamEditAction(row, col, res); From 481bd486398e1c1037a741735831b57455c5befa Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 6 Feb 2024 21:40:01 +0000 Subject: [PATCH 16/61] Remove unneeded contexts from getters. Exceptions updated. --- .../Editor/MassEdit/EditOperation.cs | 151 +++++++++--------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 9 +- 2 files changed, 83 insertions(+), 77 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 1c9d27542..dd11925da 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -146,12 +146,12 @@ internal override void Setup() Param.Row row = paramAndRow.Item2; if (paramKey == null) { - throw new Exception(@"Could not locate param"); + throw new MEOperationException(@"Could not locate param"); } if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) { - throw new Exception($@"Could not locate param {paramKey}"); + throw new MEOperationException($@"Could not locate param {paramKey}"); } Param p = ParamBank.PrimaryBank.Params[paramKey]; @@ -174,12 +174,12 @@ internal override void Setup() Param.Row row = paramAndRow.Item2; if (paramKey == null) { - throw new Exception(@"Could not locate param"); + throw new MEOperationException(@"Could not locate param"); } if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) { - throw new Exception($@"Could not locate param {paramKey}"); + throw new MEOperationException($@"Could not locate param {paramKey}"); } var count = uint.Parse(args[0]); @@ -207,12 +207,12 @@ internal override void Setup() Param.Row row = paramAndRow.Item2; if (paramKey == null) { - throw new Exception(@"Could not locate param"); + throw new MEOperationException(@"Could not locate param"); } if (!ParamBank.PrimaryBank.Params.ContainsKey(paramKey)) { - throw new Exception($@"Could not locate param {paramKey}"); + throw new MEOperationException($@"Could not locate param {paramKey}"); } Param p = ParamBank.PrimaryBank.Params[paramKey]; @@ -321,27 +321,27 @@ private OperationArgumentGetter newGetter(string[] args, string wiki, private void Setup() { - defaultGetter = newGetter(new string[0], "Gives the specified value", - value => (i, param) => (j, row) => (k, col) => value[0]); - argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", - empty => (i, param) => (j, row) => (k, col) => + defaultGetter = newGetter(new string[0], "Gives the specified value", + value => (i, c) => value[0]); + argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", + empty => (j, row) => (k, col) => { return row.Get(col).ToParamEditorString(); })); - argumentGetters.Add("field", newGetter(new[] { "field internalName" }, + argumentGetters.Add("field", newGetter(new[] { "field internalName" }, "Gives the value of the given cell/field for the currently selected row and param", field => (i, param) => { (PseudoColumn, Param.Column) col = param.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } return (j, row) => { var v = row.Get(col).ToParamEditorString(); - return (k, c) => v; + return v; }; })); argumentGetters.Add("vanilla", newGetter(new string[0], @@ -354,7 +354,7 @@ private void Setup() var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); if (!bank.Params.ContainsKey(paramName)) { - throw new Exception($@"Could not locate vanilla param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate vanilla param for {param.ParamType}"); } Param vParam = bank.Params[paramName]; @@ -363,14 +363,14 @@ private void Setup() Param.Row vRow = vParam?[row.ID]; if (vRow == null) { - throw new Exception($@"Could not locate vanilla row {row.ID}"); + throw new MEOperationException($@"Could not locate vanilla row {row.ID}"); } return (k, col) => { if (col.Item1 == PseudoColumn.None && col.Item2 == null) { - throw new Exception(@"Could not locate given field or property"); + throw new MEOperationException(@"Could not locate given field or property"); } return vRow.Get(col).ToParamEditorString(); @@ -384,7 +384,7 @@ private void Setup() { if (!ParamBank.AuxBanks.ContainsKey(bankName[0])) { - throw new Exception($@"Could not locate paramBank {bankName[0]}"); + throw new MEOperationException($@"Could not locate paramBank {bankName[0]}"); } ParamBank bank = ParamBank.AuxBanks[bankName[0]]; @@ -393,7 +393,7 @@ private void Setup() var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); if (!bank.Params.ContainsKey(paramName)) { - throw new Exception($@"Could not locate aux param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate aux param for {param.ParamType}"); } Param vParam = bank.Params[paramName]; @@ -402,14 +402,14 @@ private void Setup() Param.Row vRow = vParam?[row.ID]; if (vRow == null) { - throw new Exception($@"Could not locate aux row {row.ID}"); + throw new MEOperationException($@"Could not locate aux row {row.ID}"); } return (k, col) => { if (!col.IsColumnValid()) { - throw new Exception(@"Could not locate given field or property"); + throw new MEOperationException(@"Could not locate given field or property"); } return vRow.Get(col).ToParamEditorString(); @@ -417,7 +417,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, + argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", field => (i, param) => { @@ -425,13 +425,13 @@ private void Setup() Param? vParam = ParamBank.VanillaBank.GetParamFromName(paramName); if (vParam == null) { - throw new Exception($@"Could not locate vanilla param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate vanilla param for {param.ParamType}"); } (PseudoColumn, Param.Column) col = vParam.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } return (j, row) => @@ -439,20 +439,20 @@ private void Setup() Param.Row vRow = vParam?[row.ID]; if (vRow == null) { - throw new Exception($@"Could not locate vanilla row {row.ID}"); + throw new MEOperationException($@"Could not locate vanilla row {row.ID}"); } var v = vRow.Get(col).ToParamEditorString(); - return (k, c) => v; + return v; }; })); - argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, + argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankAndField => { if (!ParamBank.AuxBanks.ContainsKey(bankAndField[0])) { - throw new Exception($@"Could not locate paramBank {bankAndField[0]}"); + throw new MEOperationException($@"Could not locate paramBank {bankAndField[0]}"); } ParamBank bank = ParamBank.AuxBanks[bankAndField[0]]; @@ -461,14 +461,14 @@ private void Setup() var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); if (!bank.Params.ContainsKey(paramName)) { - throw new Exception($@"Could not locate aux param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate aux param for {param.ParamType}"); } Param vParam = bank.Params[paramName]; (PseudoColumn, Param.Column) col = vParam.GetCol(bankAndField[1]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {bankAndField[1]}"); + throw new MEOperationException($@"Could not locate field {bankAndField[1]}"); } return (j, row) => @@ -476,115 +476,115 @@ private void Setup() Param.Row vRow = vParam?[row.ID]; if (vRow == null) { - throw new Exception($@"Could not locate aux row {row.ID}"); + throw new MEOperationException($@"Could not locate aux row {row.ID}"); } var v = vRow.Get(col).ToParamEditorString(); - return (k, c) => v; + return v; }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, + argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, "Returns the specific value specified by the exact param, row and field.", address => { Param param = ParamBank.PrimaryBank.Params[address[0]]; if (param == null) - throw new Exception($@"Could not find param {address[0]}"); + throw new MEOperationException($@"Could not find param {address[0]}"); var id = int.Parse(address[1]); (PseudoColumn, Param.Column) field = param.GetCol(address[2]); if (!field.IsColumnValid()) - throw new Exception($@"Could not find field {address[2]} in param {address[0]}"); + throw new MEOperationException($@"Could not find field {address[2]} in param {address[0]}"); var row = param[id]; if (row == null) - throw new Exception($@"Could not find row {id} in param {address[0]}"); + throw new MEOperationException($@"Could not find row {id} in param {address[0]}"); var value = row.Get(field).ToParamEditorString(); - return (i, param) => (j, row) => (k, col) => value; + return (i, c) => value; }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { (PseudoColumn, Param.Column) col = param.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } Type colType = col.GetColumnType(); if (colType == typeof(string) || colType == typeof(byte[])) { - throw new Exception($@"Cannot average field {field[0]}"); + throw new MEOperationException($@"Cannot average field {field[0]}"); } List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); - return (j, row) => (k, c) => avg.ToString(); + return avg.ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, "Gives the median value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { (PseudoColumn, Param.Column) col = param.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); - return (j, row) => (k, c) => avg.ToParamEditorString(); + return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { (PseudoColumn, Param.Column) col = param.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; - return (j, row) => (k, c) => avg.ToParamEditorString(); + return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, "Gives the smallest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { (PseudoColumn, Param.Column) col = param.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); - return (j, row) => (k, c) => min.ToParamEditorString(); + return min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, "Gives the largest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { (PseudoColumn, Param.Column) col = param.GetCol(field[0]); if (!col.IsColumnValid()) { - throw new Exception($@"Could not locate field {field[0]}"); + throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); - return (j, row) => (k, c) => max.ToParamEditorString(); + return max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("random", newGetter( + argumentGetters.Add("random", newGetter( new[] { "minimum number (inclusive)", "maximum number (exclusive)" }, "Gives a random decimal number between the given values for each selected value", minAndMax => { @@ -592,18 +592,18 @@ private void Setup() double max; if (!double.TryParse(minAndMax[0], out min) || !double.TryParse(minAndMax[1], out max)) { - throw new Exception(@"Could not parse min and max random values"); + throw new MEOperationException(@"Could not parse min and max random values"); } if (max <= min) { - throw new Exception(@"Random max must be greater than min"); + throw new MEOperationException(@"Random max must be greater than min"); } var range = max - min; - return (i, param) => (j, row) => (k, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); + return (i, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randint", newGetter( + argumentGetters.Add("randint", newGetter( new[] { "minimum integer (inclusive)", "maximum integer (inclusive)" }, "Gives a random integer between the given values for each selected value", minAndMax => { @@ -611,17 +611,17 @@ private void Setup() int max; if (!int.TryParse(minAndMax[0], out min) || !int.TryParse(minAndMax[1], out max)) { - throw new Exception(@"Could not parse min and max randint values"); + throw new MEOperationException(@"Could not parse min and max randint values"); } if (max <= min) { - throw new Exception(@"Random max must be greater than min"); + throw new MEOperationException(@"Random max must be greater than min"); } - return (i, param) => (j, row) => (k, c) => Random.Shared.NextInt64(min, max + 1).ToString(); + return (i, c) => Random.Shared.NextInt64(min, max + 1).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, + argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", paramFieldRowSelector => { @@ -629,24 +629,23 @@ private void Setup() List<(string, Param.Row)> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); - return (i, param) => - (j, row) => (k, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); + return (i, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("paramIndex", newGetter(new string[0], + argumentGetters.Add("paramIndex", newGetter(new string[0], "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", - empty => (i, param) => (j, row) => (k, col) => + empty => (i, param) => { return i.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("rowIndex", newGetter(new string[0], + argumentGetters.Add("rowIndex", newGetter(new string[0], "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", - empty => (i, param) => (j, row) => (k, col) => + empty => (j, row) => { return j.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("fieldIndex", newGetter(new string[0], + argumentGetters.Add("fieldIndex", newGetter<(PseudoColumn, Param.Column)>(new string[0], "Gives an integer for the current selected cell/field, beginning at 0 and increasing by 1 for each cell/field selected", - empty => (i, param) => (j, row) => (k, col) => + empty => (k, col) => { return k.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -709,7 +708,7 @@ internal object getContextualArgumentFromArgs(string opArg) var opArgArgs = arg.Length > 1 ? arg[1].Split(" ", getter.args.Length) : new string[0]; if (opArgArgs.Length != getter.args.Length) { - throw new Exception( + throw new MEOperationException( @$"Contextual value {arg[0]} has wrong number of arguments. Expected {opArgArgs.Length}"); } @@ -769,10 +768,18 @@ public static object tryFoldAsFunc(this object maybeFunc, int editIndex, object return func.DynamicInvoke(editIndex, newContextInput); return func; } - public static object assertCompleteContextOrThrow(this object maybeFunc) + public static object assertCompleteContextOrThrow(this object maybeFunc, int editIndex) { if (maybeFunc is Delegate) - throw new MEOperationException("Argument getter did not have enough context to determine the value to use."); + { + Delegate func = (Delegate)maybeFunc; + var parameters = func.Method.GetParameters(); + /* bool is provided as a special context argument for no context */ + if (parameters.Length == 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(bool)) + return assertCompleteContextOrThrow(func.DynamicInvoke(editIndex, false), editIndex); + else + throw new MEOperationException("Argument getter did not have enough context to determine the value to use."); + } return maybeFunc; } } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index e755a10a2..3da03249a 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -377,8 +377,7 @@ private void ExecParamOperationArguments(int currentLine, string opargs) private MassEditResult ExecGlobalOp(int currentLine) { - var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow().ToParamEditorString()) - .ToArray(); + var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); var result = (bool)genericFunc(context, globalArgValues); if (!result) { @@ -405,7 +404,7 @@ private MassEditResult ExecVarStage(int currentLine) private MassEditResult ExecVarOpStage(int currentLine, string var, object[] args) { - MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow().ToParamEditorString()).ToArray()); + MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); var result = true; // Anything that practicably can go wrong if (!result) { @@ -488,7 +487,7 @@ private MassEditResult ExecRowStage(int currentLine, private MassEditResult ExecRowOp(int currentLine, object[] rowArgFunc, string paramname, Param.Row row, List partialActions) { - var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow().ToParamEditorString()).ToArray(); + var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); if (p2 == null) { @@ -529,7 +528,7 @@ private MassEditResult ExecCellOp(int currentLine, object[] cellArgValues, strin string errHelper = null; try { - res = genericFunc(row.Get(col), cellArgValues.Select((x, i) => x.assertCompleteContextOrThrow().ToParamEditorString()).ToArray()); + res = genericFunc(row.Get(col), cellArgValues.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); } catch (FormatException e) { From 128240e6e55123b4bfc75bb012eb199f9a5b7939 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 6 Feb 2024 21:54:21 +0000 Subject: [PATCH 17/61] un-public stuff --- .../Editor/MassEdit/EditOperation.cs | 32 +++++++++---------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 8 ++--- .../Editor/MassEdit/SearchEngine.cs | 32 +++++++++---------- .../ParamEditor/ParamEditorScreen.cs | 21 ------------ 4 files changed, 36 insertions(+), 57 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index dd11925da..6a67a26cb 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -24,7 +24,7 @@ internal MEOperationDef(string[] args, string tooltip, Func func function = func as Func; } } -public abstract class METypelessOperation +internal abstract class METypelessOperation { private static Dictionary editOperations = new(); internal static void AddEditOperation(MEOperation engine) @@ -39,7 +39,7 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); } -public class MEOperation : METypelessOperation +internal class MEOperation : METypelessOperation { internal Dictionary operations = new(); internal string name = "[Unnamed operation type]"; @@ -62,7 +62,7 @@ internal override Dictionary AllCommands() return operations; } - public List<(string, string[], string)> AvailableCommands() + internal List<(string, string[], string)> AvailableCommands() { List<(string, string[], string)> options = new(); foreach (var op in operations.Keys) @@ -87,9 +87,9 @@ internal override string NameForHelpTexts() } } -public class MEGlobalOperation : MEOperation +internal class MEGlobalOperation : MEOperation { - public static MEGlobalOperation globalOps = new(); + internal static MEGlobalOperation globalOps = new(); internal override void Setup() { @@ -131,7 +131,7 @@ internal override void Setup() } } -public class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> +internal class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> { public static MERowOperation rowOps = new(); @@ -222,7 +222,7 @@ internal override void Setup() } } -public class MEValueOperation : MEOperation +internal class MEValueOperation : MEOperation { public static MEValueOperation valueOps = new(); @@ -290,9 +290,9 @@ internal override void Setup() } } -public class MEOperationArgument +internal class MEOperationArgument { - public static MEOperationArgument arg = new(); + internal static MEOperationArgument arg = new(); private readonly Dictionary argumentGetters = new(); private OperationArgumentGetter defaultGetter; @@ -651,7 +651,7 @@ private void Setup() }, () => CFG.Current.Param_AdvancedMassedit)); } - public List<(string, string[])> AllArguments() + internal List<(string, string[])> AllArguments() { List<(string, string[])> options = new(); foreach (var op in argumentGetters.Keys) @@ -662,7 +662,7 @@ private void Setup() return options; } - public List<(string, string, string[])> VisibleArguments() + internal List<(string, string, string[])> VisibleArguments() { List<(string, string, string[])> options = new(); foreach (var op in argumentGetters.Keys) @@ -729,12 +729,12 @@ internal object getContextualArgumentFromArgs(string opArg) internal class OperationArgumentGetter { - public string[] args; + internal string[] args; internal Func func; internal Func shouldShow; - public string wiki; + internal string wiki; internal OperationArgumentGetter(string[] args, string wiki, Func @@ -749,7 +749,7 @@ internal OperationArgumentGetter(string[] args, string wiki, } -public static class OAGFuncExtension +internal static class OAGFuncExtension { /*internal static object tryFold(this Func func, object newContextInput) { @@ -758,7 +758,7 @@ public static class OAGFuncExtension return func(newContextInput); return func; }*/ - public static object tryFoldAsFunc(this object maybeFunc, int editIndex, object newContextInput) + internal static object tryFoldAsFunc(this object maybeFunc, int editIndex, object newContextInput) { if (maybeFunc is not Delegate) return maybeFunc; @@ -768,7 +768,7 @@ public static object tryFoldAsFunc(this object maybeFunc, int editIndex, object return func.DynamicInvoke(editIndex, newContextInput); return func; } - public static object assertCompleteContextOrThrow(this object maybeFunc, int editIndex) + internal static object assertCompleteContextOrThrow(this object maybeFunc, int editIndex) { if (maybeFunc is Delegate) { diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 3da03249a..821067be8 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -30,13 +30,13 @@ public MassEditResult(MassEditResultType result, string info) internal class MEParseException : Exception { - public MEParseException(string? message, int line) : base($@"{message} (line {line})") + internal MEParseException(string? message, int line) : base($@"{message} (line {line})") { } } internal class MEOperationException : Exception { - public MEOperationException(string? message) : base(message) + internal MEOperationException(string? message) : base(message) { } } @@ -85,7 +85,7 @@ internal class MECommand public static class MassParamEdit { - public static Dictionary massEditVars = new(); + internal static Dictionary massEditVars = new(); internal static object WithDynamicOf(object instance, Func dynamicFunc) { @@ -106,7 +106,7 @@ internal static object WithDynamicOf(object instance, Func dyna } } - public static void AppendParamEditAction(this List actions, Param.Row row, + internal static void AppendParamEditAction(this List actions, Param.Row row, (PseudoColumn, Param.Column) col, object newval) { if (col.Item1 == PseudoColumn.ID) diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 3c6029aca..13b6444ef 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -25,12 +25,12 @@ internal static void AddSearchEngine(SearchEngine engine) { return searchEngines[t]; } - public abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); - public abstract List<(string, string[])> AllCommands(); - public abstract List AvailableCommandsForHelpText(); - public abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); - public abstract METypelessOperation NextOperation(); - public abstract string NameForHelpTexts(); + internal abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); + internal abstract List<(string, string[])> AllCommands(); + internal abstract List AvailableCommandsForHelpText(); + internal abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); + internal abstract METypelessOperation NextOperation(); + internal abstract string NameForHelpTexts(); } internal class SearchEngine : TypelessSearchEngine { @@ -41,7 +41,7 @@ internal class SearchEngine : TypelessSearchEngine internal Func> unpacker; internal string name = "[unnamed search engine]"; - public SearchEngine() + internal SearchEngine() { Setup(); AddSearchEngine(this); @@ -72,7 +72,7 @@ internal SearchEngineCommand newCmd(string[] args, string wiki, return new SearchEngineCommand(args, wiki, func, shouldShow); } - public bool HandlesCommand(string command) + internal bool HandlesCommand(string command) { if (command.Length > 0 && command.StartsWith('!')) { @@ -82,7 +82,7 @@ public bool HandlesCommand(string command) return filterList.ContainsKey(command.Split(" ")[0]); } - public override List AvailableCommandsForHelpText() + internal override List AvailableCommandsForHelpText() { List options = new(); foreach (var op in filterList.Keys) @@ -102,7 +102,7 @@ public override List AvailableCommandsForHelpText() return options; } - public override List<(string, string[], string)> VisibleCommands(bool includeDefault) + internal override List<(string, string[], string)> VisibleCommands(bool includeDefault) { List<(string, string[], string)> options = new(); foreach (var op in filterList.Keys) @@ -119,7 +119,7 @@ public override List AvailableCommandsForHelpText() return options; } - public override List<(string, string[])> AllCommands() + internal override List<(string, string[])> AllCommands() { List<(string, string[])> options = new(); foreach (var op in filterList.Keys) @@ -213,16 +213,16 @@ public virtual List Search(A context, List sourceSet, string command, bool return liveSet; } - public override List<(TypelessSearchEngine, Type)> NextSearchEngines() + internal override List<(TypelessSearchEngine, Type)> NextSearchEngines() { return GetSearchEngines(typeof(B)); } - public override METypelessOperation NextOperation() + internal override METypelessOperation NextOperation() { return METypelessOperation.GetEditOperation(typeof(B)); } - public override string NameForHelpTexts() + internal override string NameForHelpTexts() { return name; } @@ -230,10 +230,10 @@ public override string NameForHelpTexts() internal class SearchEngineCommand { - public string[] args; + internal string[] args; internal Func>> func; internal Func shouldShow; - public string wiki; + internal string wiki; internal SearchEngineCommand(string[] args, string wiki, Func>> func, Func shouldShow) diff --git a/src/StudioCore/ParamEditor/ParamEditorScreen.cs b/src/StudioCore/ParamEditor/ParamEditorScreen.cs index 6b9bb1fd6..d7161ebf1 100644 --- a/src/StudioCore/ParamEditor/ParamEditorScreen.cs +++ b/src/StudioCore/ParamEditor/ParamEditorScreen.cs @@ -109,27 +109,6 @@ public class ParamEditorScreen : EditorScreen internal ParamEditorView _activeView; - private string[] _autoFillArgsCop = Enumerable - .Repeat("", MEValueOperation.valueOps.AvailableCommands().Sum(x => x.Item2.Length)).ToArray(); - - private string[] _autoFillArgsCse = - Enumerable.Repeat("", CellSearchEngine.cse.AllCommands().Sum(x => x.Item2.Length)).ToArray(); - - private string[] _autoFillArgsOa = - Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length)).ToArray(); - - private string[] _autoFillArgsParse = Enumerable - .Repeat("", ParamAndRowSearchEngine.parse.AllCommands().Sum(x => x.Item2.Length)).ToArray(); - - private string[] _autoFillArgsPse = - Enumerable.Repeat("", ParamSearchEngine.pse.AllCommands().Sum(x => x.Item2.Length)).ToArray(); - - private string[] _autoFillArgsRop = Enumerable - .Repeat("", MERowOperation.rowOps.AvailableCommands().Sum(x => x.Item2.Length)).ToArray(); - - private string[] _autoFillArgsRse = - Enumerable.Repeat("", RowSearchEngine.rse.AllCommands().Sum(x => x.Item2.Length)).ToArray(); - // Clipboard vars private long _clipboardBaseRow; private string _currentCtrlVOffset = "0"; From f61b7fe0f0ed00a727bff4b27f956ab79d6aa86e Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sat, 10 Feb 2024 21:58:09 +0000 Subject: [PATCH 18/61] use ParseOpStep --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 97 +++++----------------- 1 file changed, 22 insertions(+), 75 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 821067be8..0bf7e338a 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -62,7 +62,8 @@ internal MEOperationStage(string toParse, int line, string stageName, METypeless { var stage = toParse.TrimStart().Split(' ', 2); command = stage[0].Trim(); - arguments = stage[1]; + if (stage.Length > 1) + arguments = stage[1]; if (command.Equals("")) { throw new MEParseException($@"Could not find operation to perform. Add : and one of {string.Join(' ', expectedOperation.AllCommands().Keys)}", line); @@ -192,13 +193,13 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseGlobalOpStep(currentLine, command); + (result, actions) = currentEditData.ParseOpStep(currentLine, command, "global", MEGlobalOperation.globalOps, ref currentEditData.globalOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { (result, actions) = ParseFilterStep(currentLine, command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (currentLine, restOfStages) => { - return currentEditData.ParseVarOpStep(currentLine, restOfStages); + return currentEditData.ParseOpStep(currentLine, restOfStages, "var", MEValueOperation.valueOps, ref currentEditData.varOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); } else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) @@ -207,12 +208,11 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { - return currentEditData.ParseRowOpStep(currentLine, restOfStages); + return currentEditData.ParseOpStep(currentLine, restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } return ParseFilterStep(currentLine, restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (currentLine, restOfStages) => { - currentEditData.rowOpOrCellStageFunc = currentEditData.ExecCellStage; - return currentEditData.ParseCellOpStep(currentLine, restOfStages); + return currentEditData.ParseOpStep(currentLine, restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); }); } @@ -224,12 +224,11 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { - return currentEditData.ParseRowOpStep(currentLine, restOfStages); + return currentEditData.ParseOpStep(currentLine, restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } return ParseFilterStep(currentLine, restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (currentLine, restOfStages) => { - currentEditData.rowOpOrCellStageFunc = currentEditData.ExecCellStage; - return currentEditData.ParseCellOpStep(currentLine, restOfStages); + return currentEditData.ParseOpStep(currentLine, restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); }); }); @@ -279,78 +278,26 @@ private static (MassEditResult, List) ParseFilterStep(int currentL var meOpDef = operation.AllCommands()[target.command]; (argNameTarget, funcTarget) = (meOpDef.argNames, meOpDef.function); - ExecParamOperationArguments(currentLine, globalOperationInfo.arguments); + ExecParamOperationArguments(currentLine, target.arguments); if (argNameTarget.Length != paramArgFuncs.Length) { return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); } + //hacks for now + if (globalOperationInfo.command != null) + return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); + if (varOperationInfo.command != null) + return SandboxMassEditExecution(currentLine, partials => ExecVarStage(currentLine)); - return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); - } - - private (MassEditResult, List) ParseGlobalOpStep(int currentLine, string restOfStages) - { - globalOperationInfo = new MEOperationStage(restOfStages, currentLine, "global", MEGlobalOperation.globalOps); - - var meOpDef = MEGlobalOperation.globalOps.operations[globalOperationInfo.command]; - (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); - ExecParamOperationArguments(currentLine, globalOperationInfo.arguments); - if (argNames.Length != paramArgFuncs.Length) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); - } - - return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); - } - - private (MassEditResult, List) ParseVarOpStep(int currentLine, string restOfStages) - { - varOperationInfo = new MEOperationStage(restOfStages, currentLine, "var", MEValueOperation.valueOps); - - var meOpDef = MEValueOperation.valueOps.operations[varOperationInfo.command]; - (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); - ExecParamOperationArguments(currentLine, varOperationInfo.arguments); - if (argNames.Length != paramArgFuncs.Length) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {varOperationInfo} (line {currentLine})"), null); - } - - return SandboxMassEditExecution(currentLine, partials => ExecVarStage(currentLine)); - } - - private (MassEditResult, List) ParseRowOpStep(int currentLine, string restOfStages) - { - var operationstage = restOfStages.TrimStart().Split(" ", 2); - rowOperationInfo = new MEOperationStage(restOfStages, currentLine, "row", MERowOperation.rowOps); - - var meOpDef = MERowOperation.rowOps.operations[rowOperationInfo.command]; - (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); - ExecParamOperationArguments(currentLine, operationstage.Length > 1 ? operationstage[1] : null); - if (argNames.Length != paramArgFuncs.Length) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {rowOperationInfo} (line {currentLine})"), null); - } - - rowOpOrCellStageFunc = ExecRowOp; - return SandboxMassEditExecution(currentLine, partials => - paramRowStageInfo.command != null ? ExecParamRowStage(currentLine, partials) : ExecParamStage(currentLine, partials)); - } - - private (MassEditResult, List) ParseCellOpStep(int currentLine, string restOfStages) - { - var operationstage = restOfStages.TrimStart().Split(" ", 2); - cellOperationInfo = new MEOperationStage(restOfStages, currentLine, "cell/property", MEValueOperation.valueOps); - - var meOpDef = MEValueOperation.valueOps.operations[cellOperationInfo.command]; - (argNames, genericFunc) = (meOpDef.argNames, meOpDef.function); - ExecParamOperationArguments(currentLine, operationstage.Length > 1 ? operationstage[1] : null); - if (argNames.Length != paramArgFuncs.Length) - { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {cellOperationInfo} (line {currentLine})"), null); - } + if (cellStageInfo.command != null) + rowOpOrCellStageFunc = ExecCellStage; + else + rowOpOrCellStageFunc = ExecRowOp; - return SandboxMassEditExecution(currentLine, partials => - paramRowStageInfo.command != null ? ExecParamRowStage(currentLine, partials) : ExecParamStage(currentLine, partials)); + if (paramRowStageInfo.command != null) + return SandboxMassEditExecution(currentLine, partials => ExecParamRowStage(currentLine, partials)); + else + return SandboxMassEditExecution(currentLine, partials => ExecParamStage(currentLine, partials)); } private void ExecParamOperationArguments(int currentLine, string opargs) From b0ce7b356b97d2151dd005c58bac62a4c2229889 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 21 Feb 2024 19:46:00 +0000 Subject: [PATCH 19/61] Remove unneeded func --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 0bf7e338a..b875410b9 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -278,7 +278,7 @@ private static (MassEditResult, List) ParseFilterStep(int currentL var meOpDef = operation.AllCommands()[target.command]; (argNameTarget, funcTarget) = (meOpDef.argNames, meOpDef.function); - ExecParamOperationArguments(currentLine, target.arguments); + paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argNames.Length, target.arguments); if (argNameTarget.Length != paramArgFuncs.Length) { return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); @@ -300,11 +300,6 @@ private static (MassEditResult, List) ParseFilterStep(int currentL return SandboxMassEditExecution(currentLine, partials => ExecParamStage(currentLine, partials)); } - private void ExecParamOperationArguments(int currentLine, string opargs) - { - paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argNames.Length, opargs); - } - private (MassEditResult, List) SandboxMassEditExecution(int currentLine, Func, MassEditResult> innerFunc) { From ffae14d4380d46afd969c34ccae12a3668cecd9e Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 21:51:56 +0000 Subject: [PATCH 20/61] Remove dual purpose func storage --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index b875410b9..92a96baf8 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -144,9 +144,6 @@ public class MassParamEditRegex private ParamBank bank; private ParamEditorSelectionState context; private Func genericFunc; - - private Func, - MassEditResult> rowOpOrCellStageFunc; private object[] paramArgFuncs; private string[] argNames; @@ -283,21 +280,19 @@ private static (MassEditResult, List) ParseFilterStep(int currentL { return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); } + + //hacks for now if (globalOperationInfo.command != null) return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); if (varOperationInfo.command != null) return SandboxMassEditExecution(currentLine, partials => ExecVarStage(currentLine)); - if (cellStageInfo.command != null) - rowOpOrCellStageFunc = ExecCellStage; - else - rowOpOrCellStageFunc = ExecRowOp; - if (paramRowStageInfo.command != null) return SandboxMassEditExecution(currentLine, partials => ExecParamRowStage(currentLine, partials)); - else + if (paramStageInfo.command != null) return SandboxMassEditExecution(currentLine, partials => ExecParamStage(currentLine, partials)); + throw new MEParseException("No initial stage or op was parsed", currentLine); } private (MassEditResult, List) SandboxMassEditExecution(int currentLine, @@ -371,7 +366,14 @@ private MassEditResult ExecParamRowStage(int currentLine, List par var paramname = source == MassEditRowSource.Selection ? context.GetActiveParam() : ParamBank.ClipboardParam; - MassEditResult res = rowOpOrCellStageFunc(currentLine, rowArgFunc, paramname, row, partialActions); + + MassEditResult res; + if (rowOperationInfo.command != null) + res = ExecRowOp(currentLine, rowArgFunc, paramname, row, partialActions); + else if (cellStageInfo.command != null) + res = ExecCellStage(currentLine, rowArgFunc, paramname, row, partialActions); + else + throw new MEParseException("No row op or cell stage was parsed", currentLine); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -416,7 +418,13 @@ private MassEditResult ExecRowStage(int currentLine, rowEditCount++; object[] rowArgFunc = paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); - MassEditResult res = rowOpOrCellStageFunc(currentLine, rowArgFunc, paramname, row, partialActions); + MassEditResult res; + if (rowOperationInfo.command != null) + res = ExecRowOp(currentLine, rowArgFunc, paramname, row, partialActions); + else if (cellStageInfo.command != null) + res = ExecCellStage(currentLine, rowArgFunc, paramname, row, partialActions); + else + throw new MEParseException("No row op or cell stage was parsed", currentLine); if (res.Type != MassEditResultType.SUCCESS) { return res; From 3b3c48dd3d492d64a9d0919ec7e058f4d553885c Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 22:03:04 +0000 Subject: [PATCH 21/61] make currentLine member of edit instance --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 112 +++++++++++---------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 92a96baf8..e2da73277 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -139,8 +139,9 @@ internal static void AppendParamEditAction(this List actions, Para public class MassParamEditRegex { + /* Line number associated with this edit command, for error reporting. */ + private int _currentLine; - // Do we want these variables? shouldn't they be contained? private ParamBank bank; private ParamEditorSelectionState context; private Func genericFunc; @@ -183,6 +184,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba (MassEditResult result, List actions) = (null, null); MassParamEditRegex currentEditData = new(); + currentEditData._currentLine = currentLine; currentEditData.bank = bank; currentEditData.context = context; @@ -190,42 +192,42 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseOpStep(currentLine, command, "global", MEGlobalOperation.globalOps, ref currentEditData.globalOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + (result, actions) = currentEditData.ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref currentEditData.globalOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = ParseFilterStep(currentLine, command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (currentLine, restOfStages) => + (result, actions) = currentEditData.ParseFilterStep(command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (restOfStages) => { - return currentEditData.ParseOpStep(currentLine, restOfStages, "var", MEValueOperation.valueOps, ref currentEditData.varOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + return currentEditData.ParseOpStep(restOfStages, "var", MEValueOperation.valueOps, ref currentEditData.varOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); } else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = ParseFilterStep(currentLine, command, ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, (currentLine, restOfStages) => + (result, actions) = currentEditData.ParseFilterStep(command, ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, (restOfStages) => { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { - return currentEditData.ParseOpStep(currentLine, restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + return currentEditData.ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } - return ParseFilterStep(currentLine, restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (currentLine, restOfStages) => + return currentEditData.ParseFilterStep(restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (restOfStages) => { - return currentEditData.ParseOpStep(currentLine, restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + return currentEditData.ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); }); } else { - (result, actions) = ParseFilterStep(currentLine, command, ParamSearchEngine.pse, ref currentEditData.paramStageInfo, (currentLine, restOfStages) => + (result, actions) = currentEditData.ParseFilterStep(command, ParamSearchEngine.pse, ref currentEditData.paramStageInfo, (restOfStages) => { - return ParseFilterStep(currentLine, restOfStages, RowSearchEngine.rse, ref currentEditData.rowStageInfo, (currentLine, restOfStages) => + return currentEditData.ParseFilterStep(restOfStages, RowSearchEngine.rse, ref currentEditData.rowStageInfo, (restOfStages) => { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { - return currentEditData.ParseOpStep(currentLine, restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + return currentEditData.ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } - return ParseFilterStep(currentLine, restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (currentLine, restOfStages) => + return currentEditData.ParseFilterStep(restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (restOfStages) => { - return currentEditData.ParseOpStep(currentLine, restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + return currentEditData.ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); }); }); @@ -248,54 +250,54 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } } - private static (MassEditResult, List) ParseFilterStep(int currentLine, string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func)> nextStageFunc) + private (MassEditResult, List) ParseFilterStep(string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func)> nextStageFunc) { var stage = restOfStages.Split(":", 2); string stageName = expectedSearchEngine.NameForHelpTexts(); - target = new MEFilterStage(stage[0], currentLine, stageName, expectedSearchEngine); + target = new MEFilterStage(stage[0], _currentLine, stageName, expectedSearchEngine); if (stage.Length < 2) { var esList = expectedSearchEngine.NextSearchEngines(); var eo = expectedSearchEngine.NextOperation(); if (esList.Any() && eo != null) - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter or {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter or {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {_currentLine})"), null); if (esList.Any()) - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter. Check your colon placement. (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter. Check your colon placement. (line {_currentLine})"), null); if (eo != null) - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {currentLine})"), null); - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find next stage to perform (no suggestions found). Check your colon placement. (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {_currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find next stage to perform (no suggestions found). Check your colon placement. (line {_currentLine})"), null); } - return nextStageFunc(currentLine, stage[1]); + return nextStageFunc(stage[1]); } - private (MassEditResult, List) ParseOpStep(int currentLine, string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target, ref string[] argNameTarget, ref Func funcTarget) + private (MassEditResult, List) ParseOpStep(string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target, ref string[] argNameTarget, ref Func funcTarget) { - target = new MEOperationStage(restOfStages, currentLine, stageName, operation); + target = new MEOperationStage(restOfStages, _currentLine, stageName, operation); var meOpDef = operation.AllCommands()[target.command]; (argNameTarget, funcTarget) = (meOpDef.argNames, meOpDef.function); paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argNames.Length, target.arguments); if (argNameTarget.Length != paramArgFuncs.Length) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {currentLine})"), null); + return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {_currentLine})"), null); } //hacks for now if (globalOperationInfo.command != null) - return SandboxMassEditExecution(currentLine, partials => ExecGlobalOp(currentLine)); + return SandboxMassEditExecution(_currentLine, partials => ExecGlobalOp(_currentLine)); if (varOperationInfo.command != null) - return SandboxMassEditExecution(currentLine, partials => ExecVarStage(currentLine)); + return SandboxMassEditExecution(_currentLine, partials => ExecVarStage(_currentLine)); if (paramRowStageInfo.command != null) - return SandboxMassEditExecution(currentLine, partials => ExecParamRowStage(currentLine, partials)); + return SandboxMassEditExecution(_currentLine, partials => ExecParamRowStage(_currentLine, partials)); if (paramStageInfo.command != null) - return SandboxMassEditExecution(currentLine, partials => ExecParamStage(currentLine, partials)); - throw new MEParseException("No initial stage or op was parsed", currentLine); + return SandboxMassEditExecution(_currentLine, partials => ExecParamStage(_currentLine, partials)); + throw new MEParseException("No initial stage or op was parsed", _currentLine); } - private (MassEditResult, List) SandboxMassEditExecution(int currentLine, + private (MassEditResult, List) SandboxMassEditExecution(int _currentLine, Func, MassEditResult> innerFunc) { List partialActions = new(); @@ -305,31 +307,31 @@ private static (MassEditResult, List) ParseFilterStep(int currentL } catch (Exception e) { - return (new MassEditResult(MassEditResultType.OPERATIONERROR, @$"Error on line {currentLine}" + '\n' + e.GetBaseException().ToString()), null); + return (new MassEditResult(MassEditResultType.OPERATIONERROR, @$"Error on line {_currentLine}" + '\n' + e.GetBaseException().ToString()), null); } return (new MassEditResult(MassEditResultType.SUCCESS, $@"{partialActions.Count} cells affected"), partialActions); } - private MassEditResult ExecGlobalOp(int currentLine) + private MassEditResult ExecGlobalOp(int _currentLine) { var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); var result = (bool)genericFunc(context, globalArgValues); if (!result) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {_currentLine})"); } return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecVarStage(int currentLine) + private MassEditResult ExecVarStage(int _currentLine) { var varArgs = paramArgFuncs; foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) { - MassEditResult res = ExecVarOpStage(currentLine, varName, varArgs); + MassEditResult res = ExecVarOpStage(_currentLine, varName, varArgs); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -339,19 +341,19 @@ private MassEditResult ExecVarStage(int currentLine) return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecVarOpStage(int currentLine, string var, object[] args) + private MassEditResult ExecVarOpStage(int _currentLine, string var, object[] args) { MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); var result = true; // Anything that practicably can go wrong if (!result) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperationInfo} (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperationInfo} (line {_currentLine})"); } return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecParamRowStage(int currentLine, List partialActions) + private MassEditResult ExecParamRowStage(int _currentLine, List partialActions) { Param activeParam = bank.Params[context.GetActiveParam()]; IEnumerable paramArgFunc = @@ -369,11 +371,11 @@ private MassEditResult ExecParamRowStage(int currentLine, List par MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecRowOp(_currentLine, rowArgFunc, paramname, row, partialActions); else if (cellStageInfo.command != null) - res = ExecCellStage(currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecCellStage(_currentLine, rowArgFunc, paramname, row, partialActions); else - throw new MEParseException("No row op or cell stage was parsed", currentLine); + throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -383,7 +385,7 @@ private MassEditResult ExecParamRowStage(int currentLine, List par return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecParamStage(int currentLine, List partialActions) + private MassEditResult ExecParamStage(int _currentLine, List partialActions) { var paramEditCount = -1; var operationForPrint = rowOperationInfo.command != null ? rowOperationInfo : cellOperationInfo; @@ -394,11 +396,11 @@ private MassEditResult ExecParamStage(int currentLine, List partia paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(paramEditCount, p)); if (argNames.Length != paramArgFuncs.Length) { - return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {operationForPrint} (line {currentLine})"); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {operationForPrint} (line {_currentLine})"); } var paramname = b.GetKeyForParam(p); - MassEditResult res = ExecRowStage(currentLine, paramArgFunc, paramname, b, p, partialActions); + MassEditResult res = ExecRowStage(_currentLine, paramArgFunc, paramname, b, p, partialActions); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -408,7 +410,7 @@ private MassEditResult ExecParamStage(int currentLine, List partia return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecRowStage(int currentLine, + private MassEditResult ExecRowStage(int _currentLine, IEnumerable paramArgFunc, string paramname, ParamBank b, Param p, List partialActions) { @@ -420,11 +422,11 @@ private MassEditResult ExecRowStage(int currentLine, paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecRowOp(_currentLine, rowArgFunc, paramname, row, partialActions); else if (cellStageInfo.command != null) - res = ExecCellStage(currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecCellStage(_currentLine, rowArgFunc, paramname, row, partialActions); else - throw new MEParseException("No row op or cell stage was parsed", currentLine); + throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -434,14 +436,14 @@ private MassEditResult ExecRowStage(int currentLine, return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecRowOp(int currentLine, object[] rowArgFunc, string paramname, + private MassEditResult ExecRowOp(int _currentLine, object[] rowArgFunc, string paramname, Param.Row row, List partialActions) { var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); if (p2 == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {_currentLine})"); } if (rs != null) @@ -452,7 +454,7 @@ private MassEditResult ExecRowOp(int currentLine, object[] rowArgFunc, string pa return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecCellStage(int currentLine, object[] rowArgFunc, + private MassEditResult ExecCellStage(int _currentLine, object[] rowArgFunc, string paramname, Param.Row row, List partialActions) { var cellEditCount = -1; @@ -461,7 +463,7 @@ private MassEditResult ExecCellStage(int currentLine, object[] rowArgFunc, { cellEditCount++; var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); - MassEditResult res = ExecCellOp(currentLine, cellArgValues, paramname, row, col, partialActions); + MassEditResult res = ExecCellOp(_currentLine, cellArgValues, paramname, row, col, partialActions); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -471,7 +473,7 @@ private MassEditResult ExecCellStage(int currentLine, object[] rowArgFunc, return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecCellOp(int currentLine, object[] cellArgValues, string paramname, Param.Row row, + private MassEditResult ExecCellOp(int _currentLine, object[] cellArgValues, string paramname, Param.Row row, (PseudoColumn, Param.Column) col, List partialActions) { object res = null; @@ -504,17 +506,17 @@ private MassEditResult ExecCellOp(int currentLine, object[] cellArgValues, strin if (res == null && col.Item1 == PseudoColumn.ID) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on ID ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on ID ({errHelper}) (line {_currentLine})"); } if (res == null && col.Item1 == PseudoColumn.Name) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on Name ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on Name ({errHelper}) (line {_currentLine})"); } if (res == null) { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on field {col.Item2.Def.InternalName} ({errHelper}) (line {currentLine})"); + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on field {col.Item2.Def.InternalName} ({errHelper}) (line {_currentLine})"); } partialActions.AppendParamEditAction(row, col, res); From 6deb6cb1f387a1cc588f7a0869800f69fdc679f3 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 22:11:00 +0000 Subject: [PATCH 22/61] move stuff plus more currentLine --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 121 ++++++++++----------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index e2da73277..abe1b0550 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -286,19 +286,18 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba //hacks for now if (globalOperationInfo.command != null) - return SandboxMassEditExecution(_currentLine, partials => ExecGlobalOp(_currentLine)); + return SandboxMassEditExecution(partials => ExecGlobalOp()); if (varOperationInfo.command != null) - return SandboxMassEditExecution(_currentLine, partials => ExecVarStage(_currentLine)); + return SandboxMassEditExecution(partials => ExecVarStage()); if (paramRowStageInfo.command != null) - return SandboxMassEditExecution(_currentLine, partials => ExecParamRowStage(_currentLine, partials)); + return SandboxMassEditExecution(partials => ExecParamRowStage(partials)); if (paramStageInfo.command != null) - return SandboxMassEditExecution(_currentLine, partials => ExecParamStage(_currentLine, partials)); + return SandboxMassEditExecution(partials => ExecParamStage(partials)); throw new MEParseException("No initial stage or op was parsed", _currentLine); } - private (MassEditResult, List) SandboxMassEditExecution(int _currentLine, - Func, MassEditResult> innerFunc) + private (MassEditResult, List) SandboxMassEditExecution(Func, MassEditResult> innerFunc) { List partialActions = new(); try @@ -314,24 +313,12 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba partialActions); } - private MassEditResult ExecGlobalOp(int _currentLine) - { - var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var result = (bool)genericFunc(context, globalArgValues); - if (!result) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {_currentLine})"); - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecVarStage(int _currentLine) + private MassEditResult ExecVarStage() { var varArgs = paramArgFuncs; foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) { - MassEditResult res = ExecVarOpStage(_currentLine, varName, varArgs); + MassEditResult res = ExecVarOp(varName, varArgs); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -341,19 +328,7 @@ private MassEditResult ExecVarStage(int _currentLine) return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecVarOpStage(int _currentLine, string var, object[] args) - { - MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); - var result = true; // Anything that practicably can go wrong - if (!result) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperationInfo} (line {_currentLine})"); - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecParamRowStage(int _currentLine, List partialActions) + private MassEditResult ExecParamRowStage(List partialActions) { Param activeParam = bank.Params[context.GetActiveParam()]; IEnumerable paramArgFunc = @@ -371,9 +346,9 @@ private MassEditResult ExecParamRowStage(int _currentLine, List pa MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(_currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecRowOp(rowArgFunc, paramname, row, partialActions); else if (cellStageInfo.command != null) - res = ExecCellStage(_currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecCellStage(rowArgFunc, paramname, row, partialActions); else throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) @@ -385,7 +360,7 @@ private MassEditResult ExecParamRowStage(int _currentLine, List pa return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecParamStage(int _currentLine, List partialActions) + private MassEditResult ExecParamStage(List partialActions) { var paramEditCount = -1; var operationForPrint = rowOperationInfo.command != null ? rowOperationInfo : cellOperationInfo; @@ -400,7 +375,7 @@ private MassEditResult ExecParamStage(int _currentLine, List parti } var paramname = b.GetKeyForParam(p); - MassEditResult res = ExecRowStage(_currentLine, paramArgFunc, paramname, b, p, partialActions); + MassEditResult res = ExecRowStage(paramArgFunc, paramname, b, p, partialActions); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -410,8 +385,7 @@ private MassEditResult ExecParamStage(int _currentLine, List parti return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecRowStage(int _currentLine, - IEnumerable paramArgFunc, + private MassEditResult ExecRowStage(IEnumerable paramArgFunc, string paramname, ParamBank b, Param p, List partialActions) { var rowEditCount = -1; @@ -422,9 +396,9 @@ private MassEditResult ExecRowStage(int _currentLine, paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(_currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecRowOp(rowArgFunc, paramname, row, partialActions); else if (cellStageInfo.command != null) - res = ExecCellStage(_currentLine, rowArgFunc, paramname, row, partialActions); + res = ExecCellStage(rowArgFunc, paramname, row, partialActions); else throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) @@ -436,25 +410,7 @@ private MassEditResult ExecRowStage(int _currentLine, return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecRowOp(int _currentLine, object[] rowArgFunc, string paramname, - Param.Row row, List partialActions) - { - var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); - (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); - if (p2 == null) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {_currentLine})"); - } - - if (rs != null) - { - partialActions.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecCellStage(int _currentLine, object[] rowArgFunc, + private MassEditResult ExecCellStage(object[] rowArgFunc, string paramname, Param.Row row, List partialActions) { var cellEditCount = -1; @@ -463,7 +419,7 @@ private MassEditResult ExecCellStage(int _currentLine, object[] rowArgFunc, { cellEditCount++; var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); - MassEditResult res = ExecCellOp(_currentLine, cellArgValues, paramname, row, col, partialActions); + MassEditResult res = ExecCellOp(cellArgValues, paramname, row, col, partialActions); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -473,7 +429,48 @@ private MassEditResult ExecCellStage(int _currentLine, object[] rowArgFunc, return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecCellOp(int _currentLine, object[] cellArgValues, string paramname, Param.Row row, + private MassEditResult ExecGlobalOp() + { + var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); + var result = (bool)genericFunc(context, globalArgValues); + if (!result) + { + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {_currentLine})"); + } + + return new MassEditResult(MassEditResultType.SUCCESS, ""); + } + private MassEditResult ExecVarOp(string var, object[] args) + { + MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); + var result = true; // Anything that practicably can go wrong + if (!result) + { + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperationInfo} (line {_currentLine})"); + } + + return new MassEditResult(MassEditResultType.SUCCESS, ""); + } + + private MassEditResult ExecRowOp(object[] rowArgFunc, string paramname, + Param.Row row, List partialActions) + { + var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); + (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); + if (p2 == null) + { + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {_currentLine})"); + } + + if (rs != null) + { + partialActions.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); + } + + return new MassEditResult(MassEditResultType.SUCCESS, ""); + } + + private MassEditResult ExecCellOp(object[] cellArgValues, string paramname, Param.Row row, (PseudoColumn, Param.Column) col, List partialActions) { object res = null; From 522004a8bfe8e7bd1e0e81802ac4146eda432d3d Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 22:38:21 +0000 Subject: [PATCH 23/61] move stuff + fill in more generics details --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 101 ++++++++++++--------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index abe1b0550..8966b672a 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -313,50 +313,21 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba partialActions); } - private MassEditResult ExecVarStage() - { - var varArgs = paramArgFuncs; - foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) - { - MassEditResult res = ExecVarOp(varName, varArgs); - if (res.Type != MassEditResultType.SUCCESS) - { - return res; - } - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecParamRowStage(List partialActions) + private MassEditResult ExecStage(List partialActions, MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs) { - Param activeParam = bank.Params[context.GetActiveParam()]; - IEnumerable paramArgFunc = - paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(0, activeParam)); // technically invalid for clipboard - var rowEditCount = -1; - foreach ((MassEditRowSource source, Param.Row row) in ParamAndRowSearchEngine.parse.Search(context, - paramRowStageInfo.command, false, false)) - { - rowEditCount++; - object[] rowArgFunc = - paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); - var paramname = source == MassEditRowSource.Selection - ? context.GetActiveParam() - : ParamBank.ClipboardParam; - - MassEditResult res; - if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, paramname, row, partialActions); - else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, paramname, row, partialActions); - else - throw new MEParseException("No row op or cell stage was parsed", _currentLine); + var editCount = -1; + foreach (B currentObject in engine.Search(contextObject, info.command, false, false)) + { + editCount++; + //add context + IEnumerable newArgFuncs = argFuncs.Select((func, i) => func.tryFoldAsFunc(editCount, currentObject)); + //try exec stuff + MassEditResult res = null;//ExecVarOp(varName, varArgs); if (res.Type != MassEditResultType.SUCCESS) { return res; } } - return new MassEditResult(MassEditResultType.SUCCESS, ""); } @@ -369,13 +340,7 @@ private MassEditResult ExecParamStage(List partialActions) paramEditCount++; IEnumerable paramArgFunc = paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(paramEditCount, p)); - if (argNames.Length != paramArgFuncs.Length) - { - return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {operationForPrint} (line {_currentLine})"); - } - - var paramname = b.GetKeyForParam(p); - MassEditResult res = ExecRowStage(paramArgFunc, paramname, b, p, partialActions); + MassEditResult res = ExecRowStage(paramArgFunc, b.GetKeyForParam(p), b, p, partialActions); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -428,6 +393,52 @@ private MassEditResult ExecCellStage(object[] rowArgFunc, return new MassEditResult(MassEditResultType.SUCCESS, ""); } + private MassEditResult ExecVarStage() + { + var varArgs = paramArgFuncs; + foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) + { + MassEditResult res = ExecVarOp(varName, varArgs); + if (res.Type != MassEditResultType.SUCCESS) + { + return res; + } + } + + return new MassEditResult(MassEditResultType.SUCCESS, ""); + } + + private MassEditResult ExecParamRowStage(List partialActions) + { + Param activeParam = bank.Params[context.GetActiveParam()]; + IEnumerable paramArgFunc = + paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(0, activeParam)); // technically invalid for clipboard + var rowEditCount = -1; + foreach ((MassEditRowSource source, Param.Row row) in ParamAndRowSearchEngine.parse.Search(context, + paramRowStageInfo.command, false, false)) + { + rowEditCount++; + object[] rowArgFunc = + paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); + var paramname = source == MassEditRowSource.Selection + ? context.GetActiveParam() + : ParamBank.ClipboardParam; + + MassEditResult res; + if (rowOperationInfo.command != null) + res = ExecRowOp(rowArgFunc, paramname, row, partialActions); + else if (cellStageInfo.command != null) + res = ExecCellStage(rowArgFunc, paramname, row, partialActions); + else + throw new MEParseException("No row op or cell stage was parsed", _currentLine); + if (res.Type != MassEditResultType.SUCCESS) + { + return res; + } + } + + return new MassEditResult(MassEditResultType.SUCCESS, ""); + } private MassEditResult ExecGlobalOp() { From 5b68da66339bb2f86d9f57e447aa943be0065919 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 22:47:58 +0000 Subject: [PATCH 24/61] Move partialActions to current edit object --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 74 +++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 8966b672a..eb5f158ee 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -141,6 +141,8 @@ public class MassParamEditRegex { /* Line number associated with this edit command, for error reporting. */ private int _currentLine; + /* Current actions from execution of this edit command. */ + private List _partialActions = new(); private ParamBank bank; private ParamEditorSelectionState context; @@ -181,7 +183,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba command = command.Substring(0, command.Length - 1); } - (MassEditResult result, List actions) = (null, null); + MassEditResult result = null; MassParamEditRegex currentEditData = new(); currentEditData._currentLine = currentLine; @@ -192,18 +194,18 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref currentEditData.globalOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); + result = currentEditData.ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref currentEditData.globalOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); } else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseFilterStep(command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (restOfStages) => + result = currentEditData.ParseFilterStep(command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (restOfStages) => { return currentEditData.ParseOpStep(restOfStages, "var", MEValueOperation.valueOps, ref currentEditData.varOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); }); } else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - (result, actions) = currentEditData.ParseFilterStep(command, ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, (restOfStages) => + result = currentEditData.ParseFilterStep(command, ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, (restOfStages) => { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { @@ -217,7 +219,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } else { - (result, actions) = currentEditData.ParseFilterStep(command, ParamSearchEngine.pse, ref currentEditData.paramStageInfo, (restOfStages) => + result = currentEditData.ParseFilterStep(command, ParamSearchEngine.pse, ref currentEditData.paramStageInfo, (restOfStages) => { return currentEditData.ParseFilterStep(restOfStages, RowSearchEngine.rse, ref currentEditData.rowStageInfo, (restOfStages) => { @@ -238,6 +240,8 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba return (result, null); } + List actions = currentEditData._partialActions; + changeCount += actions.Count; childManager.ExecuteAction(new CompoundAction(actions)); } @@ -250,7 +254,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } } - private (MassEditResult, List) ParseFilterStep(string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func)> nextStageFunc) + private MassEditResult ParseFilterStep(string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func nextStageFunc) { var stage = restOfStages.Split(":", 2); string stageName = expectedSearchEngine.NameForHelpTexts(); @@ -261,17 +265,17 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba var esList = expectedSearchEngine.NextSearchEngines(); var eo = expectedSearchEngine.NextOperation(); if (esList.Any() && eo != null) - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter or {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {_currentLine})"), null); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter or {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {_currentLine})"); if (esList.Any()) - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter. Check your colon placement. (line {_currentLine})"), null); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {esList.Last().Item1.NameForHelpTexts()} filter. Check your colon placement. (line {_currentLine})"); if (eo != null) - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {_currentLine})"), null); - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find next stage to perform (no suggestions found). Check your colon placement. (line {_currentLine})"), null); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find {eo.NameForHelpTexts()} operation to perform. Check your colon placement. (line {_currentLine})"); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find next stage to perform (no suggestions found). Check your colon placement. (line {_currentLine})"); } return nextStageFunc(stage[1]); } - private (MassEditResult, List) ParseOpStep(string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target, ref string[] argNameTarget, ref Func funcTarget) + private MassEditResult ParseOpStep(string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target, ref string[] argNameTarget, ref Func funcTarget) { target = new MEOperationStage(restOfStages, _currentLine, stageName, operation); @@ -280,37 +284,33 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argNames.Length, target.arguments); if (argNameTarget.Length != paramArgFuncs.Length) { - return (new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {_currentLine})"), null); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {_currentLine})"); } //hacks for now if (globalOperationInfo.command != null) - return SandboxMassEditExecution(partials => ExecGlobalOp()); + return SandboxMassEditExecution(() => ExecGlobalOp()); if (varOperationInfo.command != null) - return SandboxMassEditExecution(partials => ExecVarStage()); + return SandboxMassEditExecution(() => ExecVarStage()); if (paramRowStageInfo.command != null) - return SandboxMassEditExecution(partials => ExecParamRowStage(partials)); + return SandboxMassEditExecution(() => ExecParamRowStage()); if (paramStageInfo.command != null) - return SandboxMassEditExecution(partials => ExecParamStage(partials)); + return SandboxMassEditExecution(() => ExecParamStage()); throw new MEParseException("No initial stage or op was parsed", _currentLine); } - private (MassEditResult, List) SandboxMassEditExecution(Func, MassEditResult> innerFunc) + private MassEditResult SandboxMassEditExecution(Func innerFunc) { - List partialActions = new(); try { - return (innerFunc(partialActions), partialActions); + return innerFunc(); } catch (Exception e) { - return (new MassEditResult(MassEditResultType.OPERATIONERROR, @$"Error on line {_currentLine}" + '\n' + e.GetBaseException().ToString()), null); + return new MassEditResult(MassEditResultType.OPERATIONERROR, @$"Error on line {_currentLine}" + '\n' + e.GetBaseException().ToString()); } - - return (new MassEditResult(MassEditResultType.SUCCESS, $@"{partialActions.Count} cells affected"), - partialActions); } private MassEditResult ExecStage(List partialActions, MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs) @@ -331,7 +331,7 @@ private MassEditResult ExecStage(List partialActions, MEFilt return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecParamStage(List partialActions) + private MassEditResult ExecParamStage() { var paramEditCount = -1; var operationForPrint = rowOperationInfo.command != null ? rowOperationInfo : cellOperationInfo; @@ -340,7 +340,7 @@ private MassEditResult ExecParamStage(List partialActions) paramEditCount++; IEnumerable paramArgFunc = paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(paramEditCount, p)); - MassEditResult res = ExecRowStage(paramArgFunc, b.GetKeyForParam(p), b, p, partialActions); + MassEditResult res = ExecRowStage(paramArgFunc, b.GetKeyForParam(p), b, p); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -351,7 +351,7 @@ private MassEditResult ExecParamStage(List partialActions) } private MassEditResult ExecRowStage(IEnumerable paramArgFunc, - string paramname, ParamBank b, Param p, List partialActions) + string paramname, ParamBank b, Param p) { var rowEditCount = -1; foreach ((string param, Param.Row row) in RowSearchEngine.rse.Search((b, p), rowStageInfo.command, false, false)) @@ -361,9 +361,9 @@ private MassEditResult ExecRowStage(IEnumerable paramArgFunc, paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, paramname, row, partialActions); + res = ExecRowOp(rowArgFunc, paramname, row); else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, paramname, row, partialActions); + res = ExecCellStage(rowArgFunc, paramname, row); else throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) @@ -376,7 +376,7 @@ private MassEditResult ExecRowStage(IEnumerable paramArgFunc, } private MassEditResult ExecCellStage(object[] rowArgFunc, - string paramname, Param.Row row, List partialActions) + string paramname, Param.Row row) { var cellEditCount = -1; foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search((paramname, row), cellStageInfo.command, @@ -384,7 +384,7 @@ private MassEditResult ExecCellStage(object[] rowArgFunc, { cellEditCount++; var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); - MassEditResult res = ExecCellOp(cellArgValues, paramname, row, col, partialActions); + MassEditResult res = ExecCellOp(cellArgValues, paramname, row, col); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -408,7 +408,7 @@ private MassEditResult ExecVarStage() return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecParamRowStage(List partialActions) + private MassEditResult ExecParamRowStage() { Param activeParam = bank.Params[context.GetActiveParam()]; IEnumerable paramArgFunc = @@ -426,9 +426,9 @@ private MassEditResult ExecParamRowStage(List partialActions) MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, paramname, row, partialActions); + res = ExecRowOp(rowArgFunc, paramname, row); else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, paramname, row, partialActions); + res = ExecCellStage(rowArgFunc, paramname, row); else throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) @@ -464,7 +464,7 @@ private MassEditResult ExecVarOp(string var, object[] args) } private MassEditResult ExecRowOp(object[] rowArgFunc, string paramname, - Param.Row row, List partialActions) + Param.Row row) { var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); @@ -475,14 +475,14 @@ private MassEditResult ExecRowOp(object[] rowArgFunc, string paramname, if (rs != null) { - partialActions.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); + _partialActions.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); } return new MassEditResult(MassEditResultType.SUCCESS, ""); } private MassEditResult ExecCellOp(object[] cellArgValues, string paramname, Param.Row row, - (PseudoColumn, Param.Column) col, List partialActions) + (PseudoColumn, Param.Column) col) { object res = null; string errHelper = null; @@ -527,7 +527,7 @@ private MassEditResult ExecCellOp(object[] cellArgValues, string paramname, Para return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on field {col.Item2.Def.InternalName} ({errHelper}) (line {_currentLine})"); } - partialActions.AppendParamEditAction(row, col, res); + _partialActions.AppendParamEditAction(row, col, res); return new MassEditResult(MassEditResultType.SUCCESS, ""); } } From 87188ab3b269b159df7dbedf5a9778330a81cfe4 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 22:58:56 +0000 Subject: [PATCH 25/61] more filling out, joining name+row context objects --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 31 ++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index eb5f158ee..7d889a722 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -313,7 +313,7 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(List partialActions, MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs) + private MassEditResult ExecStage(MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs) { var editCount = -1; foreach (B currentObject in engine.Search(contextObject, info.command, false, false)) @@ -321,8 +321,11 @@ private MassEditResult ExecStage(List partialActions, MEFilt editCount++; //add context IEnumerable newArgFuncs = argFuncs.Select((func, i) => func.tryFoldAsFunc(editCount, currentObject)); - //try exec stuff - MassEditResult res = null;//ExecVarOp(varName, varArgs); + //determine next stage + MEFilterStage nextInfo = new(); + SearchEngine nextStage = null; + //exec it + MassEditResult res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -361,9 +364,9 @@ private MassEditResult ExecRowStage(IEnumerable paramArgFunc, paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, paramname, row); + res = ExecRowOp(rowArgFunc, (paramname, row)); else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, paramname, row); + res = ExecCellStage(rowArgFunc, (paramname, row)); else throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) @@ -376,15 +379,15 @@ private MassEditResult ExecRowStage(IEnumerable paramArgFunc, } private MassEditResult ExecCellStage(object[] rowArgFunc, - string paramname, Param.Row row) + (string, Param.Row) row) { var cellEditCount = -1; - foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search((paramname, row), cellStageInfo.command, + foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search(row, cellStageInfo.command, false, false)) { cellEditCount++; var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); - MassEditResult res = ExecCellOp(cellArgValues, paramname, row, col); + MassEditResult res = ExecCellOp(cellArgValues, row, col); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -426,9 +429,9 @@ private MassEditResult ExecParamRowStage() MassEditResult res; if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, paramname, row); + res = ExecRowOp(rowArgFunc, (paramname, row)); else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, paramname, row); + res = ExecCellStage(rowArgFunc, (paramname, row)); else throw new MEParseException("No row op or cell stage was parsed", _currentLine); if (res.Type != MassEditResultType.SUCCESS) @@ -463,11 +466,10 @@ private MassEditResult ExecVarOp(string var, object[] args) return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecRowOp(object[] rowArgFunc, string paramname, - Param.Row row) + private MassEditResult ExecRowOp(object[] rowArgFunc, (string, Param.Row) row) { var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); - (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc((paramname, row), rowArgValues); + (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc(row, rowArgValues); if (p2 == null) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {_currentLine})"); @@ -481,9 +483,10 @@ private MassEditResult ExecRowOp(object[] rowArgFunc, string paramname, return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecCellOp(object[] cellArgValues, string paramname, Param.Row row, + private MassEditResult ExecCellOp(object[] cellArgValues, (string, Param.Row) nameAndRow, (PseudoColumn, Param.Column) col) { + (string paramName, Param.Row row) = nameAndRow; object res = null; string errHelper = null; try From c45e06072b7508af3ae0aeaf3a7dfebc0ce51ae7 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 23:07:28 +0000 Subject: [PATCH 26/61] shuffling --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 104 +++++++++++---------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 7d889a722..bb11ab7e9 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -78,11 +78,6 @@ internal string[] getArguments(int count) return arguments.Split(':', count); } } -internal class MECommand -{ - List filters = new(); - MEOperationStage operation; -} public static class MassParamEdit { @@ -150,6 +145,10 @@ public class MassParamEditRegex private object[] paramArgFuncs; private string[] argNames; + //TODO use these + List filters = new(); + MEOperationStage operation; + private MEOperationStage globalOperationInfo; private MEOperationStage varOperationInfo; private MEOperationStage rowOperationInfo; @@ -183,57 +182,12 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba command = command.Substring(0, command.Length - 1); } - MassEditResult result = null; - MassParamEditRegex currentEditData = new(); currentEditData._currentLine = currentLine; currentEditData.bank = bank; currentEditData.context = context; - var primaryFilter = command.Split(':', 2)[0].Trim(); - - if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) - { - result = currentEditData.ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref currentEditData.globalOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); - } - else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) - { - result = currentEditData.ParseFilterStep(command, VarSearchEngine.vse, ref currentEditData.varStageInfo, (restOfStages) => - { - return currentEditData.ParseOpStep(restOfStages, "var", MEValueOperation.valueOps, ref currentEditData.varOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); - }); - } - else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) - { - result = currentEditData.ParseFilterStep(command, ParamAndRowSearchEngine.parse, ref currentEditData.paramRowStageInfo, (restOfStages) => - { - if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) - { - return currentEditData.ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); - } - return currentEditData.ParseFilterStep(restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (restOfStages) => - { - return currentEditData.ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); - }); - }); - } - else - { - result = currentEditData.ParseFilterStep(command, ParamSearchEngine.pse, ref currentEditData.paramStageInfo, (restOfStages) => - { - return currentEditData.ParseFilterStep(restOfStages, RowSearchEngine.rse, ref currentEditData.rowStageInfo, (restOfStages) => - { - if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) - { - return currentEditData.ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref currentEditData.rowOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); - } - return currentEditData.ParseFilterStep(restOfStages, CellSearchEngine.cse, ref currentEditData.cellStageInfo, (restOfStages) => - { - return currentEditData.ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref currentEditData.cellOperationInfo, ref currentEditData.argNames, ref currentEditData.genericFunc); - }); - }); - }); - } + MassEditResult result = currentEditData.ParseAndExecCommand(command); if (result.Type != MassEditResultType.SUCCESS) { @@ -254,6 +208,54 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba } } + private MassEditResult ParseAndExecCommand(string command) + { + var primaryFilter = command.Split(':', 2)[0].Trim(); + + if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) + { + return ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref globalOperationInfo, ref argNames, ref genericFunc); + } + else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) + { + return ParseFilterStep(command, VarSearchEngine.vse, ref varStageInfo, (restOfStages) => + { + return ParseOpStep(restOfStages, "var", MEValueOperation.valueOps, ref varOperationInfo, ref argNames, ref genericFunc); + }); + } + else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) + { + return ParseFilterStep(command, ParamAndRowSearchEngine.parse, ref paramRowStageInfo, (restOfStages) => + { + if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) + { + return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo, ref argNames, ref genericFunc); + } + return ParseFilterStep(restOfStages, CellSearchEngine.cse, ref cellStageInfo, (restOfStages) => + { + return ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref cellOperationInfo, ref argNames, ref genericFunc); + }); + }); + } + else + { + return ParseFilterStep(command, ParamSearchEngine.pse, ref paramStageInfo, (restOfStages) => + { + return ParseFilterStep(restOfStages, RowSearchEngine.rse, ref rowStageInfo, (restOfStages) => + { + if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) + { + return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo, ref argNames, ref genericFunc); + } + return ParseFilterStep(restOfStages, CellSearchEngine.cse, ref cellStageInfo, (restOfStages) => + { + return ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref cellOperationInfo, ref argNames, ref genericFunc); + }); + }); + }); + } + } + private MassEditResult ParseFilterStep(string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func nextStageFunc) { var stage = restOfStages.Split(":", 2); From 22c2fb03fb2f21bb8a56a34dbd6d81a8b045695e Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 28 Feb 2024 23:26:19 +0000 Subject: [PATCH 27/61] ExecOp framework start --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index bb11ab7e9..2f029694a 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -293,7 +293,7 @@ private MassEditResult ParseOpStep(string restOfStages, string stageName, METype //hacks for now if (globalOperationInfo.command != null) return SandboxMassEditExecution(() => ExecGlobalOp()); - if (varOperationInfo.command != null) + if (varStageInfo.command != null) return SandboxMassEditExecution(() => ExecVarStage()); if (paramRowStageInfo.command != null) @@ -326,8 +326,16 @@ private MassEditResult ExecStage(MEFilterStage info, SearchEngine en //determine next stage MEFilterStage nextInfo = new(); SearchEngine nextStage = null; + string opStageName = null; + MEOperationStage opInfo = new(); + var contextObjects = new Dictionary(); //TODO move this + contextObjects.Add(typeof(B), currentObject); //exec it - MassEditResult res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs); + MassEditResult res; + if (opInfo.command != null) + res = ExecOp(opInfo, opStageName, newArgFuncs, contextObjects, (x) => x, (x) => true); //TODO fix funcs passed in + else + res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -444,7 +452,16 @@ private MassEditResult ExecParamRowStage() return new MassEditResult(MassEditResultType.SUCCESS, ""); } - + private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, Dictionary contextObjects, Func, object> trueContextObjectGetter, Func resultValidator) + { + var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); + var opResults = genericFunc(trueContextObjectGetter(contextObjects), argValues); + if (!resultValidator(opResults)) + { + return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); + } + return new MassEditResult(MassEditResultType.SUCCESS, ""); + } private MassEditResult ExecGlobalOp() { var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); @@ -458,7 +475,8 @@ private MassEditResult ExecGlobalOp() } private MassEditResult ExecVarOp(string var, object[] args) { - MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); + var varArgValues = args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); + MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], varArgValues); var result = true; // Anything that practicably can go wrong if (!result) { From 6234290049b6bf464130c5c3246c5e6993e74e6b Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Mon, 4 Mar 2024 03:37:29 +0000 Subject: [PATCH 28/61] extending operationtypes to have funcs on how to use and apply results --- .../Editor/MassEdit/EditOperation.cs | 83 ++++++++++++++++++- src/StudioCore/Editor/MassEdit/MassEdit.cs | 48 +++++------ 2 files changed, 102 insertions(+), 29 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 1877f9173..cd4554388 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -1,11 +1,13 @@ #nullable enable using Andre.Formats; +using Microsoft.AspNetCore.Razor.TagHelpers; using StudioCore.Editor; using StudioCore.ParamEditor; using System; using System.Collections.Generic; using System.Diagnostics.Eventing.Reader; using System.Linq; +using System.Reflection.Metadata.Ecma335; using System.Text.RegularExpressions; namespace StudioCore.Editor.MassEdit; @@ -41,8 +43,11 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); + internal abstract object getTrueValue(Dictionary contextObjects); + internal abstract bool validateResult(object res); + internal abstract void useResult(List actionList, Dictionary contextObjects, object res); } -internal class MEOperation : METypelessOperation +internal abstract class MEOperation : METypelessOperation { internal Dictionary operations = new(); internal string name = "[Unnamed operation type]"; @@ -118,6 +123,21 @@ internal override void Setup() return true; }, () => CFG.Current.Param_AdvancedMassedit)); } + + internal override object getTrueValue(Dictionary contextObjects) + { + return true; //Global op technically has no context / uses the dummy context of boolean + } + + internal override bool validateResult(object res) + { + return true; + } + + internal override void useResult(List actionList, Dictionary contextObjects, object res) + { + return; //Global ops, for now, don't use actions and simply execute effects themselves + } } internal class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> @@ -208,12 +228,31 @@ internal override void Setup() } )); } + + internal override object getTrueValue(Dictionary contextObjects) + { + return contextObjects[typeof((string, Param.Row))]; + } + + internal override bool validateResult(object res) + { + if (res.GetType() != typeof((Param, Param.Row))) + return false; + (Param, Param.Row) r2 = ((Param, Param.Row))res; + if (r2.Item1 == null) + return false; + return true; + } + + internal override void useResult(List actionList, Dictionary contextObjects, object res) + { + (Param p2, Param.Row rs) = ((Param, Param.Row))res; + actionList.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); + } } -internal class MEValueOperation : MEOperation +internal abstract class MEValueOperation : MEOperation { - public static MEValueOperation valueOps = new(); - internal override void Setup() { name = "value"; @@ -275,6 +314,42 @@ internal override void Setup() newCmd(new[] { "number" }, "Returns the smaller of the current value and number", (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit)); } + + internal override bool validateResult(object res) + { + if (res == null) + return false; + return true; + } +} +internal class MECellOperation : MEValueOperation +{ + public static MECellOperation cellOps = new(); + internal override object getTrueValue(Dictionary contextObjects) + { + (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; + (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))contextObjects[typeof((PseudoColumn, Param.Column))]; + return row.Get(col); + } + internal override void useResult(List actionList, Dictionary contextObjects, object res) + { + (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; + (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))contextObjects[typeof((PseudoColumn, Param.Column))]; + actionList.AppendParamEditAction(row, col, res); + } +} +internal class MEVarOperation : MEValueOperation +{ + public static MEVarOperation varOps = new(); + internal override object getTrueValue(Dictionary contextObjects) + { + return MassParamEdit.massEditVars[(string)contextObjects[typeof(string)]]; + } + + internal override void useResult(List actionList, Dictionary contextObjects, object res) + { + MassParamEdit.massEditVars[(string)contextObjects[typeof(string)]] = res; + } } internal class MEOperationArgument diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 2f029694a..e3e836d97 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -141,9 +141,8 @@ public class MassParamEditRegex private ParamBank bank; private ParamEditorSelectionState context; - private Func genericFunc; private object[] paramArgFuncs; - private string[] argNames; + METypelessOperationDef parsedOp; //TODO use these List filters = new(); @@ -214,13 +213,13 @@ private MassEditResult ParseAndExecCommand(string command) if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { - return ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref globalOperationInfo, ref argNames, ref genericFunc); + return ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref globalOperationInfo); } else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) { return ParseFilterStep(command, VarSearchEngine.vse, ref varStageInfo, (restOfStages) => { - return ParseOpStep(restOfStages, "var", MEValueOperation.valueOps, ref varOperationInfo, ref argNames, ref genericFunc); + return ParseOpStep(restOfStages, "var", MEVarOperation.varOps, ref varOperationInfo); }); } else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) @@ -229,11 +228,11 @@ private MassEditResult ParseAndExecCommand(string command) { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { - return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo, ref argNames, ref genericFunc); + return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo); } return ParseFilterStep(restOfStages, CellSearchEngine.cse, ref cellStageInfo, (restOfStages) => { - return ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref cellOperationInfo, ref argNames, ref genericFunc); + return ParseOpStep(restOfStages, "cell/property", MECellOperation.cellOps, ref cellOperationInfo); }); }); } @@ -245,11 +244,11 @@ private MassEditResult ParseAndExecCommand(string command) { if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) { - return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo, ref argNames, ref genericFunc); + return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo); } return ParseFilterStep(restOfStages, CellSearchEngine.cse, ref cellStageInfo, (restOfStages) => { - return ParseOpStep(restOfStages, "cell/property", MEValueOperation.valueOps, ref cellOperationInfo, ref argNames, ref genericFunc); + return ParseOpStep(restOfStages, "cell/property", MECellOperation.cellOps, ref cellOperationInfo); }); }); }); @@ -277,14 +276,13 @@ private MassEditResult ParseFilterStep(string restOfStages, TypelessSearchEngine return nextStageFunc(stage[1]); } - private MassEditResult ParseOpStep(string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target, ref string[] argNameTarget, ref Func funcTarget) + private MassEditResult ParseOpStep(string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target) { target = new MEOperationStage(restOfStages, _currentLine, stageName, operation); - var meOpDef = operation.AllCommands()[target.command]; - (argNameTarget, funcTarget) = (meOpDef.argNames, meOpDef.function); - paramArgFuncs = MEOperationArgument.arg.getContextualArguments(argNames.Length, target.arguments); - if (argNameTarget.Length != paramArgFuncs.Length) + parsedOp = operation.AllCommands()[target.command]; + paramArgFuncs = MEOperationArgument.arg.getContextualArguments(parsedOp.argNames.Length, target.arguments); + if (parsedOp.argNames.Length != paramArgFuncs.Length) { return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {_currentLine})"); } @@ -315,7 +313,7 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs) + private MassEditResult ExecStage(MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs, Dictionary contextObjects) { var editCount = -1; foreach (B currentObject in engine.Search(contextObject, info.command, false, false)) @@ -328,14 +326,13 @@ private MassEditResult ExecStage(MEFilterStage info, SearchEngine en SearchEngine nextStage = null; string opStageName = null; MEOperationStage opInfo = new(); - var contextObjects = new Dictionary(); //TODO move this - contextObjects.Add(typeof(B), currentObject); + contextObjects[typeof(B)] = currentObject; //exec it MassEditResult res; if (opInfo.command != null) - res = ExecOp(opInfo, opStageName, newArgFuncs, contextObjects, (x) => x, (x) => true); //TODO fix funcs passed in + res = ExecOp(opInfo, opStageName, newArgFuncs, contextObjects); else - res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs); + res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs, contextObjects); if (res.Type != MassEditResultType.SUCCESS) { return res; @@ -452,20 +449,21 @@ private MassEditResult ExecParamRowStage() return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, Dictionary contextObjects, Func, object> trueContextObjectGetter, Func resultValidator) + private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, Dictionary contextObjects, METypelessOperation opType) //TODO use global op { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var opResults = genericFunc(trueContextObjectGetter(contextObjects), argValues); - if (!resultValidator(opResults)) + var opResults = parsedOp.function(opType.getTrueValue(contextObjects), argValues); + if (!opType.validateResult(opResults)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); } + _partialActions.Add(null);//TODO using opType return new MassEditResult(MassEditResultType.SUCCESS, ""); } private MassEditResult ExecGlobalOp() { var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var result = (bool)genericFunc(context, globalArgValues); + var result = (bool)parsedOp.function(context, globalArgValues); if (!result) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {_currentLine})"); @@ -476,7 +474,7 @@ private MassEditResult ExecGlobalOp() private MassEditResult ExecVarOp(string var, object[] args) { var varArgValues = args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); - MassParamEdit.massEditVars[var] = genericFunc(MassParamEdit.massEditVars[var], varArgValues); + MassParamEdit.massEditVars[var] = parsedOp.function(MassParamEdit.massEditVars[var], varArgValues); var result = true; // Anything that practicably can go wrong if (!result) { @@ -489,7 +487,7 @@ private MassEditResult ExecVarOp(string var, object[] args) private MassEditResult ExecRowOp(object[] rowArgFunc, (string, Param.Row) row) { var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); - (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))genericFunc(row, rowArgValues); + (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))parsedOp.function(row, rowArgValues); if (p2 == null) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {_currentLine})"); @@ -511,7 +509,7 @@ private MassEditResult ExecCellOp(object[] cellArgValues, (string, Param.Row) na string errHelper = null; try { - res = genericFunc(row.Get(col), cellArgValues.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); + res = parsedOp.function(row.Get(col), cellArgValues.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); } catch (FormatException e) { From 1e10b59a74f982983f5ec2d428c4f99f61211805 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 6 Mar 2024 01:23:39 +0000 Subject: [PATCH 29/61] More typefree filling out --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 10 +++++----- src/StudioCore/Editor/MassEdit/MassEdit.cs | 10 +++++----- .../Editor/MassEdit/SearchEngine.cs | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index fb9de9ec2..cc3a36278 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -188,7 +188,7 @@ internal class AutoFill private static string[] _autoFillArgsGop = Enumerable.Repeat("", MEGlobalOperation.globalOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); private static string[] _autoFillArgsRop = Enumerable.Repeat("", MERowOperation.rowOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); - private static string[] _autoFillArgsCop = Enumerable.Repeat("", MEValueOperation.valueOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); + private static string[] _autoFillArgsCop = Enumerable.Repeat("", MECellOperation.cellOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length)).ToArray(); @@ -267,7 +267,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(MEValueOperation.valueOps, ref _autoFillArgsCop, ";", null); + return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); @@ -307,7 +307,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(MEValueOperation.valueOps, ref _autoFillArgsCop, ";", + return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); }); string res2 = null; @@ -350,7 +350,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select value operation..."); - return MassEditAutoFillForOperation(MEValueOperation.valueOps, ref _autoFillArgsCop, ";", + return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); }); } @@ -380,7 +380,7 @@ public static string MassEditCompleteAutoFill() public static string MassEditOpAutoFill() { - return MassEditAutoFillForOperation(MEValueOperation.valueOps, ref _autoFillArgsCop, ";", null); + return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); } private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index e3e836d97..1fb06f52f 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -313,24 +313,24 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(MEFilterStage info, SearchEngine engine, A contextObject, IEnumerable argFuncs, Dictionary contextObjects) + private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, object contextObject, IEnumerable argFuncs, Dictionary contextObjects) { var editCount = -1; - foreach (B currentObject in engine.Search(contextObject, info.command, false, false)) + foreach (object currentObject in engine.SearchNoType(contextObject, info.command, false, false)) { editCount++; //add context IEnumerable newArgFuncs = argFuncs.Select((func, i) => func.tryFoldAsFunc(editCount, currentObject)); //determine next stage MEFilterStage nextInfo = new(); - SearchEngine nextStage = null; + TypelessSearchEngine nextStage = null; string opStageName = null; MEOperationStage opInfo = new(); - contextObjects[typeof(B)] = currentObject; + contextObjects[engine.getElementType()] = currentObject; //exec it MassEditResult res; if (opInfo.command != null) - res = ExecOp(opInfo, opStageName, newArgFuncs, contextObjects); + res = ExecOp(opInfo, opStageName, newArgFuncs, contextObjects, METypelessOperation.GetEditOperation(engine.getElementType())); else res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs, contextObjects); if (res.Type != MassEditResultType.SUCCESS) diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 13b6444ef..0896b41dc 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -1,4 +1,5 @@ using Andre.Formats; +using Org.BouncyCastle.Tls; using SoulsFormats; using StudioCore.ParamEditor; using StudioCore.TextEditor; @@ -31,6 +32,9 @@ internal static void AddSearchEngine(SearchEngine engine) internal abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); internal abstract METypelessOperation NextOperation(); internal abstract string NameForHelpTexts(); + internal abstract Type getContainerType(); + internal abstract Type getElementType(); + public abstract List SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); } internal class SearchEngine : TypelessSearchEngine { @@ -134,7 +138,10 @@ internal override List AvailableCommandsForHelpText() return options; } - + public override List SearchNoType(object container, string command, bool lenient, bool failureAllOrNone) + { + return Search((A)container, command, lenient, failureAllOrNone) as List; + } public List Search(A param, string command, bool lenient, bool failureAllOrNone) { return Search(param, unpacker(param), command, lenient, failureAllOrNone); @@ -226,6 +233,16 @@ internal override string NameForHelpTexts() { return name; } + + internal override Type getContainerType() + { + return typeof(A); + } + + internal override Type getElementType() + { + return typeof(B); + } } internal class SearchEngineCommand From c8f34e5cb943296ba458635e78abc8a87f4563ed Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 6 Mar 2024 01:43:44 +0000 Subject: [PATCH 30/61] Move to execstage, start fighting types/sizes in searchengine --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 3 ++- src/StudioCore/Editor/MassEdit/SearchEngine.cs | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 1fb06f52f..5a3664bde 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -297,7 +297,8 @@ private MassEditResult ParseOpStep(string restOfStages, string stageName, METype if (paramRowStageInfo.command != null) return SandboxMassEditExecution(() => ExecParamRowStage()); if (paramStageInfo.command != null) - return SandboxMassEditExecution(() => ExecParamStage()); + return SandboxMassEditExecution(() => ExecStage(paramStageInfo, ParamSearchEngine.pse, true, paramArgFuncs, new Dictionary() { { typeof(bool), true } })); + //return SandboxMassEditExecution(() => ExecParamStage()); throw new MEParseException("No initial stage or op was parsed", _currentLine); } diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 0896b41dc..3de3ec9b4 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -34,7 +34,7 @@ internal static void AddSearchEngine(SearchEngine engine) internal abstract string NameForHelpTexts(); internal abstract Type getContainerType(); internal abstract Type getElementType(); - public abstract List SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); + public abstract IEnumerable SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); } internal class SearchEngine : TypelessSearchEngine { @@ -138,9 +138,10 @@ internal override List AvailableCommandsForHelpText() return options; } - public override List SearchNoType(object container, string command, bool lenient, bool failureAllOrNone) + public override IEnumerable SearchNoType(object container, string command, bool lenient, bool failureAllOrNone) { - return Search((A)container, command, lenient, failureAllOrNone) as List; + List res = Search((A)container, command, lenient, failureAllOrNone); + return (IEnumerable)res; } public List Search(A param, string command, bool lenient, bool failureAllOrNone) { From 945c1dd0d1f735ab91598ea4d772980252aae917 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 6 Mar 2024 02:14:35 +0000 Subject: [PATCH 31/61] Messing things up with reference type tuples --- src/StudioCore/Editor/EditorDecorations.cs | 2 +- .../Editor/MassEdit/EditOperation.cs | 12 ++-- src/StudioCore/Editor/MassEdit/MassEdit.cs | 4 +- .../Editor/MassEdit/SearchEngine.cs | 66 ++++++++++--------- src/StudioCore/ParamEditor/ParamEditorView.cs | 2 +- src/StudioCore/ParamEditor/ParamRowEditor.cs | 2 +- 6 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index 449ba0159..3e1a651e7 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -556,7 +556,7 @@ public static bool PropertyRowRefsContextItems(ParamBank bank, List re ParamMetaData meta = ParamMetaData.Get(bank.Params[rt].AppliedParamdef); var maxResultsPerRefType = 15 / reftypes.Count; - List<(string, Param.Row)> rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), + List> rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), _refContextCurrentAutoComplete, true, true); foreach ((string param, Param.Row r) in rows) { diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index cd4554388..b4cdcfebb 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -578,7 +578,7 @@ private void Setup() throw new MEOperationException($@"Cannot average field {field[0]}"); } - List<(string, Param.Row)>? rows = + List>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); @@ -594,7 +594,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List<(string, Param.Row)>? rows = + List>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); @@ -610,7 +610,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List<(string, Param.Row)>? rows = + List>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; @@ -626,7 +626,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List<(string, Param.Row)>? rows = + List>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); @@ -641,7 +641,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List<(string, Param.Row)>? rows = + List>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); return max.ToParamEditorString(); @@ -688,7 +688,7 @@ private void Setup() paramFieldRowSelector => { Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; - List<(string, Param.Row)> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), + List> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 5a3664bde..4848d265e 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -390,12 +390,12 @@ private MassEditResult ExecCellStage(object[] rowArgFunc, (string, Param.Row) row) { var cellEditCount = -1; - foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search(row, cellStageInfo.command, + foreach (Tuple col in CellSearchEngine.cse.Search(row, cellStageInfo.command, false, false)) { cellEditCount++; var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); - MassEditResult res = ExecCellOp(cellArgValues, row, col); + MassEditResult res = ExecCellOp(cellArgValues, row, (col.Item1, col.Item2)); if (res.Type != MassEditResultType.SUCCESS) { return res; diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 3de3ec9b4..dade35d49 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -1,4 +1,5 @@ using Andre.Formats; +using Microsoft.Toolkit.HighPerformance; using Org.BouncyCastle.Tls; using SoulsFormats; using StudioCore.ParamEditor; @@ -6,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text.RegularExpressions; namespace StudioCore.Editor.MassEdit; @@ -16,7 +18,7 @@ namespace StudioCore.Editor.MassEdit; internal abstract class TypelessSearchEngine { private static Dictionary> searchEngines = new(); - internal static void AddSearchEngine(SearchEngine engine) + internal static void AddSearchEngine(SearchEngine engine) where O : class { if (!searchEngines.ContainsKey(typeof(I))) searchEngines.Add(typeof(I), new()); @@ -36,9 +38,8 @@ internal static void AddSearchEngine(SearchEngine engine) internal abstract Type getElementType(); public abstract IEnumerable SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); } -internal class SearchEngine : TypelessSearchEngine +internal class SearchEngine : TypelessSearchEngine where B : class { - internal SearchEngineCommand defaultFilter; internal Dictionary> filterList = new(); @@ -266,7 +267,7 @@ internal SearchEngineCommand(string[] args, string wiki, Func : SearchEngine +internal class MultiStageSearchEngine : SearchEngine where B : class where D : class { internal Func contextGetterForMultiStage; internal Func resultRetrieverForMultiStage; @@ -291,10 +292,10 @@ public override List Search(A context, List sourceSet, string command, boo } } -internal class ParamAndRowSearchEngine : MultiStageSearchEngine +internal class ParamAndRowSearchEngine : MultiStageSearchEngine, (ParamBank, Param), Tuple> { - public static SearchEngine parse = + public static SearchEngine> parse = new ParamAndRowSearchEngine(); internal override void Setup() @@ -302,9 +303,9 @@ internal override void Setup() name = "paramrow"; unpacker = selection => { - List<(MassEditRowSource, Param.Row)> list = new(); - list.AddRange(selection.GetSelectedRows().Select((x, i) => (MassEditRowSource.Selection, x))); - list.AddRange(ParamBank.ClipboardRows.Select((x, i) => (MassEditRowSource.Clipboard, x))); + List> list = new(); + list.AddRange(selection.GetSelectedRows().Select((x, i) => Tuple.Create(MassEditRowSource.Selection, x))); + list.AddRange(ParamBank.ClipboardRows.Select((x, i) => Tuple.Create(MassEditRowSource.Clipboard, x))); return list; }; filterList.Add("selection", @@ -319,9 +320,9 @@ internal override void Setup() exampleItem.Item1 == MassEditRowSource.Selection ? state.GetActiveParam() : ParamBank.ClipboardParam]); - sourceListGetterForMultiStage = row => (null, row.Item2); + sourceListGetterForMultiStage = row => Tuple.Create(null, row.Item2); searchEngineForMultiStage = RowSearchEngine.rse; - resultRetrieverForMultiStage = (row, exampleItem) => (exampleItem.Item1, row.Item2); + resultRetrieverForMultiStage = (row, exampleItem) => Tuple.Create(exampleItem.Item1, row.Item2); } } @@ -331,7 +332,7 @@ internal enum MassEditRowSource Clipboard } -internal class ParamSearchEngine : SearchEngine +internal class ParamSearchEngine : SearchEngine> { public static ParamSearchEngine pse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -346,7 +347,7 @@ internal override void Setup() name = "param"; unpacker = dummy => ParamBank.AuxBanks.Select((aux, i) => aux.Value.Params.Select((x, i) => (aux.Value, x.Value))) - .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).ToList(); + .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).Select((x, i) => Tuple.Create(x.bank, x.x)).ToList(); filterList.Add("modified", newCmd(new string[0], "Selects params where any rows do not match the vanilla version, or where any are added. Ignores row names", noArgs(noContext(param => @@ -397,7 +398,7 @@ internal override void Setup() } } -internal class RowSearchEngine : SearchEngine<(ParamBank, Param), (string, Param.Row)> +internal class RowSearchEngine : SearchEngine<(ParamBank, Param), Tuple> { public static RowSearchEngine rse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -413,7 +414,7 @@ internal override void Setup() unpacker = param => { string name = param.Item1.GetKeyForParam(param.Item2); - return param.Item2.Rows.Select((x, i) => (name, x)).ToList(); + return param.Item2.Rows.Select((x, i) => Tuple.Create(name, x)).ToList(); }; filterList.Add("modified", newCmd(new string[0], "Selects rows which do not match the vanilla version, or are added. Ignores row name", noArgs(context => @@ -565,12 +566,13 @@ internal override void Setup() { var paramName = context.Item1.GetKeyForParam(context.Item2); IReadOnlyList cols = context.Item2.Columns; - (PseudoColumn, Param.Column) testCol = context.Item2.GetCol(field); + var vtup = context.Item2.GetCol(field); + Tuple testCol = Tuple.Create(vtup.Item1, vtup.Item2); return row => { (string paramName, Param.Row row) cseSearchContext = (paramName, row.Item2); - List<(PseudoColumn, Param.Column)> res = CellSearchEngine.cse.Search(cseSearchContext, - new List<(PseudoColumn, Param.Column)> { testCol }, args[1], lenient, false); + List> res = CellSearchEngine.cse.Search(cseSearchContext, + new List> { testCol }, args[1], lenient, false); return res.Contains(testCol); }; }; @@ -765,7 +767,7 @@ internal override void Setup() throw new Exception("Could not find param " + otherParam); } - List<(string, Param.Row)> rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, + List> rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, lenient, false); (PseudoColumn, Param.Column) otherFieldReal = otherParamReal.GetCol(otherField); if (!otherFieldReal.IsColumnValid()) @@ -862,7 +864,7 @@ internal override void Setup() } } -internal class CellSearchEngine : SearchEngine<(string, Param.Row), (PseudoColumn, Param.Column)> +internal class CellSearchEngine : SearchEngine<(string, Param.Row), Tuple> { public static CellSearchEngine cse = new(); @@ -871,10 +873,10 @@ internal override void Setup() name = "cell/property"; unpacker = row => { - List<(PseudoColumn, Param.Column)> list = new(); - list.Add((PseudoColumn.ID, null)); - list.Add((PseudoColumn.Name, null)); - list.AddRange(row.Item2.Columns.Select((cell, i) => (PseudoColumn.None, cell))); + List> list = new(); + list.Add(Tuple.Create(PseudoColumn.ID, null)); + list.Add(Tuple.Create(PseudoColumn.Name, null)); + list.AddRange(row.Item2.Columns.Select((cell, i) => Tuple.Create(PseudoColumn.None, cell))); return list; }; defaultFilter = newCmd(new[] { "field internalName (regex)" }, @@ -935,10 +937,10 @@ internal override void Setup() return col => { - (PseudoColumn, Param.Column) vcol = col.GetAs(vParam); - var valA = row.Item2.Get(col); + (PseudoColumn, Param.Column) vcol = (col.Item1, col.Item2).GetAs(vParam); + var valA = row.Item2.Get((col.Item1, col.Item2)); var valB = r.Get(vcol); - return ParamUtils.IsValueDiff(ref valA, ref valB, col.GetColumnType()); + return ParamUtils.IsValueDiff(ref valA, ref valB, (col.Item1, col.Item2).GetColumnType()); }; })); filterList.Add("auxmodified", newCmd(new[] { "parambank name" }, @@ -984,11 +986,11 @@ internal override void Setup() return col => { - (PseudoColumn, Param.Column) auxcol = col.GetAs(auxParam); - (PseudoColumn, Param.Column) vcol = col.GetAs(vParam); + (PseudoColumn, Param.Column) auxcol = (col.Item1, col.Item2).GetAs(auxParam); + (PseudoColumn, Param.Column) vcol = (col.Item1, col.Item2).GetAs(vParam); var valA = r.Get(auxcol); var valB = r2.Get(vcol); - return ParamUtils.IsValueDiff(ref valA, ref valB, col.GetColumnType()); + return ParamUtils.IsValueDiff(ref valA, ref valB, (col.Item1, col.Item2).GetColumnType()); }; }; }, () => ParamBank.AuxBanks.Count > 0)); @@ -998,7 +1000,7 @@ internal override void Setup() { Regex r = new('^' + args[0] + '$', lenient ? RegexOptions.IgnoreCase : RegexOptions.None); //Leniency rules break from the norm - return row => col => r.IsMatch(col.GetColumnSfType()); + return row => col => r.IsMatch((col.Item1, col.Item2).GetColumnSfType()); }, () => CFG.Current.Param_AdvancedMassedit)); } } diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index b984648b4..7916f6c5b 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -160,7 +160,7 @@ private void ParamView_ParamList_Main(bool doFocus, float scale, float scrollTo) { List paramKeyList = UICache.GetCached(_paramEditor, _viewIndex, () => { - List<(ParamBank, Param)> list = + List> list = ParamSearchEngine.pse.Search(true, _selection.currentParamSearchString, true, true); List keyList = list.Where(param => param.Item1 == ParamBank.PrimaryBank) .Select(param => ParamBank.PrimaryBank.GetKeyForParam(param.Item2)).ToList(); diff --git a/src/StudioCore/ParamEditor/ParamRowEditor.cs b/src/StudioCore/ParamEditor/ParamRowEditor.cs index 805c55482..c1ec3671f 100644 --- a/src/StudioCore/ParamEditor/ParamRowEditor.cs +++ b/src/StudioCore/ParamEditor/ParamRowEditor.cs @@ -206,7 +206,7 @@ public void PropEditorParamRow(ParamBank bank, Param.Row row, Param.Row vrow, Li var search = propSearchString; List<(PseudoColumn, Param.Column)> cols = UICache.GetCached(_paramEditor, row, "fieldFilter", - () => CellSearchEngine.cse.Search((activeParam, row), search, true, true)); + () => CellSearchEngine.cse.Search((activeParam, row), search, true, true).Select(x => (x.Item1, x.Item2)).ToList()); List<(PseudoColumn, Param.Column)> vcols = UICache.GetCached(_paramEditor, vrow, "vFieldFilter", () => cols.Select((x, i) => x.GetAs(ParamBank.VanillaBank.GetParamFromName(activeParam))).ToList()); List> auxCols = UICache.GetCached(_paramEditor, auxRows, From 15311dc15855b4d27e105254d92fa87955c2e05a Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Mon, 18 Mar 2024 00:32:11 +0000 Subject: [PATCH 32/61] un-Tuple and encode the tuple into searchengine because Tuple was silly. --- src/StudioCore/Editor/EditorDecorations.cs | 2 +- .../Editor/MassEdit/EditOperation.cs | 12 +- src/StudioCore/Editor/MassEdit/MassEdit.cs | 4 +- .../Editor/MassEdit/SearchEngine.cs | 124 +++++++++--------- src/StudioCore/ParamEditor/ParamEditorView.cs | 2 +- 5 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index 3e1a651e7..449ba0159 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -556,7 +556,7 @@ public static bool PropertyRowRefsContextItems(ParamBank bank, List re ParamMetaData meta = ParamMetaData.Get(bank.Params[rt].AppliedParamdef); var maxResultsPerRefType = 15 / reftypes.Count; - List> rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), + List<(string, Param.Row)> rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), _refContextCurrentAutoComplete, true, true); foreach ((string param, Param.Row r) in rows) { diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index b4cdcfebb..cd4554388 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -578,7 +578,7 @@ private void Setup() throw new MEOperationException($@"Cannot average field {field[0]}"); } - List>? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); @@ -594,7 +594,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List>? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); @@ -610,7 +610,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List>? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; @@ -626,7 +626,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List>? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); @@ -641,7 +641,7 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - List>? rows = + List<(string, Param.Row)>? rows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); return max.ToParamEditorString(); @@ -688,7 +688,7 @@ private void Setup() paramFieldRowSelector => { Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; - List> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), + List<(string, Param.Row)> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 4848d265e..5e629659c 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -390,7 +390,7 @@ private MassEditResult ExecCellStage(object[] rowArgFunc, (string, Param.Row) row) { var cellEditCount = -1; - foreach (Tuple col in CellSearchEngine.cse.Search(row, cellStageInfo.command, + foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search(row, cellStageInfo.command, false, false)) { cellEditCount++; @@ -409,7 +409,7 @@ private MassEditResult ExecVarStage() var varArgs = paramArgFuncs; foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) { - MassEditResult res = ExecVarOp(varName, varArgs); + MassEditResult res = ExecVarOp(varName.Item2, varArgs); if (res.Type != MassEditResultType.SUCCESS) { return res; diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index dade35d49..f7b19a9f6 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -18,7 +18,7 @@ namespace StudioCore.Editor.MassEdit; internal abstract class TypelessSearchEngine { private static Dictionary> searchEngines = new(); - internal static void AddSearchEngine(SearchEngine engine) where O : class + internal static void AddSearchEngine(SearchEngine engine) { if (!searchEngines.ContainsKey(typeof(I))) searchEngines.Add(typeof(I), new()); @@ -36,14 +36,14 @@ internal static void AddSearchEngine(SearchEngine engine) where O : internal abstract string NameForHelpTexts(); internal abstract Type getContainerType(); internal abstract Type getElementType(); - public abstract IEnumerable SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); + public abstract IEnumerable<(object, object)> SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); } -internal class SearchEngine : TypelessSearchEngine where B : class +internal class SearchEngine : TypelessSearchEngine { - internal SearchEngineCommand defaultFilter; + internal SearchEngineCommand defaultFilter; - internal Dictionary> filterList = new(); - internal Func> unpacker; + internal Dictionary> filterList = new(); + internal Func> unpacker; internal string name = "[unnamed search engine]"; internal SearchEngine() @@ -57,12 +57,12 @@ protected void addExistsFilter() filterList.Add("exists", newCmd(new string[0], "Selects all elements", noArgs(noContext(B => true)))); } - protected Func>> noArgs(Func> func) + protected Func>> noArgs(Func> func) { return (args, lenient) => func; } - protected Func> noContext(Func func) + protected Func> noContext(Func<(O, F), bool> func) { return context => func; } @@ -71,10 +71,10 @@ internal virtual void Setup() { } - internal SearchEngineCommand newCmd(string[] args, string wiki, - Func>> func, Func shouldShow = null) + internal SearchEngineCommand newCmd(string[] args, string wiki, + Func>> func, Func shouldShow = null) { - return new SearchEngineCommand(args, wiki, func, shouldShow); + return new SearchEngineCommand(args, wiki, func, shouldShow); } internal bool HandlesCommand(string command) @@ -92,7 +92,7 @@ internal override List AvailableCommandsForHelpText() List options = new(); foreach (var op in filterList.Keys) { - SearchEngineCommand cmd = filterList[op]; + SearchEngineCommand cmd = filterList[op]; if (cmd.shouldShow == null || cmd.shouldShow()) { options.Add(op + "(" + filterList[op].args.Length + " args)"); @@ -112,7 +112,7 @@ internal override List AvailableCommandsForHelpText() List<(string, string[], string)> options = new(); foreach (var op in filterList.Keys) { - SearchEngineCommand cmd = filterList[op]; + SearchEngineCommand cmd = filterList[op]; if (cmd.shouldShow == null || cmd.shouldShow()) { options.Add((op, cmd.args, cmd.wiki)); @@ -139,21 +139,21 @@ internal override List AvailableCommandsForHelpText() return options; } - public override IEnumerable SearchNoType(object container, string command, bool lenient, bool failureAllOrNone) + public override IEnumerable<(object, object)> SearchNoType(object container, string command, bool lenient, bool failureAllOrNone) { - List res = Search((A)container, command, lenient, failureAllOrNone); - return (IEnumerable)res; + List<(O, F)> res = Search((C)container, command, lenient, failureAllOrNone); + return (IEnumerable<(object, object)>)res; } - public List Search(A param, string command, bool lenient, bool failureAllOrNone) + public List<(O, F)> Search(C param, string command, bool lenient, bool failureAllOrNone) { return Search(param, unpacker(param), command, lenient, failureAllOrNone); } - public virtual List Search(A context, List sourceSet, string command, bool lenient, bool failureAllOrNone) + public virtual List<(O, F)> Search(C context, List<(O, F)> sourceSet, string command, bool lenient, bool failureAllOrNone) { //assumes unpacking doesn't fail var conditions = command.Split("&&", StringSplitOptions.TrimEntries); - List liveSet = sourceSet; + List<(O, F)> liveSet = sourceSet; try { @@ -167,7 +167,7 @@ public virtual List Search(A context, List sourceSet, string command, bool var cmd = condition.Split(' ', 2); - SearchEngineCommand selectedCommand; + SearchEngineCommand selectedCommand; int argC; string[] args; var not = false; @@ -200,10 +200,10 @@ public virtual List Search(A context, List sourceSet, string command, bool } } - Func> filter = selectedCommand.func(args, lenient); - Func criteria = filter(context); - List newRows = new(); - foreach (B row in liveSet) + Func> filter = selectedCommand.func(args, lenient); + Func<(O, F), bool> criteria = filter(context); + List<(O, F)> newRows = new(); + foreach ((O, F) row in liveSet) { if (not ^ criteria(row)) { @@ -216,7 +216,7 @@ public virtual List Search(A context, List sourceSet, string command, bool } catch (Exception e) { - liveSet = failureAllOrNone ? sourceSet : new List(); + liveSet = failureAllOrNone ? sourceSet : new List<(O, F)>(); } return liveSet; @@ -224,11 +224,11 @@ public virtual List Search(A context, List sourceSet, string command, bool internal override List<(TypelessSearchEngine, Type)> NextSearchEngines() { - return GetSearchEngines(typeof(B)); + return GetSearchEngines(typeof((O, F))); } internal override METypelessOperation NextOperation() { - return METypelessOperation.GetEditOperation(typeof(B)); + return METypelessOperation.GetEditOperation(typeof((O, F))); } internal override string NameForHelpTexts() @@ -238,12 +238,12 @@ internal override string NameForHelpTexts() internal override Type getContainerType() { - return typeof(A); + return typeof(C); } internal override Type getElementType() { - return typeof(B); + return typeof((O, F)); } } @@ -267,35 +267,35 @@ internal SearchEngineCommand(string[] args, string wiki, Func : SearchEngine where B : class where D : class +internal class MultiStageSearchEngine : SearchEngine { - internal Func contextGetterForMultiStage; - internal Func resultRetrieverForMultiStage; - internal SearchEngine searchEngineForMultiStage; - internal Func sourceListGetterForMultiStage; + internal Func contextGetterForMultiStage; + internal Func<(O2, F2), (O1, F1), (O1, F1)> resultRetrieverForMultiStage; + internal SearchEngine searchEngineForMultiStage; + internal Func<(O1, F1), (O2, F2)> sourceListGetterForMultiStage; - public override List Search(A context, List sourceSet, string command, bool lenient, + public override List<(O1, F1)> Search(C1 context, List<(O1, F1)> sourceSet, string command, bool lenient, bool failureAllOrNone) { var conditions = command.Split("&&", 2, StringSplitOptions.TrimEntries); - List stage1list = base.Search(context, sourceSet, conditions[0], lenient, failureAllOrNone); + List<(O1, F1)> stage1list = base.Search(context, sourceSet, conditions[0], lenient, failureAllOrNone); if (conditions.Length == 1) { return stage1list; } - B exampleItem = stage1list.FirstOrDefault(); - List stage2list = searchEngineForMultiStage.Search(contextGetterForMultiStage(context, exampleItem), + (O1, F1) exampleItem = stage1list.FirstOrDefault(); + List<(O2, F2)> stage2list = searchEngineForMultiStage.Search(contextGetterForMultiStage(context, exampleItem), stage1list.Select(x => sourceListGetterForMultiStage(x)).ToList(), conditions[1], lenient, failureAllOrNone); return stage2list.Select(x => resultRetrieverForMultiStage(x, exampleItem)).ToList(); } } -internal class ParamAndRowSearchEngine : MultiStageSearchEngine, (ParamBank, Param), Tuple> +internal class ParamAndRowSearchEngine : MultiStageSearchEngine { - public static SearchEngine> parse = + public static SearchEngine parse = new ParamAndRowSearchEngine(); internal override void Setup() @@ -303,9 +303,9 @@ internal override void Setup() name = "paramrow"; unpacker = selection => { - List> list = new(); - list.AddRange(selection.GetSelectedRows().Select((x, i) => Tuple.Create(MassEditRowSource.Selection, x))); - list.AddRange(ParamBank.ClipboardRows.Select((x, i) => Tuple.Create(MassEditRowSource.Clipboard, x))); + List<(MassEditRowSource, Param.Row)> list = new(); + list.AddRange(selection.GetSelectedRows().Select((x, i) => (MassEditRowSource.Selection, x))); + list.AddRange(ParamBank.ClipboardRows.Select((x, i) => (MassEditRowSource.Clipboard, x))); return list; }; filterList.Add("selection", @@ -320,9 +320,9 @@ internal override void Setup() exampleItem.Item1 == MassEditRowSource.Selection ? state.GetActiveParam() : ParamBank.ClipboardParam]); - sourceListGetterForMultiStage = row => Tuple.Create(null, row.Item2); + sourceListGetterForMultiStage = row => (null, row.Item2); searchEngineForMultiStage = RowSearchEngine.rse; - resultRetrieverForMultiStage = (row, exampleItem) => Tuple.Create(exampleItem.Item1, row.Item2); + resultRetrieverForMultiStage = (row, exampleItem) => (exampleItem.Item1, row.Item2); } } @@ -332,7 +332,7 @@ internal enum MassEditRowSource Clipboard } -internal class ParamSearchEngine : SearchEngine> +internal class ParamSearchEngine : SearchEngine { public static ParamSearchEngine pse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -347,7 +347,7 @@ internal override void Setup() name = "param"; unpacker = dummy => ParamBank.AuxBanks.Select((aux, i) => aux.Value.Params.Select((x, i) => (aux.Value, x.Value))) - .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).Select((x, i) => Tuple.Create(x.bank, x.x)).ToList(); + .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).Select((x, i) => (x.bank, x.x)).ToList(); filterList.Add("modified", newCmd(new string[0], "Selects params where any rows do not match the vanilla version, or where any are added. Ignores row names", noArgs(noContext(param => @@ -398,7 +398,7 @@ internal override void Setup() } } -internal class RowSearchEngine : SearchEngine<(ParamBank, Param), Tuple> +internal class RowSearchEngine : SearchEngine<(ParamBank, Param), string, Param.Row> { public static RowSearchEngine rse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -414,7 +414,7 @@ internal override void Setup() unpacker = param => { string name = param.Item1.GetKeyForParam(param.Item2); - return param.Item2.Rows.Select((x, i) => Tuple.Create(name, x)).ToList(); + return param.Item2.Rows.Select((x, i) => (name, x)).ToList(); }; filterList.Add("modified", newCmd(new string[0], "Selects rows which do not match the vanilla version, or are added. Ignores row name", noArgs(context => @@ -567,12 +567,12 @@ internal override void Setup() var paramName = context.Item1.GetKeyForParam(context.Item2); IReadOnlyList cols = context.Item2.Columns; var vtup = context.Item2.GetCol(field); - Tuple testCol = Tuple.Create(vtup.Item1, vtup.Item2); + (PseudoColumn, Param.Column) testCol = (vtup.Item1, vtup.Item2); return row => { (string paramName, Param.Row row) cseSearchContext = (paramName, row.Item2); - List> res = CellSearchEngine.cse.Search(cseSearchContext, - new List> { testCol }, args[1], lenient, false); + List<(PseudoColumn, Param.Column)> res = CellSearchEngine.cse.Search(cseSearchContext, + new List<(PseudoColumn, Param.Column)> { testCol }, args[1], lenient, false); return res.Contains(testCol); }; }; @@ -767,7 +767,7 @@ internal override void Setup() throw new Exception("Could not find param " + otherParam); } - List> rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, + List<(string, Param.Row)> rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, lenient, false); (PseudoColumn, Param.Column) otherFieldReal = otherParamReal.GetCol(otherField); if (!otherFieldReal.IsColumnValid()) @@ -864,7 +864,7 @@ internal override void Setup() } } -internal class CellSearchEngine : SearchEngine<(string, Param.Row), Tuple> +internal class CellSearchEngine : SearchEngine<(string, Param.Row), PseudoColumn, Param.Column> { public static CellSearchEngine cse = new(); @@ -873,10 +873,10 @@ internal override void Setup() name = "cell/property"; unpacker = row => { - List> list = new(); - list.Add(Tuple.Create(PseudoColumn.ID, null)); - list.Add(Tuple.Create(PseudoColumn.Name, null)); - list.AddRange(row.Item2.Columns.Select((cell, i) => Tuple.Create(PseudoColumn.None, cell))); + List<(PseudoColumn, Param.Column)> list = new(); + list.Add((PseudoColumn.ID, null)); + list.Add((PseudoColumn.Name, null)); + list.AddRange(row.Item2.Columns.Select((cell, i) => (PseudoColumn.None, cell))); return list; }; defaultFilter = newCmd(new[] { "field internalName (regex)" }, @@ -1005,7 +1005,7 @@ internal override void Setup() } } -internal class VarSearchEngine : SearchEngine +internal class VarSearchEngine : SearchEngine { public static VarSearchEngine vse = new(); @@ -1014,7 +1014,7 @@ internal override void Setup() name = "variable"; unpacker = dummy => { - return MassParamEdit.massEditVars.Keys.ToList(); + return MassParamEdit.massEditVars.Keys.Select(x => (true, x)).ToList(); }; filterList.Add("vars", newCmd(new[] { "variable names (regex)" }, "Selects variables whose name matches the given regex", (args, lenient) => @@ -1025,7 +1025,7 @@ internal override void Setup() } Regex rx = lenient ? new Regex(args[0], RegexOptions.IgnoreCase) : new Regex($@"^{args[0]}$"); - return noContext(name => rx.IsMatch(name)); + return noContext(bname => rx.IsMatch(bname.Item2)); })); } } diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index 7916f6c5b..b984648b4 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -160,7 +160,7 @@ private void ParamView_ParamList_Main(bool doFocus, float scale, float scrollTo) { List paramKeyList = UICache.GetCached(_paramEditor, _viewIndex, () => { - List> list = + List<(ParamBank, Param)> list = ParamSearchEngine.pse.Search(true, _selection.currentParamSearchString, true, true); List keyList = list.Where(param => param.Item1 == ParamBank.PrimaryBank) .Select(param => ParamBank.PrimaryBank.GetKeyForParam(param.Item2)).ToList(); From db2214f2c729cb5fb0b3bcfacf1159ca1cd270da Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 3 Apr 2024 00:22:55 +0100 Subject: [PATCH 33/61] Generify Parsing and Exec, searchengine is now balanced. delegate typing remains an issue. --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 41 +- .../Editor/MassEdit/EditOperation.cs | 36 +- src/StudioCore/Editor/MassEdit/MassEdit.cs | 365 ++++-------------- .../Editor/MassEdit/SearchEngine.cs | 157 +++----- src/StudioCore/ParamEditor/ParamEditorView.cs | 2 +- 5 files changed, 197 insertions(+), 404 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index cc3a36278..f9d0b29a6 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -173,12 +173,13 @@ internal string getCurrentStepText(bool valid, string command, int[] argIndices, internal class AutoFill { - private static readonly AutoFillSearchEngine autoFillParse = new("parse", ParamAndRowSearchEngine.parse); + private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", ParamRowSelectionSearchEngine.prsse); + private static readonly AutoFillSearchEngine autoFillPrcse = new("prcse", ParamRowClipBoardSearchEngine.prcse); private static readonly AutoFillSearchEngine autoFillVse = new("vse", VarSearchEngine.vse); private static readonly AutoFillSearchEngine autoFillPse = - new("pse", ParamSearchEngine.pse); + new("pse", ParamRowSelectionSearchEngine.prsse); private static readonly AutoFillSearchEngine autoFillRse = new("rse", RowSearchEngine.rse); @@ -249,9 +250,10 @@ public static string MassEditCompleteAutoFill() ImGui.Button($@"{ForkAwesome.CaretDown}"); if (ImGui.BeginPopupContextItem("##meautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { - ImGui.PushID("paramrow"); + /*special case*/ + ImGui.PushID("paramrowselection"); ImGui.TextColored(HINTCOLOUR, "Select param and rows..."); - var result1 = autoFillParse.Menu(false, autoFillRse, false, ": ", null, inheritedCommand => + var result0 = autoFillPrsse.Menu(false, autoFillRse, false, ": ", null, inheritedCommand => { if (inheritedCommand != null) { @@ -280,6 +282,37 @@ public static string MassEditCompleteAutoFill() return res2; }); ImGui.PopID(); + ImGui.PushID("paramrowclipboard"); + var result1 = autoFillPrcse.Menu(false, autoFillRse, false, ": ", null, inheritedCommand => + { + if (inheritedCommand != null) + { + ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand); + } + + ImGui.TextColored(HINTCOLOUR, "Select fields..."); + var res1 = autoFillCse.Menu(true, true, ": ", inheritedCommand, inheritedCommand2 => + { + if (inheritedCommand2 != null) + { + ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand2); + } + + ImGui.TextColored(HINTCOLOUR, "Select field operation..."); + return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); + }); + ImGui.Separator(); + ImGui.TextColored(HINTCOLOUR, "Select row operation..."); + var res2 = MassEditAutoFillForOperation(MERowOperation.rowOps, ref _autoFillArgsRop, ";", null); + if (res1 != null) + { + return res1; + } + + return res2; + }); + ImGui.PopID(); + /*end special case*/ ImGui.Separator(); ImGui.PushID("param"); ImGui.TextColored(HINTCOLOUR, "Select params..."); diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index cd4554388..0248f1828 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -43,9 +43,10 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); - internal abstract object getTrueValue(Dictionary contextObjects); + internal abstract object getTrueValue(Dictionary contextObjects); internal abstract bool validateResult(object res); - internal abstract void useResult(List actionList, Dictionary contextObjects, object res); + internal abstract void useResult(List actionList, Dictionary contextObjects, object res); + internal abstract bool HandlesCommand(string command); } internal abstract class MEOperation : METypelessOperation { @@ -55,13 +56,14 @@ internal abstract class MEOperation : METypelessOperation internal MEOperation() { Setup(); + AddEditOperation(this); } internal virtual void Setup() { } - internal bool HandlesCommand(string command) + internal override bool HandlesCommand(string command) { return operations.ContainsKey(command); } @@ -124,7 +126,7 @@ internal override void Setup() }, () => CFG.Current.Param_AdvancedMassedit)); } - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue(Dictionary contextObjects) { return true; //Global op technically has no context / uses the dummy context of boolean } @@ -134,7 +136,7 @@ internal override bool validateResult(object res) return true; } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void useResult(List actionList, Dictionary contextObjects, object res) { return; //Global ops, for now, don't use actions and simply execute effects themselves } @@ -229,7 +231,7 @@ internal override void Setup() )); } - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue(Dictionary contextObjects) { return contextObjects[typeof((string, Param.Row))]; } @@ -244,14 +246,14 @@ internal override bool validateResult(object res) return true; } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void useResult(List actionList, Dictionary contextObjects, object res) { (Param p2, Param.Row rs) = ((Param, Param.Row))res; actionList.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); } } -internal abstract class MEValueOperation : MEOperation +internal abstract class MEValueOperation : MEOperation { internal override void Setup() { @@ -322,33 +324,33 @@ internal override bool validateResult(object res) return true; } } -internal class MECellOperation : MEValueOperation +internal class MECellOperation : MEValueOperation<(PseudoColumn, Param.Column)> { public static MECellOperation cellOps = new(); - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue(Dictionary contextObjects) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))contextObjects[typeof((PseudoColumn, Param.Column))]; return row.Get(col); } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void useResult(List actionList, Dictionary contextObjects, object res) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))contextObjects[typeof((PseudoColumn, Param.Column))]; actionList.AppendParamEditAction(row, col, res); } } -internal class MEVarOperation : MEValueOperation +internal class MEVarOperation : MEValueOperation { public static MEVarOperation varOps = new(); - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue(Dictionary contextObjects) { - return MassParamEdit.massEditVars[(string)contextObjects[typeof(string)]]; + return MassParamEdit.massEditVars[(string)contextObjects[typeof(string)].Item2]; } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void useResult(List actionList, Dictionary contextObjects, object res) { - MassParamEdit.massEditVars[(string)contextObjects[typeof(string)]] = res; + MassParamEdit.massEditVars[(string)contextObjects[typeof(string)].Item2] = res; } } @@ -820,7 +822,7 @@ internal static class OAGFuncExtension return func(newContextInput); return func; }*/ - internal static object tryFoldAsFunc(this object maybeFunc, int editIndex, object newContextInput) + internal static object tryFoldAsFunc(this object maybeFunc, int editIndex, (object, object) newContextInput) { if (maybeFunc is not Delegate) return maybeFunc; diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 5e629659c..102a58a73 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -1,5 +1,7 @@ #nullable enable using Andre.Formats; +using DotNext.Collections.Generic; +using Org.BouncyCastle.Crypto.Engines; using StudioCore.Editor; using StudioCore.ParamEditor; using System; @@ -44,21 +46,24 @@ internal MEOperationException(string? message) : base(message) internal struct MEFilterStage { internal string command; + internal TypelessSearchEngine engine; // No arguments because this is handled separately in SearchEngine - internal MEFilterStage(string toParse, int line, string stageName, TypelessSearchEngine expectedStage) + internal MEFilterStage(string toParse, int line, string stageName, TypelessSearchEngine stageEngine) { command = toParse.Trim(); if (command.Equals("")) { - throw new MEParseException($@"Could not find {stageName} filter. Add : and one of {string.Join(", ", expectedStage.AvailableCommandsForHelpText())}", line); + throw new MEParseException($@"Could not find {stageName} filter. Add : and one of {string.Join(", ", stageEngine.AvailableCommandsForHelpText())}", line); } + engine = stageEngine; } } internal struct MEOperationStage { internal string command; internal string arguments; - internal MEOperationStage(string toParse, int line, string stageName, METypelessOperation expectedOperation) + internal METypelessOperation operation; + internal MEOperationStage(string toParse, int line, string stageName, METypelessOperation operationType) { var stage = toParse.TrimStart().Split(' ', 2); command = stage[0].Trim(); @@ -66,12 +71,13 @@ internal MEOperationStage(string toParse, int line, string stageName, METypeless arguments = stage[1]; if (command.Equals("")) { - throw new MEParseException($@"Could not find operation to perform. Add : and one of {string.Join(' ', expectedOperation.AllCommands().Keys)}", line); + throw new MEParseException($@"Could not find operation to perform. Add : and one of {string.Join(' ', operationType.AllCommands().Keys)}", line); } - if (!expectedOperation.AllCommands().ContainsKey(command)) + if (!operationType.AllCommands().ContainsKey(command)) { throw new MEParseException($@"Unknown {stageName} operation {command}", line); } + operation = operationType; } internal string[] getArguments(int count) { @@ -141,23 +147,13 @@ public class MassParamEditRegex private ParamBank bank; private ParamEditorSelectionState context; - private object[] paramArgFuncs; + private object[] argFuncs; METypelessOperationDef parsedOp; - //TODO use these - List filters = new(); + Queue filters = new(); MEOperationStage operation; - private MEOperationStage globalOperationInfo; - private MEOperationStage varOperationInfo; - private MEOperationStage rowOperationInfo; - private MEOperationStage cellOperationInfo; - private MEFilterStage varStageInfo; - private MEFilterStage paramRowStageInfo; - private MEFilterStage paramStageInfo; - private MEFilterStage rowStageInfo; - private MEFilterStage cellStageInfo; - + internal static ParamEditorSelectionState totalHackPleaseKillme = null; public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank bank, string commandsString, ParamEditorSelectionState context) { @@ -185,6 +181,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba currentEditData._currentLine = currentLine; currentEditData.bank = bank; currentEditData.context = context; + totalHackPleaseKillme = context; MassEditResult result = currentEditData.ParseAndExecCommand(command); @@ -209,57 +206,35 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba private MassEditResult ParseAndExecCommand(string command) { - var primaryFilter = command.Split(':', 2)[0].Trim(); + var stage = command.Split(":", 2); - if (MEGlobalOperation.globalOps.HandlesCommand(primaryFilter.Split(" ", 2)[0])) - { - return ParseOpStep(command, "global", MEGlobalOperation.globalOps, ref globalOperationInfo); - } - else if (VarSearchEngine.vse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) - { - return ParseFilterStep(command, VarSearchEngine.vse, ref varStageInfo, (restOfStages) => - { - return ParseOpStep(restOfStages, "var", MEVarOperation.varOps, ref varOperationInfo); - }); - } - else if (ParamAndRowSearchEngine.parse.HandlesCommand(primaryFilter.Split(" ", 2)[0])) - { - return ParseFilterStep(command, ParamAndRowSearchEngine.parse, ref paramRowStageInfo, (restOfStages) => - { - if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) - { - return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo); - } - return ParseFilterStep(restOfStages, CellSearchEngine.cse, ref cellStageInfo, (restOfStages) => - { - return ParseOpStep(restOfStages, "cell/property", MECellOperation.cellOps, ref cellOperationInfo); - }); - }); - } - else + Type currentType = typeof((bool, bool)); // Always start at boolbool type as basis + string firstStage = stage[0]; + string firstStageKeyword = firstStage.Trim().Split(" ", 2)[0]; + + var op = METypelessOperation.GetEditOperation(currentType); + // Try run an operation + if (op != null && op.HandlesCommand(firstStageKeyword)) + return ParseOpStep(stage[1], op.NameForHelpTexts(), op); + + var nextStage = TypelessSearchEngine.GetSearchEngines(currentType); + // Try out each defined search engine for the current type + foreach ((TypelessSearchEngine engine, Type t) in nextStage) { - return ParseFilterStep(command, ParamSearchEngine.pse, ref paramStageInfo, (restOfStages) => + if (engine.HandlesCommand(firstStageKeyword)) { - return ParseFilterStep(restOfStages, RowSearchEngine.rse, ref rowStageInfo, (restOfStages) => - { - if (MERowOperation.rowOps.HandlesCommand(restOfStages.Trim().Split(" ", 2)[0])) - { - return ParseOpStep(restOfStages, "row", MERowOperation.rowOps, ref rowOperationInfo); - } - return ParseFilterStep(restOfStages, CellSearchEngine.cse, ref cellStageInfo, (restOfStages) => - { - return ParseOpStep(restOfStages, "cell/property", MECellOperation.cellOps, ref cellOperationInfo); - }); - }); - }); + return ParseFilterStep(command, engine); + } } + //Assume it's default search of last search option + return ParseFilterStep(command, nextStage.Last().Item1); } - private MassEditResult ParseFilterStep(string restOfStages, TypelessSearchEngine expectedSearchEngine, ref MEFilterStage target, Func nextStageFunc) + private MassEditResult ParseFilterStep(string stageText, TypelessSearchEngine expectedSearchEngine) { - var stage = restOfStages.Split(":", 2); + var stage = stageText.Split(":", 2); string stageName = expectedSearchEngine.NameForHelpTexts(); - target = new MEFilterStage(stage[0], _currentLine, stageName, expectedSearchEngine); + filters.Enqueue(new MEFilterStage(stage[0], _currentLine, stageName, expectedSearchEngine)); if (stage.Length < 2) { @@ -274,31 +249,45 @@ private MassEditResult ParseFilterStep(string restOfStages, TypelessSearchEngine return new MassEditResult(MassEditResultType.PARSEERROR, $@"Could not find next stage to perform (no suggestions found). Check your colon placement. (line {_currentLine})"); } - return nextStageFunc(stage[1]); + Type currentType = expectedSearchEngine.getElementType(); + string restOfStages = stage[1]; + string nextStageKeyword = restOfStages.Trim().Split(" ", 2)[0]; + + var op = METypelessOperation.GetEditOperation(currentType); + // Try run an operation + if (op != null && op.HandlesCommand(nextStageKeyword)) + return ParseOpStep(stage[1], op.NameForHelpTexts(), op); + + var nextStage = TypelessSearchEngine.GetSearchEngines(currentType); + // Try out each defined search engine for the current type + foreach ((TypelessSearchEngine engine, Type t) in nextStage) + { + if (engine.HandlesCommand(nextStageKeyword)) + return ParseFilterStep(restOfStages, engine); + } + //Assume it's default search of last search option + return ParseFilterStep(restOfStages, nextStage.Last().Item1); } - private MassEditResult ParseOpStep(string restOfStages, string stageName, METypelessOperation operation, ref MEOperationStage target) + private MassEditResult ParseOpStep(string stageText, string stageName, METypelessOperation operation) { - target = new MEOperationStage(restOfStages, _currentLine, stageName, operation); + this.operation = new MEOperationStage(stageText, _currentLine, stageName, operation); - parsedOp = operation.AllCommands()[target.command]; - paramArgFuncs = MEOperationArgument.arg.getContextualArguments(parsedOp.argNames.Length, target.arguments); - if (parsedOp.argNames.Length != paramArgFuncs.Length) + parsedOp = operation.AllCommands()[this.operation.command]; + argFuncs = MEOperationArgument.arg.getContextualArguments(parsedOp.argNames.Length, this.operation.arguments); + if (parsedOp.argNames.Length != argFuncs.Length) { - return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {globalOperationInfo.command} (line {_currentLine})"); + return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {this.operation.command} (line {_currentLine})"); } + var contextObjects = new Dictionary() { { typeof(bool), (true, true)} }; - //hacks for now - if (globalOperationInfo.command != null) - return SandboxMassEditExecution(() => ExecGlobalOp()); - if (varStageInfo.command != null) - return SandboxMassEditExecution(() => ExecVarStage()); - - if (paramRowStageInfo.command != null) - return SandboxMassEditExecution(() => ExecParamRowStage()); - if (paramStageInfo.command != null) - return SandboxMassEditExecution(() => ExecStage(paramStageInfo, ParamSearchEngine.pse, true, paramArgFuncs, new Dictionary() { { typeof(bool), true } })); - //return SandboxMassEditExecution(() => ExecParamStage()); + if (filters.Count == 0) + return SandboxMassEditExecution(() => ExecOp(this.operation, this.operation.command, argFuncs, contextObjects, operation)); + else + { + MEFilterStage baseFilter = filters.Dequeue(); + return SandboxMassEditExecution(() => ExecStage(baseFilter, baseFilter.engine, (true, true), argFuncs, contextObjects)); + } throw new MEParseException("No initial stage or op was parsed", _currentLine); } @@ -314,143 +303,34 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, object contextObject, IEnumerable argFuncs, Dictionary contextObjects) + private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, (object, object) contextObject, IEnumerable argFuncs, Dictionary contextObjects) { var editCount = -1; - foreach (object currentObject in engine.SearchNoType(contextObject, info.command, false, false)) + foreach ((object, object) currentObject in engine.SearchNoType(contextObject, info.command, false, false)) { editCount++; //add context - IEnumerable newArgFuncs = argFuncs.Select((func, i) => func.tryFoldAsFunc(editCount, currentObject)); - //determine next stage - MEFilterStage nextInfo = new(); - TypelessSearchEngine nextStage = null; - string opStageName = null; - MEOperationStage opInfo = new(); contextObjects[engine.getElementType()] = currentObject; + //update argGetters + IEnumerable newArgFuncs = argFuncs.Select((func, i) => func.tryFoldAsFunc(editCount, currentObject)); //exec it MassEditResult res; - if (opInfo.command != null) - res = ExecOp(opInfo, opStageName, newArgFuncs, contextObjects, METypelessOperation.GetEditOperation(engine.getElementType())); - else - res = ExecStage(nextInfo, nextStage, currentObject, newArgFuncs, contextObjects); - if (res.Type != MassEditResultType.SUCCESS) - { - return res; - } - } - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecParamStage() - { - var paramEditCount = -1; - var operationForPrint = rowOperationInfo.command != null ? rowOperationInfo : cellOperationInfo; - foreach ((ParamBank b, Param p) in ParamSearchEngine.pse.Search(false, paramStageInfo.command, false, false)) - { - paramEditCount++; - IEnumerable paramArgFunc = - paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(paramEditCount, p)); - MassEditResult res = ExecRowStage(paramArgFunc, b.GetKeyForParam(p), b, p); - if (res.Type != MassEditResultType.SUCCESS) - { - return res; - } - } - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecRowStage(IEnumerable paramArgFunc, - string paramname, ParamBank b, Param p) - { - var rowEditCount = -1; - foreach ((string param, Param.Row row) in RowSearchEngine.rse.Search((b, p), rowStageInfo.command, false, false)) - { - rowEditCount++; - object[] rowArgFunc = - paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); - MassEditResult res; - if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, (paramname, row)); - else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, (paramname, row)); + if (filters.Count == 0) + res = ExecOp(operation, operation.command, argFuncs, contextObjects, operation.operation); else - throw new MEParseException("No row op or cell stage was parsed", _currentLine); - if (res.Type != MassEditResultType.SUCCESS) { - return res; + MEFilterStage nextFilterFilter = filters.Dequeue(); + res = ExecStage(nextFilterFilter, nextFilterFilter.engine, currentObject, newArgFuncs, contextObjects); } - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecCellStage(object[] rowArgFunc, - (string, Param.Row) row) - { - var cellEditCount = -1; - foreach ((PseudoColumn, Param.Column) col in CellSearchEngine.cse.Search(row, cellStageInfo.command, - false, false)) - { - cellEditCount++; - var cellArgValues = rowArgFunc.Select((argV, i) => argV.tryFoldAsFunc(cellEditCount, col)).ToArray(); - MassEditResult res = ExecCellOp(cellArgValues, row, (col.Item1, col.Item2)); if (res.Type != MassEditResultType.SUCCESS) { return res; } } - return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecVarStage() - { - var varArgs = paramArgFuncs; - foreach (var varName in VarSearchEngine.vse.Search(false, varStageInfo.command, false, false)) - { - MassEditResult res = ExecVarOp(varName.Item2, varArgs); - if (res.Type != MassEditResultType.SUCCESS) - { - return res; - } - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecParamRowStage() - { - Param activeParam = bank.Params[context.GetActiveParam()]; - IEnumerable paramArgFunc = - paramArgFuncs.Select((func, i) => func.tryFoldAsFunc(0, activeParam)); // technically invalid for clipboard - var rowEditCount = -1; - foreach ((MassEditRowSource source, Param.Row row) in ParamAndRowSearchEngine.parse.Search(context, - paramRowStageInfo.command, false, false)) - { - rowEditCount++; - object[] rowArgFunc = - paramArgFunc.Select((rowFunc, i) => rowFunc.tryFoldAsFunc(rowEditCount, row)).ToArray(); - var paramname = source == MassEditRowSource.Selection - ? context.GetActiveParam() - : ParamBank.ClipboardParam; - - MassEditResult res; - if (rowOperationInfo.command != null) - res = ExecRowOp(rowArgFunc, (paramname, row)); - else if (cellStageInfo.command != null) - res = ExecCellStage(rowArgFunc, (paramname, row)); - else - throw new MEParseException("No row op or cell stage was parsed", _currentLine); - if (res.Type != MassEditResultType.SUCCESS) - { - return res; - } - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, Dictionary contextObjects, METypelessOperation opType) //TODO use global op + private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); var opResults = parsedOp.function(opType.getTrueValue(contextObjects), argValues); @@ -461,97 +341,6 @@ private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerabl _partialActions.Add(null);//TODO using opType return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecGlobalOp() - { - var globalArgValues = paramArgFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var result = (bool)parsedOp.function(context, globalArgValues); - if (!result) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing global operation {globalOperationInfo} (line {_currentLine})"); - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - private MassEditResult ExecVarOp(string var, object[] args) - { - var varArgValues = args.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); - MassParamEdit.massEditVars[var] = parsedOp.function(MassParamEdit.massEditVars[var], varArgValues); - var result = true; // Anything that practicably can go wrong - if (!result) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing var operation {varOperationInfo} (line {_currentLine})"); - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecRowOp(object[] rowArgFunc, (string, Param.Row) row) - { - var rowArgValues = rowArgFunc.Select((argV, i) => argV.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray(); - (Param? p2, Param.Row? rs) = ((Param? p2, Param.Row? rs))parsedOp.function(row, rowArgValues); - if (p2 == null) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {rowOperationInfo.command} {String.Join(' ', rowArgValues)} on row (line {_currentLine})"); - } - - if (rs != null) - { - _partialActions.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); - } - - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } - - private MassEditResult ExecCellOp(object[] cellArgValues, (string, Param.Row) nameAndRow, - (PseudoColumn, Param.Column) col) - { - (string paramName, Param.Row row) = nameAndRow; - object res = null; - string errHelper = null; - try - { - res = parsedOp.function(row.Get(col), cellArgValues.Select((x, i) => x.assertCompleteContextOrThrow(i).ToParamEditorString()).ToArray()); - } - catch (FormatException e) - { - errHelper = "Type is not correct. Check the operation arguments result in usable values."; - } - catch (InvalidCastException e) - { - errHelper = "Cannot cast to correct type. Check the operation arguments result in usable values."; - } - catch (MEOperationException e) - { - errHelper = e.Message; - } - catch (Exception e) - { - errHelper = $@"Unknown error ({e.Message})"; - } - string errorValue = null; - if (res == null) - { - errorValue = cellArgValues.Length > 0 && cellArgValues[0] is not Delegate ? String.Join(' ', cellArgValues) : "[Undetermined value]"; - } - - if (res == null && col.Item1 == PseudoColumn.ID) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on ID ({errHelper}) (line {_currentLine})"); - } - - if (res == null && col.Item1 == PseudoColumn.Name) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on Name ({errHelper}) (line {_currentLine})"); - } - - if (res == null) - { - return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Could not perform operation {cellOperationInfo.command} {errorValue} on field {col.Item2.Def.InternalName} ({errHelper}) (line {_currentLine})"); - } - - _partialActions.AppendParamEditAction(row, col, res); - return new MassEditResult(MassEditResultType.SUCCESS, ""); - } } public class MassParamEditOther diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index f7b19a9f6..cb8d426ca 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -18,15 +18,18 @@ namespace StudioCore.Editor.MassEdit; internal abstract class TypelessSearchEngine { private static Dictionary> searchEngines = new(); - internal static void AddSearchEngine(SearchEngine engine) + internal static void AddSearchEngine(SearchEngine engine) { - if (!searchEngines.ContainsKey(typeof(I))) - searchEngines.Add(typeof(I), new()); - searchEngines[typeof(I)].Add((engine, typeof(O))); + if (!searchEngines.ContainsKey(typeof((CO, CF)))) + searchEngines.Add(typeof((CO, CF)), new()); + searchEngines[typeof((CO, CF))].Add((engine, typeof((EO, EF)))); } internal static List<(TypelessSearchEngine, Type)> GetSearchEngines(Type t) { - return searchEngines[t]; + var list = searchEngines.GetValueOrDefault(t); + if (list == null) + list = new List<(TypelessSearchEngine, Type)>(); + return list; } internal abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); internal abstract List<(string, string[])> AllCommands(); @@ -36,14 +39,15 @@ internal static void AddSearchEngine(SearchEngine engine) internal abstract string NameForHelpTexts(); internal abstract Type getContainerType(); internal abstract Type getElementType(); - public abstract IEnumerable<(object, object)> SearchNoType(object container, string command, bool lenient, bool failureAllOrNone); + public abstract IEnumerable<(object, object)> SearchNoType((object, object) container, string command, bool lenient, bool failureAllOrNone); + internal abstract bool HandlesCommand(string command); } -internal class SearchEngine : TypelessSearchEngine +internal class SearchEngine : TypelessSearchEngine { - internal SearchEngineCommand defaultFilter; + internal SearchEngineCommand<(CO, CF), (EO, EF)> defaultFilter; - internal Dictionary> filterList = new(); - internal Func> unpacker; + internal Dictionary> filterList = new(); + internal Func<(CO, CF), List<(EO, EF)>> unpacker; internal string name = "[unnamed search engine]"; internal SearchEngine() @@ -54,15 +58,15 @@ internal SearchEngine() protected void addExistsFilter() { - filterList.Add("exists", newCmd(new string[0], "Selects all elements", noArgs(noContext(B => true)))); + filterList.Add("exists", newCmd(new string[0], "Selects all elements", noArgs(noContext(b => true)))); } - protected Func>> noArgs(Func> func) + protected Func>> noArgs(Func<(CO, CF), Func<(EO, EF), bool>> func) { return (args, lenient) => func; } - protected Func> noContext(Func<(O, F), bool> func) + protected Func<(CO, CF), Func<(EO, EF), bool>> noContext(Func<(EO, EF), bool> func) { return context => func; } @@ -71,13 +75,13 @@ internal virtual void Setup() { } - internal SearchEngineCommand newCmd(string[] args, string wiki, - Func>> func, Func shouldShow = null) + internal SearchEngineCommand<(CO, CF), (EO, EF)> newCmd(string[] args, string wiki, + Func>> func, Func shouldShow = null) { - return new SearchEngineCommand(args, wiki, func, shouldShow); + return new SearchEngineCommand<(CO, CF), (EO, EF)>(args, wiki, func, shouldShow); } - internal bool HandlesCommand(string command) + internal override bool HandlesCommand(string command) { if (command.Length > 0 && command.StartsWith('!')) { @@ -92,7 +96,7 @@ internal override List AvailableCommandsForHelpText() List options = new(); foreach (var op in filterList.Keys) { - SearchEngineCommand cmd = filterList[op]; + SearchEngineCommand<(CO, CF), (EO, EF)> cmd = filterList[op]; if (cmd.shouldShow == null || cmd.shouldShow()) { options.Add(op + "(" + filterList[op].args.Length + " args)"); @@ -112,7 +116,7 @@ internal override List AvailableCommandsForHelpText() List<(string, string[], string)> options = new(); foreach (var op in filterList.Keys) { - SearchEngineCommand cmd = filterList[op]; + SearchEngineCommand<(CO, CF), (EO, EF)> cmd = filterList[op]; if (cmd.shouldShow == null || cmd.shouldShow()) { options.Add((op, cmd.args, cmd.wiki)); @@ -139,21 +143,21 @@ internal override List AvailableCommandsForHelpText() return options; } - public override IEnumerable<(object, object)> SearchNoType(object container, string command, bool lenient, bool failureAllOrNone) + public override IEnumerable<(object, object)> SearchNoType((object, object) container, string command, bool lenient, bool failureAllOrNone) { - List<(O, F)> res = Search((C)container, command, lenient, failureAllOrNone); - return (IEnumerable<(object, object)>)res; + List<(EO, EF)> res = Search(((CO, CF))container, command, lenient, failureAllOrNone); + return res.Select((x) => ((object)x.Item1, (object)x.Item2)); } - public List<(O, F)> Search(C param, string command, bool lenient, bool failureAllOrNone) + public List<(EO, EF)> Search((CO, CF) param, string command, bool lenient, bool failureAllOrNone) { return Search(param, unpacker(param), command, lenient, failureAllOrNone); } - public virtual List<(O, F)> Search(C context, List<(O, F)> sourceSet, string command, bool lenient, bool failureAllOrNone) + public virtual List<(EO, EF)> Search((CO, CF) context, List<(EO, EF)> sourceSet, string command, bool lenient, bool failureAllOrNone) { //assumes unpacking doesn't fail var conditions = command.Split("&&", StringSplitOptions.TrimEntries); - List<(O, F)> liveSet = sourceSet; + List<(EO, EF)> liveSet = sourceSet; try { @@ -167,7 +171,7 @@ internal override List AvailableCommandsForHelpText() var cmd = condition.Split(' ', 2); - SearchEngineCommand selectedCommand; + SearchEngineCommand<(CO, CF), (EO, EF)> selectedCommand; int argC; string[] args; var not = false; @@ -200,10 +204,10 @@ internal override List AvailableCommandsForHelpText() } } - Func> filter = selectedCommand.func(args, lenient); - Func<(O, F), bool> criteria = filter(context); - List<(O, F)> newRows = new(); - foreach ((O, F) row in liveSet) + Func<(CO, CF), Func<(EO, EF), bool>> filter = selectedCommand.func(args, lenient); + Func<(EO, EF), bool> criteria = filter(context); + List<(EO, EF)> newRows = new(); + foreach ((EO, EF) row in liveSet) { if (not ^ criteria(row)) { @@ -216,7 +220,7 @@ internal override List AvailableCommandsForHelpText() } catch (Exception e) { - liveSet = failureAllOrNone ? sourceSet : new List<(O, F)>(); + liveSet = failureAllOrNone ? sourceSet : new List<(EO, EF)>(); } return liveSet; @@ -224,11 +228,11 @@ internal override List AvailableCommandsForHelpText() internal override List<(TypelessSearchEngine, Type)> NextSearchEngines() { - return GetSearchEngines(typeof((O, F))); + return GetSearchEngines(typeof((EO, EF))); } internal override METypelessOperation NextOperation() { - return METypelessOperation.GetEditOperation(typeof((O, F))); + return METypelessOperation.GetEditOperation(typeof((EO, EF))); } internal override string NameForHelpTexts() @@ -238,12 +242,12 @@ internal override string NameForHelpTexts() internal override Type getContainerType() { - return typeof(C); + return typeof((CO, CF)); } internal override Type getElementType() { - return typeof((O, F)); + return typeof((EO, EF)); } } @@ -264,75 +268,40 @@ internal SearchEngineCommand(string[] args, string wiki, Func : SearchEngine +internal class ParamRowSelectionSearchEngine : SearchEngine { - internal Func contextGetterForMultiStage; - internal Func<(O2, F2), (O1, F1), (O1, F1)> resultRetrieverForMultiStage; - internal SearchEngine searchEngineForMultiStage; - internal Func<(O1, F1), (O2, F2)> sourceListGetterForMultiStage; + public static ParamRowSelectionSearchEngine prsse = new(); - public override List<(O1, F1)> Search(C1 context, List<(O1, F1)> sourceSet, string command, bool lenient, - bool failureAllOrNone) + internal override void Setup() { - var conditions = command.Split("&&", 2, StringSplitOptions.TrimEntries); - List<(O1, F1)> stage1list = base.Search(context, sourceSet, conditions[0], lenient, failureAllOrNone); - if (conditions.Length == 1) - { - return stage1list; - } - - (O1, F1) exampleItem = stage1list.FirstOrDefault(); - List<(O2, F2)> stage2list = searchEngineForMultiStage.Search(contextGetterForMultiStage(context, exampleItem), - stage1list.Select(x => sourceListGetterForMultiStage(x)).ToList(), conditions[1], lenient, - failureAllOrNone); - return stage2list.Select(x => resultRetrieverForMultiStage(x, exampleItem)).ToList(); + name = "selection"; + unpacker = dummy => { + string param = MassParamEditRegex.totalHackPleaseKillme.GetActiveParam(); + return MassParamEditRegex.totalHackPleaseKillme.GetSelectedRows().Select((x) => (param, x)).ToList(); + }; + filterList.Add("selection", newCmd(new string[0], + "Selects param rows selected in the current param window", + noArgs(noContext(param => true)))); } } - -internal class ParamAndRowSearchEngine : MultiStageSearchEngine +internal class ParamRowClipBoardSearchEngine : SearchEngine { - public static SearchEngine parse = - new ParamAndRowSearchEngine(); + public static ParamRowClipBoardSearchEngine prcse = new(); internal override void Setup() { - name = "paramrow"; - unpacker = selection => - { - List<(MassEditRowSource, Param.Row)> list = new(); - list.AddRange(selection.GetSelectedRows().Select((x, i) => (MassEditRowSource.Selection, x))); - list.AddRange(ParamBank.ClipboardRows.Select((x, i) => (MassEditRowSource.Clipboard, x))); - return list; + name = "clipboard"; + unpacker = dummy => { + string param = ParamBank.ClipboardParam; + return ParamBank.ClipboardRows.Select((x) => (param, x)).ToList(); }; - filterList.Add("selection", - newCmd(new string[0], "Selects the current param selection and selected rows in that param", - noArgs(noContext(row => row.Item1 == MassEditRowSource.Selection)))); - filterList.Add("clipboard", - newCmd(new string[0], "Selects the param of the clipboard and the rows in the clipboard", - noArgs(noContext(row => row.Item1 == MassEditRowSource.Clipboard)), - () => ParamBank.ClipboardRows?.Count > 0)); - contextGetterForMultiStage = (state, exampleItem) => (ParamBank.PrimaryBank, - ParamBank.PrimaryBank.Params[ - exampleItem.Item1 == MassEditRowSource.Selection - ? state.GetActiveParam() - : ParamBank.ClipboardParam]); - sourceListGetterForMultiStage = row => (null, row.Item2); - searchEngineForMultiStage = RowSearchEngine.rse; - resultRetrieverForMultiStage = (row, exampleItem) => (exampleItem.Item1, row.Item2); + filterList.Add("clipboard", newCmd(new string[0], + "Selects param rows copied in the clipboard", + noArgs(noContext(param => true)))); } } -internal enum MassEditRowSource -{ - Selection, - Clipboard -} - -internal class ParamSearchEngine : SearchEngine +internal class ParamSearchEngine : SearchEngine { public static ParamSearchEngine pse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -398,7 +367,7 @@ internal override void Setup() } } -internal class RowSearchEngine : SearchEngine<(ParamBank, Param), string, Param.Row> +internal class RowSearchEngine : SearchEngine { public static RowSearchEngine rse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; @@ -864,7 +833,7 @@ internal override void Setup() } } -internal class CellSearchEngine : SearchEngine<(string, Param.Row), PseudoColumn, Param.Column> +internal class CellSearchEngine : SearchEngine { public static CellSearchEngine cse = new(); @@ -1005,7 +974,7 @@ internal override void Setup() } } -internal class VarSearchEngine : SearchEngine +internal class VarSearchEngine : SearchEngine { public static VarSearchEngine vse = new(); diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index b984648b4..35059b3c2 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -161,7 +161,7 @@ private void ParamView_ParamList_Main(bool doFocus, float scale, float scrollTo) List paramKeyList = UICache.GetCached(_paramEditor, _viewIndex, () => { List<(ParamBank, Param)> list = - ParamSearchEngine.pse.Search(true, _selection.currentParamSearchString, true, true); + ParamSearchEngine.pse.Search((true, true), _selection.currentParamSearchString, true, true); List keyList = list.Where(param => param.Item1 == ParamBank.PrimaryBank) .Select(param => ParamBank.PrimaryBank.GetKeyForParam(param.Item2)).ToList(); From b8984196e156f038952fde60dfa7e36045779443 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 3 Apr 2024 00:49:16 +0100 Subject: [PATCH 34/61] Use wrapping hack to coerce types. Pass current contextObject more readily. --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 2 +- .../Editor/MassEdit/EditOperation.cs | 56 +++++++++---------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 18 +++--- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index f9d0b29a6..69ce78493 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -416,7 +416,7 @@ public static string MassEditOpAutoFill() return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); } - private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, + private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, string suffix, Func subMenu) { var currentArgIndex = 0; diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 0248f1828..ed0262f68 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -19,22 +19,22 @@ internal abstract class METypelessOperationDef internal Func function; internal Func shouldShow; } -internal class MEOperationDef : METypelessOperationDef +internal class MEOperationDef : METypelessOperationDef { - internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) + internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) { argNames = args; wiki = tooltip; - function = func as Func; + function = (x, str) => func((I)x, str); //Shitty wrapping perf loss shouldShow = show; } } internal abstract class METypelessOperation { private static Dictionary editOperations = new(); - internal static void AddEditOperation(MEOperation engine) + internal static void AddEditOperation(MEOperation engine) { - editOperations[typeof(I)] = engine; + editOperations[typeof(R)] = engine; } internal static METypelessOperation GetEditOperation(Type t) { @@ -43,12 +43,12 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); - internal abstract object getTrueValue(Dictionary contextObjects); + internal abstract object getTrueValue((object, object) currentObject, Dictionary contextObjects); internal abstract bool validateResult(object res); - internal abstract void useResult(List actionList, Dictionary contextObjects, object res); + internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); internal abstract bool HandlesCommand(string command); } -internal abstract class MEOperation : METypelessOperation +internal abstract class MEOperation : METypelessOperation { internal Dictionary operations = new(); internal string name = "[Unnamed operation type]"; @@ -71,13 +71,13 @@ internal override Dictionary AllCommands() { return operations; } - internal MEOperationDef newCmd(string[] args, string wiki, Func func, Func show = null) + internal MEOperationDef newCmd(string[] args, string wiki, Func func, Func show = null) { - return new MEOperationDef(args, wiki, func, show); + return new MEOperationDef(args, wiki, func, show); } - internal MEOperationDef newCmd(string wiki, Func func, Func show) + internal MEOperationDef newCmd(string wiki, Func func, Func show) { - return new MEOperationDef(Array.Empty(), wiki, func, show); + return new MEOperationDef(Array.Empty(), wiki, func, show); } internal override string NameForHelpTexts() @@ -86,7 +86,7 @@ internal override string NameForHelpTexts() } } -internal class MEGlobalOperation : MEOperation +internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool> { internal static MEGlobalOperation globalOps = new(); @@ -126,7 +126,7 @@ internal override void Setup() }, () => CFG.Current.Param_AdvancedMassedit)); } - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { return true; //Global op technically has no context / uses the dummy context of boolean } @@ -136,13 +136,13 @@ internal override bool validateResult(object res) return true; } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { return; //Global ops, for now, don't use actions and simply execute effects themselves } } -internal class MERowOperation : MEOperation<(string, Param.Row), (Param, Param.Row)> +internal class MERowOperation : MEOperation<(string, Param.Row), (string, Param.Row), (Param, Param.Row)> { public static MERowOperation rowOps = new(); @@ -231,9 +231,9 @@ internal override void Setup() )); } - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { - return contextObjects[typeof((string, Param.Row))]; + return currentObject; } internal override bool validateResult(object res) @@ -246,14 +246,14 @@ internal override bool validateResult(object res) return true; } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { (Param p2, Param.Row rs) = ((Param, Param.Row))res; actionList.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); } } -internal abstract class MEValueOperation : MEOperation +internal abstract class MEValueOperation : MEOperation { internal override void Setup() { @@ -327,30 +327,30 @@ internal override bool validateResult(object res) internal class MECellOperation : MEValueOperation<(PseudoColumn, Param.Column)> { public static MECellOperation cellOps = new(); - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; - (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))contextObjects[typeof((PseudoColumn, Param.Column))]; + (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; return row.Get(col); } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; - (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))contextObjects[typeof((PseudoColumn, Param.Column))]; + (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; actionList.AppendParamEditAction(row, col, res); } } internal class MEVarOperation : MEValueOperation { public static MEVarOperation varOps = new(); - internal override object getTrueValue(Dictionary contextObjects) + internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { - return MassParamEdit.massEditVars[(string)contextObjects[typeof(string)].Item2]; + return MassParamEdit.massEditVars[(string)currentObject.Item2]; } - internal override void useResult(List actionList, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { - MassParamEdit.massEditVars[(string)contextObjects[typeof(string)].Item2] = res; + MassParamEdit.massEditVars[(string)currentObject.Item2] = res; } } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 102a58a73..db24b334f 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -278,15 +278,15 @@ private MassEditResult ParseOpStep(string stageText, string stageName, METypeles { return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {this.operation.command} (line {_currentLine})"); } - - var contextObjects = new Dictionary() { { typeof(bool), (true, true)} }; + var currentObj = (true, true); + var contextObjects = new Dictionary() { { typeof(bool), currentObj} }; if (filters.Count == 0) - return SandboxMassEditExecution(() => ExecOp(this.operation, this.operation.command, argFuncs, contextObjects, operation)); + return SandboxMassEditExecution(() => ExecOp(this.operation, this.operation.command, argFuncs, currentObj, contextObjects, operation)); else { MEFilterStage baseFilter = filters.Dequeue(); - return SandboxMassEditExecution(() => ExecStage(baseFilter, baseFilter.engine, (true, true), argFuncs, contextObjects)); + return SandboxMassEditExecution(() => ExecStage(baseFilter, baseFilter.engine, currentObj, contextObjects, argFuncs)); } throw new MEParseException("No initial stage or op was parsed", _currentLine); } @@ -303,7 +303,7 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, (object, object) contextObject, IEnumerable argFuncs, Dictionary contextObjects) + private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, (object, object) contextObject, Dictionary contextObjects, IEnumerable argFuncs) { var editCount = -1; foreach ((object, object) currentObject in engine.SearchNoType(contextObject, info.command, false, false)) @@ -317,11 +317,11 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine MassEditResult res; if (filters.Count == 0) - res = ExecOp(operation, operation.command, argFuncs, contextObjects, operation.operation); + res = ExecOp(operation, operation.command, argFuncs, currentObject, contextObjects, operation.operation); else { MEFilterStage nextFilterFilter = filters.Dequeue(); - res = ExecStage(nextFilterFilter, nextFilterFilter.engine, currentObject, newArgFuncs, contextObjects); + res = ExecStage(nextFilterFilter, nextFilterFilter.engine, currentObject, contextObjects, newArgFuncs); } if (res.Type != MassEditResultType.SUCCESS) { @@ -330,10 +330,10 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine } return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, Dictionary contextObjects, METypelessOperation opType) + private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var opResults = parsedOp.function(opType.getTrueValue(contextObjects), argValues); + var opResults = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); if (!opType.validateResult(opResults)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); From d06c701d1a686876cd2a0b64bc176e7f64a5a8ca Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 3 Apr 2024 01:21:42 +0100 Subject: [PATCH 35/61] Actually execute actions. Don't double-dequeue filterstages. --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index db24b334f..843ba3852 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -150,7 +150,7 @@ public class MassParamEditRegex private object[] argFuncs; METypelessOperationDef parsedOp; - Queue filters = new(); + List filters = new(); MEOperationStage operation; internal static ParamEditorSelectionState totalHackPleaseKillme = null; @@ -183,7 +183,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba currentEditData.context = context; totalHackPleaseKillme = context; - MassEditResult result = currentEditData.ParseAndExecCommand(command); + MassEditResult result = currentEditData.ParseCommand(command); if (result.Type != MassEditResultType.SUCCESS) { @@ -203,8 +203,7 @@ public static (MassEditResult, ActionManager child) PerformMassEdit(ParamBank ba return (new MassEditResult(MassEditResultType.PARSEERROR, e.ToString()), null); } } - - private MassEditResult ParseAndExecCommand(string command) + private MassEditResult ParseCommand(string command) { var stage = command.Split(":", 2); @@ -234,7 +233,7 @@ private MassEditResult ParseFilterStep(string stageText, TypelessSearchEngine ex { var stage = stageText.Split(":", 2); string stageName = expectedSearchEngine.NameForHelpTexts(); - filters.Enqueue(new MEFilterStage(stage[0], _currentLine, stageName, expectedSearchEngine)); + filters.Add(new MEFilterStage(stage[0], _currentLine, stageName, expectedSearchEngine)); if (stage.Length < 2) { @@ -285,8 +284,9 @@ private MassEditResult ParseOpStep(string stageText, string stageName, METypeles return SandboxMassEditExecution(() => ExecOp(this.operation, this.operation.command, argFuncs, currentObj, contextObjects, operation)); else { - MEFilterStage baseFilter = filters.Dequeue(); - return SandboxMassEditExecution(() => ExecStage(baseFilter, baseFilter.engine, currentObj, contextObjects, argFuncs)); + int filterDepth = 0; + MEFilterStage baseFilter = filters[filterDepth]; + return SandboxMassEditExecution(() => ExecStage(baseFilter, baseFilter.engine, filterDepth, currentObj, contextObjects, argFuncs)); } throw new MEParseException("No initial stage or op was parsed", _currentLine); } @@ -303,9 +303,10 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, (object, object) contextObject, Dictionary contextObjects, IEnumerable argFuncs) + private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, int filterDepth, (object, object) contextObject, Dictionary contextObjects, IEnumerable argFuncs) { var editCount = -1; + filterDepth++; foreach ((object, object) currentObject in engine.SearchNoType(contextObject, info.command, false, false)) { editCount++; @@ -316,29 +317,30 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine //exec it MassEditResult res; - if (filters.Count == 0) + if (filterDepth == filters.Count) res = ExecOp(operation, operation.command, argFuncs, currentObject, contextObjects, operation.operation); else { - MEFilterStage nextFilterFilter = filters.Dequeue(); - res = ExecStage(nextFilterFilter, nextFilterFilter.engine, currentObject, contextObjects, newArgFuncs); + MEFilterStage nextFilter = filters[filterDepth]; + res = ExecStage(nextFilter, nextFilter.engine, filterDepth, currentObject, contextObjects, newArgFuncs); } if (res.Type != MassEditResultType.SUCCESS) { return res; } } + return new MassEditResult(MassEditResultType.SUCCESS, ""); } private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var opResults = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); - if (!opType.validateResult(opResults)) + var opResult = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); + if (!opType.validateResult(opResult)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); } - _partialActions.Add(null);//TODO using opType + opType.UseResult(_partialActions, currentObject, contextObjects, opResult); return new MassEditResult(MassEditResultType.SUCCESS, ""); } } From f98ec56a8c9ce546518d457c8b7b33103738feda Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Mon, 15 Apr 2024 23:23:45 +0100 Subject: [PATCH 36/61] Screw up types and break stuff (to be fixed) --- .../Editor/MassEdit/EditOperation.cs | 166 ++++++++++-------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 5 +- 2 files changed, 95 insertions(+), 76 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index ed0262f68..1d66bf56e 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -16,16 +16,16 @@ internal abstract class METypelessOperationDef { internal string[] argNames; internal string wiki; - internal Func function; + internal Func function; internal Func shouldShow; } -internal class MEOperationDef : METypelessOperationDef +internal class MEOperationDef : METypelessOperationDef { - internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) + internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) { argNames = args; wiki = tooltip; - function = (x, str) => func((I)x, str); //Shitty wrapping perf loss + function = (o, f, str) => func(o, (I)f, str); //Shitty wrapping perf loss shouldShow = show; } } @@ -43,9 +43,10 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); + internal abstract object getTrueObj((object, object) currentObject, Dictionary contextObjects); internal abstract object getTrueValue((object, object) currentObject, Dictionary contextObjects); internal abstract bool validateResult(object res); - internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); + internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object context, object res); internal abstract bool HandlesCommand(string command); } internal abstract class MEOperation : METypelessOperation @@ -71,13 +72,13 @@ internal override Dictionary AllCommands() { return operations; } - internal MEOperationDef newCmd(string[] args, string wiki, Func func, Func show = null) + internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) { - return new MEOperationDef(args, wiki, func, show); + operations.Add(command, new MEOperationDef(args, wiki, func, show)); } - internal MEOperationDef newCmd(string wiki, Func func, Func show) + internal void NewCmd(string command, string wiki, Func func, Func show = null) { - return new MEOperationDef(Array.Empty(), wiki, func, show); + NewCmd(command, Array.Empty(), wiki, func, show); } internal override string NameForHelpTexts() @@ -93,14 +94,14 @@ internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool> internal override void Setup() { name = "global"; - operations.Add("clear", newCmd(new string[0], "Clears clipboard param and rows", (selectionState, args) => + NewCmd("clear", new string[0], "Clears clipboard param and rows", (dummy, selectionState, args) => { ParamBank.ClipboardParam = null; ParamBank.ClipboardRows.Clear(); return true; - })); - operations.Add("newvar", newCmd(new[] { "variable name", "value" }, - "Creates a variable with the given value, and the type of that value", (selectionState, args) => + }); + NewCmd("newvar", new[] { "variable name", "value" }, + "Creates a variable with the given value, and the type of that value", (dummy, selectionState, args) => { int asInt; double asDouble; @@ -118,14 +119,17 @@ internal override void Setup() } return true; - }, () => CFG.Current.Param_AdvancedMassedit)); - operations.Add("clearvars", newCmd(new string[0], "Deletes all variables", (selectionState, args) => + }, () => CFG.Current.Param_AdvancedMassedit); + NewCmd("clearvars", new string[0], "Deletes all variables", (dummy, selectionState, args) => { MassParamEdit.massEditVars.Clear(); return true; - }, () => CFG.Current.Param_AdvancedMassedit)); + }, () => CFG.Current.Param_AdvancedMassedit); + } + internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) + { + return true; //Global op technically has no context / uses the dummy context of boolean } - internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { return true; //Global op technically has no context / uses the dummy context of boolean @@ -136,7 +140,7 @@ internal override bool validateResult(object res) return true; } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) { return; //Global ops, for now, don't use actions and simply execute effects themselves } @@ -149,12 +153,12 @@ internal class MERowOperation : MEOperation<(string, Param.Row), (string, Param. internal override void Setup() { name = "row"; - operations.Add("copy", newCmd(new string[0], + NewCmd("copy", new string[0], "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", - (paramAndRow, args) => + (param, rowPair, args) => { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; + var paramKey = (string)param; + Param.Row row = rowPair.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -176,13 +180,13 @@ internal override void Setup() ParamBank.ClipboardRows.Add(new Param.Row(row, p)); return (p, null); } - )); - operations.Add("copyN", newCmd(new[] { "count" }, + ); + NewCmd("copyN", new[] { "count" }, "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", - (paramAndRow, args) => + (param, rowPair, args) => { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; + var paramKey = (string)param; + Param.Row row = rowPair.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -208,13 +212,13 @@ internal override void Setup() } return (p, null); - }, () => CFG.Current.Param_AdvancedMassedit)); - operations.Add("paste", newCmd(new string[0], + }, () => CFG.Current.Param_AdvancedMassedit); + NewCmd("paste", new string[0], "Adds the selected rows to the primary regulation or parambnd in the selected param", - (paramAndRow, args) => + (param, rowPair, args) => { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; + var paramKey = (string)param; + Param.Row row = rowPair.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -228,12 +232,15 @@ internal override void Setup() Param p = ParamBank.PrimaryBank.Params[paramKey]; return (p, new Param.Row(row, p)); } - )); + ); + } + internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) + { + return currentObject.Item1; } - internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { - return currentObject; + return currentObject.Item2; } internal override bool validateResult(object res) @@ -246,8 +253,9 @@ internal override bool validateResult(object res) return true; } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) { + //use Param from result as this may be different to original Param obj (Param p2, Param.Row rs) = ((Param, Param.Row))res; actionList.Add(new AddParamsAction(p2, "FromMassEdit", new List { rs }, false, true)); } @@ -258,13 +266,13 @@ internal abstract class MEValueOperation : MEOperation internal override void Setup() { name = "value"; - operations.Add("=", - newCmd(new[] { "number or text" }, + NewCmd("=", + new[] { "number or text" }, "Assigns the given value to the selected values. Will attempt conversion to the value's data type", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => args[0]))); - operations.Add("+", newCmd(new[] { "number or text" }, + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => args[0])); + NewCmd("+", new[] { "number or text" }, "Adds the number to the selected values, or appends text if that is the data type of the values", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => { double val; if (double.TryParse(args[0], out val)) @@ -273,48 +281,48 @@ internal override void Setup() } return v + args[0]; - }))); - operations.Add("-", - newCmd(new[] { "number" }, "Subtracts the number from the selected values", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v - double.Parse(args[0])))); - operations.Add("*", - newCmd(new[] { "number" }, "Multiplies selected values by the number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v * double.Parse(args[0])))); - operations.Add("/", - newCmd(new[] { "number" }, "Divides the selected values by the number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v / double.Parse(args[0])))); - operations.Add("%", - newCmd(new[] { "number" }, "Gives the remainder when the selected values are divided by the number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v % double.Parse(args[0])), () => CFG.Current.Param_AdvancedMassedit)); - operations.Add("scale", newCmd(new[] { "factor number", "center number" }, + })); + NewCmd("-", + new[] { "number" }, "Subtracts the number from the selected values", + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v - double.Parse(args[0]))); + NewCmd("*", + new[] { "number" }, "Multiplies selected values by the number", + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v * double.Parse(args[0]))); + NewCmd("/", + new[] { "number" }, "Divides the selected values by the number", + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v / double.Parse(args[0]))); + NewCmd("%", + new[] { "number" }, "Gives the remainder when the selected values are divided by the number", + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v % double.Parse(args[0])), () => CFG.Current.Param_AdvancedMassedit); + NewCmd("scale", new[] { "factor number", "center number" }, "Multiplies the difference between the selected values and the center number by the factor number", - (ctx, args) => + (value, ctx, args) => { var opp1 = double.Parse(args[0]); var opp2 = double.Parse(args[1]); - return MassParamEdit.WithDynamicOf(ctx, v => + return MassParamEdit.WithDynamicOf(value, v => { return ((v - opp2) * opp1) + opp2; }); } - )); - operations.Add("replace", - newCmd(new[] { "text to replace", "new text" }, + ); + NewCmd("replace", + new[] { "text to replace", "new text" }, "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => v.Replace(args[0], args[1])))); - operations.Add("replacex", newCmd(new[] { "text to replace (regex)", "new text (w/ groups)" }, + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v.Replace(args[0], args[1]))); + NewCmd("replacex", new[] { "text to replace (regex)", "new text (w/ groups)" }, "Interprets the selected values as text and replaces all occurances of the given regex with the replacement, supporting regex groups", - (ctx, args) => + (ctx, value, args) => { Regex rx = new(args[0]); - return MassParamEdit.WithDynamicOf(ctx, v => rx.Replace(v, args[1])); - }, () => CFG.Current.Param_AdvancedMassedit)); - operations.Add("max", - newCmd(new[] { "number" }, "Returns the larger of the current value and number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Max(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit)); - operations.Add("min", - newCmd(new[] { "number" }, "Returns the smaller of the current value and number", - (ctx, args) => MassParamEdit.WithDynamicOf(ctx, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit)); + return MassParamEdit.WithDynamicOf(value, v => rx.Replace(v, args[1])); + }, () => CFG.Current.Param_AdvancedMassedit); + NewCmd("max", + new[] { "number" }, "Returns the larger of the current value and number", + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Max(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); + NewCmd("min", + new[] { "number" }, "Returns the smaller of the current value and number", + (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); } internal override bool validateResult(object res) @@ -327,15 +335,20 @@ internal override bool validateResult(object res) internal class MECellOperation : MEValueOperation<(PseudoColumn, Param.Column)> { public static MECellOperation cellOps = new(); + internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) + { + (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; + return currentObject; + } internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; return row.Get(col); } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) { - (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; + Param.Row row = (Param.Row) obj; (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; actionList.AppendParamEditAction(row, col, res); } @@ -343,12 +356,17 @@ internal override void UseResult(List actionList, (object, object) internal class MEVarOperation : MEValueOperation { public static MEVarOperation varOps = new(); + + internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) + { + return (string)currentObject.Item2; + } internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) { return MassParamEdit.massEditVars[(string)currentObject.Item2]; } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) { MassParamEdit.massEditVars[(string)currentObject.Item2] = res; } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 843ba3852..e29442ba5 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -335,12 +335,13 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - var opResult = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); + object ctxObj = opType.getTrueObj(currentObject, contextObjects); + var opResult = parsedOp.function(ctxObj, opType.getTrueValue(currentObject, contextObjects), argValues);//TODO NOTNULL IT if (!opType.validateResult(opResult)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); } - opType.UseResult(_partialActions, currentObject, contextObjects, opResult); + opType.UseResult(_partialActions, currentObject, contextObjects, ctxObj, opResult); return new MassEditResult(MassEditResultType.SUCCESS, ""); } } From 422d216d70f2f418c54ceadfedeb859889ea7753 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Mon, 15 Apr 2024 23:33:17 +0100 Subject: [PATCH 37/61] CollectionExpressions --- .../Editor/MassEdit/EditOperation.cs | 78 +++++++++---------- .../Editor/MassEdit/SearchEngine.cs | 68 ++++++++-------- 2 files changed, 70 insertions(+), 76 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 1d66bf56e..81cc63001 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -76,10 +76,6 @@ internal void NewCmd(string command, string[] args, string wiki, Func(args, wiki, func, show)); } - internal void NewCmd(string command, string wiki, Func func, Func show = null) - { - NewCmd(command, Array.Empty(), wiki, func, show); - } internal override string NameForHelpTexts() { @@ -94,13 +90,13 @@ internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool> internal override void Setup() { name = "global"; - NewCmd("clear", new string[0], "Clears clipboard param and rows", (dummy, selectionState, args) => + NewCmd("clear", [], "Clears clipboard param and rows", (dummy, selectionState, args) => { ParamBank.ClipboardParam = null; ParamBank.ClipboardRows.Clear(); return true; }); - NewCmd("newvar", new[] { "variable name", "value" }, + NewCmd("newvar", ["variable name", "value"], "Creates a variable with the given value, and the type of that value", (dummy, selectionState, args) => { int asInt; @@ -120,7 +116,7 @@ internal override void Setup() return true; }, () => CFG.Current.Param_AdvancedMassedit); - NewCmd("clearvars", new string[0], "Deletes all variables", (dummy, selectionState, args) => + NewCmd("clearvars", [], "Deletes all variables", (dummy, selectionState, args) => { MassParamEdit.massEditVars.Clear(); return true; @@ -153,7 +149,7 @@ internal class MERowOperation : MEOperation<(string, Param.Row), (string, Param. internal override void Setup() { name = "row"; - NewCmd("copy", new string[0], + NewCmd("copy", [], "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", (param, rowPair, args) => { @@ -181,7 +177,7 @@ internal override void Setup() return (p, null); } ); - NewCmd("copyN", new[] { "count" }, + NewCmd("copyN", ["count"], "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", (param, rowPair, args) => { @@ -213,7 +209,7 @@ internal override void Setup() return (p, null); }, () => CFG.Current.Param_AdvancedMassedit); - NewCmd("paste", new string[0], + NewCmd("paste", [], "Adds the selected rows to the primary regulation or parambnd in the selected param", (param, rowPair, args) => { @@ -267,10 +263,10 @@ internal override void Setup() { name = "value"; NewCmd("=", - new[] { "number or text" }, + ["number or text"], "Assigns the given value to the selected values. Will attempt conversion to the value's data type", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => args[0])); - NewCmd("+", new[] { "number or text" }, + NewCmd("+", ["number or text"], "Adds the number to the selected values, or appends text if that is the data type of the values", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => { @@ -283,18 +279,18 @@ internal override void Setup() return v + args[0]; })); NewCmd("-", - new[] { "number" }, "Subtracts the number from the selected values", + ["number"], "Subtracts the number from the selected values", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v - double.Parse(args[0]))); NewCmd("*", - new[] { "number" }, "Multiplies selected values by the number", + ["number"], "Multiplies selected values by the number", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v * double.Parse(args[0]))); NewCmd("/", - new[] { "number" }, "Divides the selected values by the number", + ["number"], "Divides the selected values by the number", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v / double.Parse(args[0]))); NewCmd("%", - new[] { "number" }, "Gives the remainder when the selected values are divided by the number", + ["number"], "Gives the remainder when the selected values are divided by the number", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v % double.Parse(args[0])), () => CFG.Current.Param_AdvancedMassedit); - NewCmd("scale", new[] { "factor number", "center number" }, + NewCmd("scale", ["factor number", "center number"], "Multiplies the difference between the selected values and the center number by the factor number", (value, ctx, args) => { @@ -310,7 +306,7 @@ internal override void Setup() new[] { "text to replace", "new text" }, "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v.Replace(args[0], args[1]))); - NewCmd("replacex", new[] { "text to replace (regex)", "new text (w/ groups)" }, + NewCmd("replacex", ["text to replace (regex)", "new text (w/ groups)"], "Interprets the selected values as text and replaces all occurances of the given regex with the replacement, supporting regex groups", (ctx, value, args) => { @@ -318,10 +314,10 @@ internal override void Setup() return MassParamEdit.WithDynamicOf(value, v => rx.Replace(v, args[1])); }, () => CFG.Current.Param_AdvancedMassedit); NewCmd("max", - new[] { "number" }, "Returns the larger of the current value and number", + ["number"], "Returns the larger of the current value and number", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Max(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); NewCmd("min", - new[] { "number" }, "Returns the smaller of the current value and number", + ["number"], "Returns the smaller of the current value and number", (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); } @@ -403,14 +399,14 @@ private OperationArgumentGetter newGetter(string[] args, string wiki, private void Setup() { - defaultGetter = newGetter(new string[0], "Gives the specified value", + defaultGetter = newGetter([], "Gives the specified value", value => (i, c) => value[0]); argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", empty => (j, row) => (k, col) => { return row.Get(col).ToParamEditorString(); })); - argumentGetters.Add("field", newGetter(new[] { "field internalName" }, + argumentGetters.Add("field", newGetter(["field internalName"], "Gives the value of the given cell/field for the currently selected row and param", field => (i, param) => { @@ -426,7 +422,7 @@ private void Setup() return v; }; })); - argumentGetters.Add("vanilla", newGetter(new string[0], + argumentGetters.Add("vanilla", newGetter([], "Gives the value of the equivalent cell/field in the vanilla regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", empty => { @@ -460,7 +456,7 @@ private void Setup() }; }; })); - argumentGetters.Add("aux", newGetter(new[] { "parambank name" }, + argumentGetters.Add("aux", newGetter(["parambank name"], "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankName => { @@ -499,7 +495,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, + argumentGetters.Add("vanillafield", newGetter(["field internalName"], "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", field => (i, param) => { @@ -528,7 +524,7 @@ private void Setup() return v; }; })); - argumentGetters.Add("auxfield", newGetter(new[] { "parambank name", "field internalName" }, + argumentGetters.Add("auxfield", newGetter(["parambank name", "field internalName"], "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankAndField => { @@ -566,7 +562,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, + argumentGetters.Add("paramlookup", newGetter(["param name", "row id", "field name"], "Returns the specific value specified by the exact param, row and field.", address => { Param param = ParamBank.PrimaryBank.Params[address[0]]; @@ -582,7 +578,7 @@ private void Setup() var value = row.Get(field).ToParamEditorString(); return (i, c) => value; }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("average", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("average", newGetter(["field internalName", "row selector"], "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { @@ -604,7 +600,7 @@ private void Setup() var avg = vals.Average(val => Convert.ToDouble(val)); return avg.ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("median", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("median", newGetter(["field internalName", "row selector"], "Gives the median value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { @@ -620,7 +616,7 @@ private void Setup() var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("mode", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("mode", newGetter(["field internalName", "row selector"], "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { @@ -636,7 +632,7 @@ private void Setup() .First().Item1; return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("min", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("min", newGetter(["field internalName", "row selector"], "Gives the smallest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { @@ -651,7 +647,7 @@ private void Setup() var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("max", newGetter(new[] { "field internalName", "row selector" }, + argumentGetters.Add("max", newGetter(["field internalName", "row selector"], "Gives the largest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { @@ -667,7 +663,7 @@ private void Setup() return max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); argumentGetters.Add("random", newGetter( - new[] { "minimum number (inclusive)", "maximum number (exclusive)" }, + ["minimum number (inclusive)", "maximum number (exclusive)"], "Gives a random decimal number between the given values for each selected value", minAndMax => { double min; @@ -686,7 +682,7 @@ private void Setup() return (i, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); argumentGetters.Add("randint", newGetter( - new[] { "minimum integer (inclusive)", "maximum integer (inclusive)" }, + ["minimum integer (inclusive)", "maximum integer (inclusive)"], "Gives a random integer between the given values for each selected value", minAndMax => { int min; @@ -703,7 +699,7 @@ private void Setup() return (i, c) => Random.Shared.NextInt64(min, max + 1).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randFrom", newGetter(new[] { "param name", "field internalName", "row selector" }, + argumentGetters.Add("randFrom", newGetter(["param name", "field internalName", "row selector"], "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", paramFieldRowSelector => { @@ -713,19 +709,19 @@ private void Setup() var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("paramIndex", newGetter(new string[0], + argumentGetters.Add("paramIndex", newGetter([], "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", empty => (i, param) => { return i.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("rowIndex", newGetter(new string[0], + argumentGetters.Add("rowIndex", newGetter([], "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", empty => (j, row) => { return j.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("fieldIndex", newGetter<(PseudoColumn, Param.Column)>(new string[0], + argumentGetters.Add("fieldIndex", newGetter<(PseudoColumn, Param.Column)>([], "Gives an integer for the current selected cell/field, beginning at 0 and increasing by 1 for each cell/field selected", empty => (k, col) => { @@ -761,7 +757,7 @@ private void Setup() internal object[] getContextualArguments(int argumentCount, string opData) { - var opArgs = opData == null ? new string[0] : opData.Split(':', argumentCount); + var opArgs = opData == null ? [] : opData.Split(':', argumentCount); var contextualArgs = new object[opArgs.Length]; for (var i = 0; i < opArgs.Length; i++) { @@ -787,7 +783,7 @@ internal object getContextualArgumentFromArgs(string opArg) if (argumentGetters.ContainsKey(arg[0].Trim())) { OperationArgumentGetter getter = argumentGetters[arg[0]]; - var opArgArgs = arg.Length > 1 ? arg[1].Split(" ", getter.args.Length) : new string[0]; + var opArgArgs = arg.Length > 1 ? arg[1].Split(" ", getter.args.Length) : []; if (opArgArgs.Length != getter.args.Length) { throw new MEOperationException( @@ -805,7 +801,7 @@ internal object getContextualArgumentFromArgs(string opArg) return getter.func(opArgArgs); } - return defaultGetter.func(new[] { opArg }); + return defaultGetter.func([opArg]); } } diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index cb8d426ca..0c67cca48 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -58,7 +58,7 @@ internal SearchEngine() protected void addExistsFilter() { - filterList.Add("exists", newCmd(new string[0], "Selects all elements", noArgs(noContext(b => true)))); + filterList.Add("exists", newCmd([], "Selects all elements", noArgs(noContext(b => true)))); } protected Func>> noArgs(Func<(CO, CF), Func<(EO, EF), bool>> func) @@ -279,7 +279,7 @@ internal override void Setup() string param = MassParamEditRegex.totalHackPleaseKillme.GetActiveParam(); return MassParamEditRegex.totalHackPleaseKillme.GetSelectedRows().Select((x) => (param, x)).ToList(); }; - filterList.Add("selection", newCmd(new string[0], + filterList.Add("selection", newCmd([], "Selects param rows selected in the current param window", noArgs(noContext(param => true)))); } @@ -295,7 +295,7 @@ internal override void Setup() string param = ParamBank.ClipboardParam; return ParamBank.ClipboardRows.Select((x) => (param, x)).ToList(); }; - filterList.Add("clipboard", newCmd(new string[0], + filterList.Add("clipboard", newCmd([], "Selects param rows copied in the clipboard", noArgs(noContext(param => true)))); } @@ -317,7 +317,7 @@ internal override void Setup() unpacker = dummy => ParamBank.AuxBanks.Select((aux, i) => aux.Value.Params.Select((x, i) => (aux.Value, x.Value))) .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).Select((x, i) => (x.bank, x.x)).ToList(); - filterList.Add("modified", newCmd(new string[0], + filterList.Add("modified", newCmd([], "Selects params where any rows do not match the vanilla version, or where any are added. Ignores row names", noArgs(noContext(param => { @@ -329,7 +329,7 @@ internal override void Setup() HashSet cache = bank.GetVanillaDiffRows(bank.GetKeyForParam(param.Item2)); return cache.Count > 0; })))); - filterList.Add("param", newCmd(new[] { "param name (regex)" }, + filterList.Add("param", newCmd(["param name (regex)"], "Selects all params whose name matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[0], RegexOptions.IgnoreCase) : new Regex($@"^{args[0]}$"); @@ -340,7 +340,7 @@ internal override void Setup() ? "" : bank.GetKeyForParam(param.Item2))); })); - filterList.Add("auxparam", newCmd(new[] { "parambank name", "param name (regex)" }, + filterList.Add("auxparam", newCmd(["parambank name", "param name (regex)"], "Selects params from the specified regulation or parambnd where the param name matches the given regex", (args, lenient) => { @@ -353,7 +353,7 @@ internal override void Setup() ? "" : auxBank.GetKeyForParam(param.Item2))); }, () => ParamBank.AuxBanks.Count > 0 && CFG.Current.Param_AdvancedMassedit)); - defaultFilter = newCmd(new[] { "param name (regex)" }, + defaultFilter = newCmd(["param name (regex)"], "Selects all params whose name matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[0], RegexOptions.IgnoreCase) : new Regex($@"^{args[0]}$"); @@ -385,7 +385,7 @@ internal override void Setup() string name = param.Item1.GetKeyForParam(param.Item2); return param.Item2.Rows.Select((x, i) => (name, x)).ToList(); }; - filterList.Add("modified", newCmd(new string[0], + filterList.Add("modified", newCmd([], "Selects rows which do not match the vanilla version, or are added. Ignores row name", noArgs(context => { var paramName = context.Item1.GetKeyForParam(context.Item2); @@ -393,7 +393,7 @@ internal override void Setup() return row => cache.Contains(row.Item2.ID); } ))); - filterList.Add("added", newCmd(new string[0], "Selects rows where the ID is not found in the vanilla param", + filterList.Add("added", newCmd([], "Selects rows where the ID is not found in the vanilla param", noArgs(context => { var paramName = context.Item1.GetKeyForParam(context.Item2); @@ -406,7 +406,7 @@ internal override void Setup() return row => vanilParam[row.Item2.ID] == null; } ))); - filterList.Add("mergeable", newCmd(new string[0], + filterList.Add("mergeable", newCmd([], "Selects rows which are not modified in the primary regulation or parambnd and there is exactly one equivalent row in another regulation or parambnd that is modified", noArgs(context => { @@ -424,7 +424,7 @@ internal override void Setup() auxCaches.Where(x => x.Item2.Contains(row.Item2.ID) && x.Item1.Contains(row.Item2.ID)).Count() == 1; } ), () => ParamBank.AuxBanks.Count > 0)); - filterList.Add("conflicts", newCmd(new string[0], + filterList.Add("conflicts", newCmd([], "Selects rows which, among all equivalents in the primary and additional regulations or parambnds, there is more than row 1 which is modified", noArgs(context => { @@ -437,26 +437,26 @@ internal override void Setup() .Where(x => x.Item2.Contains(row.Item2.ID) && x.Item1.Contains(row.Item2.ID)).Count() > 1; } ), () => ParamBank.AuxBanks.Count > 0)); - filterList.Add("id", newCmd(new[] { "row id (regex)" }, "Selects rows whose ID matches the given regex", + filterList.Add("id", newCmd(["row id (regex)"], "Selects rows whose ID matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[0].ToLower()) : new Regex($@"^{args[0]}$"); return noContext(row => rx.IsMatch(row.Item2.ID.ToString())); })); - filterList.Add("idrange", newCmd(new[] { "row id minimum (inclusive)", "row id maximum (inclusive)" }, + filterList.Add("idrange", newCmd(["row id minimum (inclusive)", "row id maximum (inclusive)"], "Selects rows whose ID falls in the given numerical range", (args, lenient) => { var floor = double.Parse(args[0]); var ceil = double.Parse(args[1]); return noContext(row => row.Item2.ID >= floor && row.Item2.ID <= ceil); })); - filterList.Add("name", newCmd(new[] { "row name (regex)" }, + filterList.Add("name", newCmd(["row name (regex)"], "Selects rows whose Name matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[0], RegexOptions.IgnoreCase) : new Regex($@"^{args[0]}$"); return noContext(row => rx.IsMatch(row.Item2.Name == null ? "" : row.Item2.Name)); })); - filterList.Add("prop", newCmd(new[] { "field internalName", "field value (regex)" }, + filterList.Add("prop", newCmd(["field internalName", "field value (regex)"], "Selects rows where the specified field has a value that matches the given regex", (args, lenient) => { Regex rx = lenient ? new Regex(args[1], RegexOptions.IgnoreCase) : new Regex($@"^{args[1]}$"); @@ -475,7 +475,7 @@ internal override void Setup() }); })); filterList.Add("proprange", newCmd( - new[] { "field internalName", "field value minimum (inclusive)", "field value maximum (inclusive)" }, + ["field internalName", "field value minimum (inclusive)", "field value maximum (inclusive)"], "Selects rows where the specified field has a value that falls in the given numerical range", (args, lenient) => { @@ -493,7 +493,7 @@ internal override void Setup() return Convert.ToDouble(c.Value.Value) >= floor && Convert.ToDouble(c.Value.Value) <= ceil; }); })); - filterList.Add("propref", newCmd(new[] { "field internalName", "referenced row name (regex)" }, + filterList.Add("propref", newCmd(["field internalName", "referenced row name (regex)"], "Selects rows where the specified field that references another param has a value referencing a row whose name matches the given regex", (args, lenient) => { @@ -526,7 +526,7 @@ internal override void Setup() }; }; }, () => CFG.Current.Param_AdvancedMassedit)); - filterList.Add("propwhere", newCmd(new[] { "field internalName", "cell/field selector" }, + filterList.Add("propwhere", newCmd(["field internalName", "cell/field selector"], "Selects rows where the specified field appears when the given cell/field search is given", (args, lenient) => { @@ -546,7 +546,7 @@ internal override void Setup() }; }; }, () => CFG.Current.Param_AdvancedMassedit)); - filterList.Add("fmg", newCmd(new[] { "fmg title (regex)" }, + filterList.Add("fmg", newCmd(["fmg title (regex)"], "Selects rows which have an attached FMG and that FMG's text matches the given regex", (args, lenient) => { @@ -589,7 +589,7 @@ internal override void Setup() }; }; }, () => CFG.Current.Param_AdvancedMassedit)); - filterList.Add("vanillaprop", newCmd(new[] { "field internalName", "field value (regex)" }, + filterList.Add("vanillaprop", newCmd(["field internalName", "field value (regex)"], "Selects rows where the vanilla equivilent of that row has a value for the given field that matches the given regex", (args, lenient) => { @@ -619,7 +619,7 @@ internal override void Setup() }; }, () => CFG.Current.Param_AdvancedMassedit)); filterList.Add("vanillaproprange", newCmd( - new[] { "field internalName", "field value minimum (inclusive)", "field value maximum (inclusive)" }, + ["field internalName", "field value minimum (inclusive)", "field value maximum (inclusive)"], "Selects rows where the vanilla equivilent of that row has a value for the given field that falls in the given numerical range", (args, lenient) => { @@ -647,7 +647,7 @@ internal override void Setup() }; }; }, () => CFG.Current.Param_AdvancedMassedit)); - filterList.Add("auxprop", newCmd(new[] { "parambank name", "field internalName", "field value (regex)" }, + filterList.Add("auxprop", newCmd(["parambank name", "field internalName", "field value (regex)"], "Selects rows where the equivilent of that row in the given regulation or parambnd has a value for the given field that matches the given regex.\nCan be used to determine if an aux row exists.", (args, lenient) => { @@ -683,11 +683,10 @@ internal override void Setup() }; }, () => ParamBank.AuxBanks.Count > 0 && CFG.Current.Param_AdvancedMassedit)); filterList.Add("auxproprange", newCmd( - new[] - { + [ "parambank name", "field internalName", "field value minimum (inclusive)", "field value maximum (inclusive)" - }, + ], "Selects rows where the equivilent of that row in the given regulation or parambnd has a value for the given field that falls in the given range", (args, lenient) => { @@ -718,11 +717,10 @@ internal override void Setup() }, () => ParamBank.AuxBanks.Count > 0 && CFG.Current.Param_AdvancedMassedit)); filterList.Add("semijoin", newCmd( - new[] - { + [ "this field internalName", "other param", "other param field internalName", "other param row search" - }, + ], "Selects all rows where the value of a given field is any of the values in the second given field found in the given param using the given row selector", (args, lenient) => { @@ -761,7 +759,7 @@ internal override void Setup() }; }; }, () => CFG.Current.Param_AdvancedMassedit)); - filterList.Add("unique", newCmd(new string[] { "field" }, "Selects all rows where the value in the given field is unique", (args, lenient) => + filterList.Add("unique", newCmd(["field"], "Selects all rows where the value in the given field is unique", (args, lenient) => { string field = args[0].Replace(@"\s", " "); return (param) => @@ -777,7 +775,7 @@ internal override void Setup() }; }; }, () => CFG.Current.Param_AdvancedMassedit)); - defaultFilter = newCmd(new[] { "row ID or Name (regex)" }, + defaultFilter = newCmd(["row ID or Name (regex)"], "Selects rows where either the ID or Name matches the given regex, except in strict/massedit mode", (args, lenient) => { @@ -848,7 +846,7 @@ internal override void Setup() list.AddRange(row.Item2.Columns.Select((cell, i) => (PseudoColumn.None, cell))); return list; }; - defaultFilter = newCmd(new[] { "field internalName (regex)" }, + defaultFilter = newCmd(["field internalName (regex)"], "Selects cells/fields where the internal name of that field matches the given regex", (args, lenient) => { var matchID = args[0] == "ID"; @@ -883,7 +881,7 @@ internal override void Setup() return false; }); }); - filterList.Add("modified", newCmd(new string[0], + filterList.Add("modified", newCmd([], "Selects cells/fields where the equivalent cell in the vanilla regulation or parambnd has a different value", (args, lenient) => row => { @@ -912,7 +910,7 @@ internal override void Setup() return ParamUtils.IsValueDiff(ref valA, ref valB, (col.Item1, col.Item2).GetColumnType()); }; })); - filterList.Add("auxmodified", newCmd(new[] { "parambank name" }, + filterList.Add("auxmodified", newCmd(["parambank name"], "Selects cells/fields where the equivalent cell in the specified regulation or parambnd has a different value", (args, lenient) => { @@ -963,7 +961,7 @@ internal override void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - filterList.Add("sftype", newCmd(new[] { "paramdef type" }, + filterList.Add("sftype", newCmd(["paramdef type"], "Selects cells/fields where the field's data type, as enumerated by soulsformats, matches the given regex", (args, lenient) => { @@ -985,7 +983,7 @@ internal override void Setup() { return MassParamEdit.massEditVars.Keys.Select(x => (true, x)).ToList(); }; - filterList.Add("vars", newCmd(new[] { "variable names (regex)" }, + filterList.Add("vars", newCmd(["variable names (regex)"], "Selects variables whose name matches the given regex", (args, lenient) => { if (args[0].StartsWith('$')) From a0a14c28e2cd29911e70bae5538cc02a6bee70c8 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 16 Apr 2024 00:06:25 +0100 Subject: [PATCH 38/61] Rename all generics for clarity --- .../Editor/MassEdit/EditOperation.cs | 30 ++++---- .../Editor/MassEdit/SearchEngine.cs | 69 +++++++++---------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 81cc63001..228642b02 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -19,22 +19,22 @@ internal abstract class METypelessOperationDef internal Func function; internal Func shouldShow; } -internal class MEOperationDef : METypelessOperationDef +internal class MEOperationDef : METypelessOperationDef { - internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) + internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) { argNames = args; wiki = tooltip; - function = (o, f, str) => func(o, (I)f, str); //Shitty wrapping perf loss + function = (o, f, str) => func(o, (TInput)f, str); //Shitty wrapping perf loss shouldShow = show; } } internal abstract class METypelessOperation { private static Dictionary editOperations = new(); - internal static void AddEditOperation(MEOperation engine) + internal static void AddEditOperation(MEOperation engine) { - editOperations[typeof(R)] = engine; + editOperations[typeof(TMECategory)] = engine; } internal static METypelessOperation GetEditOperation(Type t) { @@ -49,7 +49,7 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object context, object res); internal abstract bool HandlesCommand(string command); } -internal abstract class MEOperation : METypelessOperation +internal abstract class MEOperation : METypelessOperation { internal Dictionary operations = new(); internal string name = "[Unnamed operation type]"; @@ -72,9 +72,9 @@ internal override Dictionary AllCommands() { return operations; } - internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) + internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) { - operations.Add(command, new MEOperationDef(args, wiki, func, show)); + operations.Add(command, new MEOperationDef(args, wiki, func, show)); } internal override string NameForHelpTexts() @@ -257,7 +257,7 @@ internal override void UseResult(List actionList, (object, object) } } -internal abstract class MEValueOperation : MEOperation +internal abstract class MEValueOperation : MEOperation { internal override void Setup() { @@ -378,20 +378,20 @@ private MEOperationArgument() { Setup(); } - private OperationArgumentGetter newGetter

(string[] args, string wiki, - Func> + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); } - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func>> + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); } - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func>>> + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>>> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 0c67cca48..60713170f 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -18,23 +18,20 @@ namespace StudioCore.Editor.MassEdit; internal abstract class TypelessSearchEngine { private static Dictionary> searchEngines = new(); - internal static void AddSearchEngine(SearchEngine engine) + internal static void AddSearchEngine(SearchEngine engine) { - if (!searchEngines.ContainsKey(typeof((CO, CF)))) - searchEngines.Add(typeof((CO, CF)), new()); - searchEngines[typeof((CO, CF))].Add((engine, typeof((EO, EF)))); + if (!searchEngines.ContainsKey(typeof((TContextObject, TContextField)))) + searchEngines.Add(typeof((TContextObject, TContextField)), new()); + searchEngines[typeof((TContextObject, TContextField))].Add((engine, typeof((TElementObject, TElementField)))); } - internal static List<(TypelessSearchEngine, Type)> GetSearchEngines(Type t) + internal static List<(TypelessSearchEngine, Type)> GetSearchEngines(Type t) //Type t is expected to be (TContextObject, TContextField) { - var list = searchEngines.GetValueOrDefault(t); - if (list == null) - list = new List<(TypelessSearchEngine, Type)>(); - return list; + return searchEngines.GetValueOrDefault(t) ?? ([]); } internal abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); internal abstract List<(string, string[])> AllCommands(); internal abstract List AvailableCommandsForHelpText(); - internal abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); + internal abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); //Type t is expected to be (TContextObject, TContextField) internal abstract METypelessOperation NextOperation(); internal abstract string NameForHelpTexts(); internal abstract Type getContainerType(); @@ -42,12 +39,12 @@ internal static void AddSearchEngine(SearchEngine SearchNoType((object, object) container, string command, bool lenient, bool failureAllOrNone); internal abstract bool HandlesCommand(string command); } -internal class SearchEngine : TypelessSearchEngine +internal class SearchEngine : TypelessSearchEngine { - internal SearchEngineCommand<(CO, CF), (EO, EF)> defaultFilter; + internal SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)> defaultFilter; - internal Dictionary> filterList = new(); - internal Func<(CO, CF), List<(EO, EF)>> unpacker; + internal Dictionary> filterList = new(); + internal Func<(TContextObject, TContextField), List<(TElementObject, TElementField)>> unpacker; internal string name = "[unnamed search engine]"; internal SearchEngine() @@ -61,12 +58,12 @@ protected void addExistsFilter() filterList.Add("exists", newCmd([], "Selects all elements", noArgs(noContext(b => true)))); } - protected Func>> noArgs(Func<(CO, CF), Func<(EO, EF), bool>> func) + protected Func>> noArgs(Func<(TContextObject, TContextField), Func<(TElementObject, TElementField), bool>> func) { return (args, lenient) => func; } - protected Func<(CO, CF), Func<(EO, EF), bool>> noContext(Func<(EO, EF), bool> func) + protected Func<(TContextObject, TContextField), Func<(TElementObject, TElementField), bool>> noContext(Func<(TElementObject, TElementField), bool> func) { return context => func; } @@ -75,10 +72,10 @@ internal virtual void Setup() { } - internal SearchEngineCommand<(CO, CF), (EO, EF)> newCmd(string[] args, string wiki, - Func>> func, Func shouldShow = null) + internal SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)> newCmd(string[] args, string wiki, + Func>> func, Func shouldShow = null) { - return new SearchEngineCommand<(CO, CF), (EO, EF)>(args, wiki, func, shouldShow); + return new SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)>(args, wiki, func, shouldShow); } internal override bool HandlesCommand(string command) @@ -96,7 +93,7 @@ internal override List AvailableCommandsForHelpText() List options = new(); foreach (var op in filterList.Keys) { - SearchEngineCommand<(CO, CF), (EO, EF)> cmd = filterList[op]; + SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)> cmd = filterList[op]; if (cmd.shouldShow == null || cmd.shouldShow()) { options.Add(op + "(" + filterList[op].args.Length + " args)"); @@ -116,7 +113,7 @@ internal override List AvailableCommandsForHelpText() List<(string, string[], string)> options = new(); foreach (var op in filterList.Keys) { - SearchEngineCommand<(CO, CF), (EO, EF)> cmd = filterList[op]; + SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)> cmd = filterList[op]; if (cmd.shouldShow == null || cmd.shouldShow()) { options.Add((op, cmd.args, cmd.wiki)); @@ -145,19 +142,19 @@ internal override List AvailableCommandsForHelpText() } public override IEnumerable<(object, object)> SearchNoType((object, object) container, string command, bool lenient, bool failureAllOrNone) { - List<(EO, EF)> res = Search(((CO, CF))container, command, lenient, failureAllOrNone); + List<(TElementObject, TElementField)> res = Search(((TContextObject, TContextField))container, command, lenient, failureAllOrNone); return res.Select((x) => ((object)x.Item1, (object)x.Item2)); } - public List<(EO, EF)> Search((CO, CF) param, string command, bool lenient, bool failureAllOrNone) + public List<(TElementObject, TElementField)> Search((TContextObject, TContextField) param, string command, bool lenient, bool failureAllOrNone) { return Search(param, unpacker(param), command, lenient, failureAllOrNone); } - public virtual List<(EO, EF)> Search((CO, CF) context, List<(EO, EF)> sourceSet, string command, bool lenient, bool failureAllOrNone) + public virtual List<(TElementObject, TElementField)> Search((TContextObject, TContextField) context, List<(TElementObject, TElementField)> sourceSet, string command, bool lenient, bool failureAllOrNone) { //assumes unpacking doesn't fail var conditions = command.Split("&&", StringSplitOptions.TrimEntries); - List<(EO, EF)> liveSet = sourceSet; + List<(TElementObject, TElementField)> liveSet = sourceSet; try { @@ -171,7 +168,7 @@ internal override List AvailableCommandsForHelpText() var cmd = condition.Split(' ', 2); - SearchEngineCommand<(CO, CF), (EO, EF)> selectedCommand; + SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)> selectedCommand; int argC; string[] args; var not = false; @@ -186,7 +183,7 @@ internal override List AvailableCommandsForHelpText() selectedCommand = filterList[cmd[0]]; argC = selectedCommand.args.Length; args = cmd.Length == 1 - ? new string[0] + ? [] : cmd[1].Split(' ', argC, StringSplitOptions.TrimEntries); } else @@ -204,10 +201,10 @@ internal override List AvailableCommandsForHelpText() } } - Func<(CO, CF), Func<(EO, EF), bool>> filter = selectedCommand.func(args, lenient); - Func<(EO, EF), bool> criteria = filter(context); - List<(EO, EF)> newRows = new(); - foreach ((EO, EF) row in liveSet) + Func<(TContextObject, TContextField), Func<(TElementObject, TElementField), bool>> filter = selectedCommand.func(args, lenient); + Func<(TElementObject, TElementField), bool> criteria = filter(context); + List<(TElementObject, TElementField)> newRows = new(); + foreach ((TElementObject, TElementField) row in liveSet) { if (not ^ criteria(row)) { @@ -220,7 +217,7 @@ internal override List AvailableCommandsForHelpText() } catch (Exception e) { - liveSet = failureAllOrNone ? sourceSet : new List<(EO, EF)>(); + liveSet = failureAllOrNone ? sourceSet : []; } return liveSet; @@ -228,11 +225,11 @@ internal override List AvailableCommandsForHelpText() internal override List<(TypelessSearchEngine, Type)> NextSearchEngines() { - return GetSearchEngines(typeof((EO, EF))); + return GetSearchEngines(typeof((TElementObject, TElementField))); } internal override METypelessOperation NextOperation() { - return METypelessOperation.GetEditOperation(typeof((EO, EF))); + return METypelessOperation.GetEditOperation(typeof((TElementObject, TElementField))); } internal override string NameForHelpTexts() @@ -242,12 +239,12 @@ internal override string NameForHelpTexts() internal override Type getContainerType() { - return typeof((CO, CF)); + return typeof((TContextObject, TContextField)); } internal override Type getElementType() { - return typeof((EO, EF)); + return typeof((TElementObject, TElementField)); } } From a563fddcac1426198bf21834b5acd604487fdb7b Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 16 Apr 2024 00:22:48 +0100 Subject: [PATCH 39/61] Remove hastily added object param, casting errors will abound. --- .../Editor/MassEdit/EditOperation.cs | 66 +++++++++---------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 5 +- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 228642b02..dd84825e5 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -16,16 +16,16 @@ internal abstract class METypelessOperationDef { internal string[] argNames; internal string wiki; - internal Func function; + internal Func function; internal Func shouldShow; } internal class MEOperationDef : METypelessOperationDef { - internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) + internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) { argNames = args; wiki = tooltip; - function = (o, f, str) => func(o, (TInput)f, str); //Shitty wrapping perf loss + function = (f, str) => func((TInput)f, str); //Shitty wrapping perf loss shouldShow = show; } } @@ -46,7 +46,7 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract object getTrueObj((object, object) currentObject, Dictionary contextObjects); internal abstract object getTrueValue((object, object) currentObject, Dictionary contextObjects); internal abstract bool validateResult(object res); - internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object context, object res); + internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); internal abstract bool HandlesCommand(string command); } internal abstract class MEOperation : METypelessOperation @@ -72,7 +72,7 @@ internal override Dictionary AllCommands() { return operations; } - internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) + internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) { operations.Add(command, new MEOperationDef(args, wiki, func, show)); } @@ -90,14 +90,14 @@ internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool> internal override void Setup() { name = "global"; - NewCmd("clear", [], "Clears clipboard param and rows", (dummy, selectionState, args) => + NewCmd("clear", [], "Clears clipboard param and rows", (dummy, args) => { ParamBank.ClipboardParam = null; ParamBank.ClipboardRows.Clear(); return true; }); NewCmd("newvar", ["variable name", "value"], - "Creates a variable with the given value, and the type of that value", (dummy, selectionState, args) => + "Creates a variable with the given value, and the type of that value", (dummy, args) => { int asInt; double asDouble; @@ -116,7 +116,7 @@ internal override void Setup() return true; }, () => CFG.Current.Param_AdvancedMassedit); - NewCmd("clearvars", [], "Deletes all variables", (dummy, selectionState, args) => + NewCmd("clearvars", [], "Deletes all variables", (dummy, args) => { MassParamEdit.massEditVars.Clear(); return true; @@ -136,7 +136,7 @@ internal override bool validateResult(object res) return true; } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { return; //Global ops, for now, don't use actions and simply execute effects themselves } @@ -151,10 +151,10 @@ internal override void Setup() name = "row"; NewCmd("copy", [], "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", - (param, rowPair, args) => + (paramAndRow, args) => { - var paramKey = (string)param; - Param.Row row = rowPair.Item2; + var paramKey = paramAndRow.Item1; + Param.Row row = paramAndRow.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -179,10 +179,10 @@ internal override void Setup() ); NewCmd("copyN", ["count"], "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", - (param, rowPair, args) => + (paramAndRow, args) => { - var paramKey = (string)param; - Param.Row row = rowPair.Item2; + var paramKey = paramAndRow.Item1; + Param.Row row = paramAndRow.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -211,10 +211,10 @@ internal override void Setup() }, () => CFG.Current.Param_AdvancedMassedit); NewCmd("paste", [], "Adds the selected rows to the primary regulation or parambnd in the selected param", - (param, rowPair, args) => + (paramAndRow, args) => { - var paramKey = (string)param; - Param.Row row = rowPair.Item2; + var paramKey = paramAndRow.Item1; + Param.Row row = paramAndRow.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -249,7 +249,7 @@ internal override bool validateResult(object res) return true; } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { //use Param from result as this may be different to original Param obj (Param p2, Param.Row rs) = ((Param, Param.Row))res; @@ -265,10 +265,10 @@ internal override void Setup() NewCmd("=", ["number or text"], "Assigns the given value to the selected values. Will attempt conversion to the value's data type", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => args[0])); + (value, args) => MassParamEdit.WithDynamicOf(value, v => args[0])); NewCmd("+", ["number or text"], "Adds the number to the selected values, or appends text if that is the data type of the values", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => + (value, args) => MassParamEdit.WithDynamicOf(value, v => { double val; if (double.TryParse(args[0], out val)) @@ -280,19 +280,19 @@ internal override void Setup() })); NewCmd("-", ["number"], "Subtracts the number from the selected values", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v - double.Parse(args[0]))); + (value, args) => MassParamEdit.WithDynamicOf(value, v => v - double.Parse(args[0]))); NewCmd("*", ["number"], "Multiplies selected values by the number", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v * double.Parse(args[0]))); + (value, args) => MassParamEdit.WithDynamicOf(value, v => v * double.Parse(args[0]))); NewCmd("/", ["number"], "Divides the selected values by the number", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v / double.Parse(args[0]))); + (value, args) => MassParamEdit.WithDynamicOf(value, v => v / double.Parse(args[0]))); NewCmd("%", ["number"], "Gives the remainder when the selected values are divided by the number", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v % double.Parse(args[0])), () => CFG.Current.Param_AdvancedMassedit); + (value, args) => MassParamEdit.WithDynamicOf(value, v => v % double.Parse(args[0])), () => CFG.Current.Param_AdvancedMassedit); NewCmd("scale", ["factor number", "center number"], "Multiplies the difference between the selected values and the center number by the factor number", - (value, ctx, args) => + (value, args) => { var opp1 = double.Parse(args[0]); var opp2 = double.Parse(args[1]); @@ -305,20 +305,20 @@ internal override void Setup() NewCmd("replace", new[] { "text to replace", "new text" }, "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => v.Replace(args[0], args[1]))); + (value, args) => MassParamEdit.WithDynamicOf(value, v => v.Replace(args[0], args[1]))); NewCmd("replacex", ["text to replace (regex)", "new text (w/ groups)"], "Interprets the selected values as text and replaces all occurances of the given regex with the replacement, supporting regex groups", - (ctx, value, args) => + (value, args) => { Regex rx = new(args[0]); return MassParamEdit.WithDynamicOf(value, v => rx.Replace(v, args[1])); }, () => CFG.Current.Param_AdvancedMassedit); NewCmd("max", ["number"], "Returns the larger of the current value and number", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Max(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); + (value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Max(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); NewCmd("min", ["number"], "Returns the smaller of the current value and number", - (ctx, value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); + (value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); } internal override bool validateResult(object res) @@ -342,9 +342,9 @@ internal override object getTrueValue((object, object) currentObject, Dictionary (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; return row.Get(col); } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { - Param.Row row = (Param.Row) obj; + (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; actionList.AppendParamEditAction(row, col, res); } @@ -362,7 +362,7 @@ internal override object getTrueValue((object, object) currentObject, Dictionary return MassParamEdit.massEditVars[(string)currentObject.Item2]; } - internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object obj, object res) + internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) { MassParamEdit.massEditVars[(string)currentObject.Item2] = res; } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index e29442ba5..843ba3852 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -335,13 +335,12 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); - object ctxObj = opType.getTrueObj(currentObject, contextObjects); - var opResult = parsedOp.function(ctxObj, opType.getTrueValue(currentObject, contextObjects), argValues);//TODO NOTNULL IT + var opResult = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); if (!opType.validateResult(opResult)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); } - opType.UseResult(_partialActions, currentObject, contextObjects, ctxObj, opResult); + opType.UseResult(_partialActions, currentObject, contextObjects, opResult); return new MassEditResult(MassEditResultType.SUCCESS, ""); } } From 361db0d439717a981b615db53d406c7f365e3c88 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 16 Apr 2024 00:41:59 +0100 Subject: [PATCH 40/61] logging currentline --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 843ba3852..753323494 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -334,7 +334,7 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine } private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { - var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(0).ToParamEditorString()).ToArray(); + var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(_currentLine).ToParamEditorString()).ToArray(); var opResult = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); if (!opType.validateResult(opResult)) { From 7ca5502aed29e82da7f8dcdc0d8822b085ddcd74 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 16 Apr 2024 05:01:55 +0100 Subject: [PATCH 41/61] rename and trim --- .../Editor/MassEdit/EditOperation.cs | 37 +++++-------------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 4 +- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index dd84825e5..2d62d55ac 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -43,9 +43,8 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); - internal abstract object getTrueObj((object, object) currentObject, Dictionary contextObjects); - internal abstract object getTrueValue((object, object) currentObject, Dictionary contextObjects); - internal abstract bool validateResult(object res); + internal abstract object GetElementValue((object, object) currentObject, Dictionary contextObjects); + internal abstract bool ValidateResult(object res); internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); internal abstract bool HandlesCommand(string command); } @@ -122,16 +121,12 @@ internal override void Setup() return true; }, () => CFG.Current.Param_AdvancedMassedit); } - internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) - { - return true; //Global op technically has no context / uses the dummy context of boolean - } - internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) + internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { return true; //Global op technically has no context / uses the dummy context of boolean } - internal override bool validateResult(object res) + internal override bool ValidateResult(object res) { return true; } @@ -230,16 +225,12 @@ internal override void Setup() } ); } - internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) - { - return currentObject.Item1; - } - internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) + internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { return currentObject.Item2; } - internal override bool validateResult(object res) + internal override bool ValidateResult(object res) { if (res.GetType() != typeof((Param, Param.Row))) return false; @@ -321,7 +312,7 @@ internal override void Setup() (value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); } - internal override bool validateResult(object res) + internal override bool ValidateResult(object res) { if (res == null) return false; @@ -331,12 +322,7 @@ internal override bool validateResult(object res) internal class MECellOperation : MEValueOperation<(PseudoColumn, Param.Column)> { public static MECellOperation cellOps = new(); - internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) - { - (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; - return currentObject; - } - internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) + internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; (PseudoColumn, Param.Column) col = ((PseudoColumn, Param.Column))currentObject; @@ -352,12 +338,7 @@ internal override void UseResult(List actionList, (object, object) internal class MEVarOperation : MEValueOperation { public static MEVarOperation varOps = new(); - - internal override object getTrueObj((object, object) currentObject, Dictionary contextObjects) - { - return (string)currentObject.Item2; - } - internal override object getTrueValue((object, object) currentObject, Dictionary contextObjects) + internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { return MassParamEdit.massEditVars[(string)currentObject.Item2]; } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 753323494..b6b629732 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -335,8 +335,8 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(_currentLine).ToParamEditorString()).ToArray(); - var opResult = parsedOp.function(opType.getTrueValue(currentObject, contextObjects), argValues); - if (!opType.validateResult(opResult)) + var opResult = parsedOp.function(opType.GetElementValue(currentObject, contextObjects), argValues); + if (!opType.ValidateResult(opResult)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); } From 16c5d0b879c6c3a7810fc6ee1c43f1f1420b1b1b Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 16 Apr 2024 05:33:34 +0100 Subject: [PATCH 42/61] Meme fix --- src/StudioCore/Editor/MassEdit/EditOperation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 2d62d55ac..7a015b942 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -25,7 +25,7 @@ internal MEOperationDef(string[] args, string tooltip, Func func((TInput)f, str); //Shitty wrapping perf loss + function = (f, str) => func((TInput)f, str); //Shitty wrapping perf loss. Also fails to cast tuples which are in use all over. shouldShow = show; } } @@ -227,7 +227,7 @@ internal override void Setup() } internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { - return currentObject.Item2; + return currentObject; } internal override bool ValidateResult(object res) From b9ab669f5a7224706a8e4858d198cfd8a986bc0c Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Tue, 16 Apr 2024 06:01:29 +0100 Subject: [PATCH 43/61] encode object/value into editop function --- .../Editor/MassEdit/EditOperation.cs | 47 ++++++++++--------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 2 +- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 7a015b942..6422d2997 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -16,23 +16,30 @@ internal abstract class METypelessOperationDef { internal string[] argNames; internal string wiki; - internal Func function; + internal Func function; internal Func shouldShow; } -internal class MEOperationDef : METypelessOperationDef +internal class MEOperationDef : METypelessOperationDef { - internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) + internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) { argNames = args; wiki = tooltip; - function = (f, str) => func((TInput)f, str); //Shitty wrapping perf loss. Also fails to cast tuples which are in use all over. + function = (dummy, v, str) => func((TInputValue)v, str); //Shitty wrapping perf loss. + shouldShow = show; + } + internal MEOperationDef(string[] args, string tooltip, Func func, Func show = null) + { + argNames = args; + wiki = tooltip; + function = (o, v, str) => func((TInputObject) o, (TInputValue)v, str); //Shitty wrapping perf loss. shouldShow = show; } } internal abstract class METypelessOperation { private static Dictionary editOperations = new(); - internal static void AddEditOperation(MEOperation engine) + internal static void AddEditOperation(MEOperation engine) { editOperations[typeof(TMECategory)] = engine; } @@ -48,7 +55,7 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); internal abstract bool HandlesCommand(string command); } -internal abstract class MEOperation : METypelessOperation +internal abstract class MEOperation : METypelessOperation { internal Dictionary operations = new(); internal string name = "[Unnamed operation type]"; @@ -71,9 +78,13 @@ internal override Dictionary AllCommands() { return operations; } - internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) + internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) + { + operations.Add(command, new MEOperationDef(args, wiki, func, show)); + } + internal void NewCmd(string command, string[] args, string wiki, Func func, Func show = null) { - operations.Add(command, new MEOperationDef(args, wiki, func, show)); + operations.Add(command, new MEOperationDef(args, wiki, func, show)); } internal override string NameForHelpTexts() @@ -82,7 +93,7 @@ internal override string NameForHelpTexts() } } -internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool> +internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool, bool> { internal static MEGlobalOperation globalOps = new(); @@ -137,7 +148,7 @@ internal override void UseResult(List actionList, (object, object) } } -internal class MERowOperation : MEOperation<(string, Param.Row), (string, Param.Row), (Param, Param.Row)> +internal class MERowOperation : MEOperation<(string, Param.Row), string, Param.Row, (Param, Param.Row)> //technically we're still using string as the containing object in place of Param { public static MERowOperation rowOps = new(); @@ -146,10 +157,8 @@ internal override void Setup() name = "row"; NewCmd("copy", [], "Adds the selected rows into clipboard. If the clipboard param is different, the clipboard is emptied first", - (paramAndRow, args) => + (paramKey, row, args) => { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -174,10 +183,8 @@ internal override void Setup() ); NewCmd("copyN", ["count"], "Adds the selected rows into clipboard the given number of times. If the clipboard param is different, the clipboard is emptied first", - (paramAndRow, args) => + (paramKey, row, args) => { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -206,10 +213,8 @@ internal override void Setup() }, () => CFG.Current.Param_AdvancedMassedit); NewCmd("paste", [], "Adds the selected rows to the primary regulation or parambnd in the selected param", - (paramAndRow, args) => + (paramKey, row, args) => { - var paramKey = paramAndRow.Item1; - Param.Row row = paramAndRow.Item2; if (paramKey == null) { throw new MEOperationException(@"Could not locate param"); @@ -227,7 +232,7 @@ internal override void Setup() } internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { - return currentObject; + return currentObject.Item2; } internal override bool ValidateResult(object res) @@ -248,7 +253,7 @@ internal override void UseResult(List actionList, (object, object) } } -internal abstract class MEValueOperation : MEOperation +internal abstract class MEValueOperation : MEOperation { internal override void Setup() { diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index b6b629732..9a9bd6bd0 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -335,7 +335,7 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(_currentLine).ToParamEditorString()).ToArray(); - var opResult = parsedOp.function(opType.GetElementValue(currentObject, contextObjects), argValues); + var opResult = parsedOp.function(currentObject.Item1, opType.GetElementValue(currentObject, contextObjects), argValues); if (!opType.ValidateResult(opResult)) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); From 969609ad41cec914c74be1dc85fccbc7222b1efb Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 17 Apr 2024 22:43:03 +0100 Subject: [PATCH 44/61] typing check on usage --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index 69ce78493..dfbd410b6 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -416,7 +416,7 @@ public static string MassEditOpAutoFill() return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); } - private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, + private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, string suffix, Func subMenu) { var currentArgIndex = 0; From 9d88fbef65fc8f73d1129140409fb473741888c5 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Wed, 17 Apr 2024 23:13:39 +0100 Subject: [PATCH 45/61] update argGetters to use searchengine's actual types --- .../Editor/MassEdit/EditOperation.cs | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 6422d2997..1e7ea28ac 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -385,18 +385,18 @@ private OperationArgumentGetter newGetter([], "Gives the specified value", + defaultGetter = newGetter<(bool, bool)>([], "Gives the specified value", value => (i, c) => value[0]); - argumentGetters.Add("self", newGetter(new string[0], "Gives the value of the currently selected value", + argumentGetters.Add("self", newGetter<(string, Param.Row), (PseudoColumn, Param.Column)>([], "Gives the value of the currently selected value", empty => (j, row) => (k, col) => { - return row.Get(col).ToParamEditorString(); + return row.Item2.Get(col).ToParamEditorString(); })); - argumentGetters.Add("field", newGetter(["field internalName"], + argumentGetters.Add("field", newGetter<(ParamBank, Param), (string, Param.Row)>(["field internalName"], "Gives the value of the given cell/field for the currently selected row and param", field => (i, param) => { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); @@ -404,30 +404,30 @@ private void Setup() return (j, row) => { - var v = row.Get(col).ToParamEditorString(); + var v = row.Item2.Get(col).ToParamEditorString(); return v; }; })); - argumentGetters.Add("vanilla", newGetter([], + argumentGetters.Add("vanilla", newGetter<(ParamBank, Param), (string, Param.Row), (PseudoColumn, Param.Column)>([], "Gives the value of the equivalent cell/field in the vanilla regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", empty => { ParamBank bank = ParamBank.VanillaBank; return (i, param) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); if (!bank.Params.ContainsKey(paramName)) { - throw new MEOperationException($@"Could not locate vanilla param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate vanilla param for {param.Item2.ParamType}"); } Param vParam = bank.Params[paramName]; return (j, row) => { - Param.Row vRow = vParam?[row.ID]; + Param.Row vRow = vParam?[row.Item2.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate vanilla row {row.ID}"); + throw new MEOperationException($@"Could not locate vanilla row {row.Item2.ID}"); } return (k, col) => @@ -442,7 +442,7 @@ private void Setup() }; }; })); - argumentGetters.Add("aux", newGetter(["parambank name"], + argumentGetters.Add("aux", newGetter<(ParamBank, Param), (string, Param.Row), (PseudoColumn, Param.Column)>(["parambank name"], "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankName => { @@ -454,19 +454,19 @@ private void Setup() ParamBank bank = ParamBank.AuxBanks[bankName[0]]; return (i, param) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); if (!bank.Params.ContainsKey(paramName)) { - throw new MEOperationException($@"Could not locate aux param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate aux param for {param.Item2.ParamType}"); } Param vParam = bank.Params[paramName]; return (j, row) => { - Param.Row vRow = vParam?[row.ID]; + Param.Row vRow = vParam?[row.Item2.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate aux row {row.ID}"); + throw new MEOperationException($@"Could not locate aux row {row.Item2.ID}"); } return (k, col) => @@ -481,15 +481,15 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("vanillafield", newGetter(["field internalName"], + argumentGetters.Add("vanillafield", newGetter<(ParamBank, Param), (string, Param.Row)>(["field internalName"], "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", field => (i, param) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); Param? vParam = ParamBank.VanillaBank.GetParamFromName(paramName); if (vParam == null) { - throw new MEOperationException($@"Could not locate vanilla param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate vanilla param for {param.Item2.ParamType}"); } (PseudoColumn, Param.Column) col = vParam.GetCol(field[0]); @@ -500,17 +500,17 @@ private void Setup() return (j, row) => { - Param.Row vRow = vParam?[row.ID]; + Param.Row vRow = vParam?[row.Item2.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate vanilla row {row.ID}"); + throw new MEOperationException($@"Could not locate vanilla row {row.Item2.ID}"); } var v = vRow.Get(col).ToParamEditorString(); return v; }; })); - argumentGetters.Add("auxfield", newGetter(["parambank name", "field internalName"], + argumentGetters.Add("auxfield", newGetter<(ParamBank, Param), (string, Param.Row)>(["parambank name", "field internalName"], "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankAndField => { @@ -522,10 +522,10 @@ private void Setup() ParamBank bank = ParamBank.AuxBanks[bankAndField[0]]; return (i, param) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); if (!bank.Params.ContainsKey(paramName)) { - throw new MEOperationException($@"Could not locate aux param for {param.ParamType}"); + throw new MEOperationException($@"Could not locate aux param for {param.Item2.ParamType}"); } Param vParam = bank.Params[paramName]; @@ -537,10 +537,10 @@ private void Setup() return (j, row) => { - Param.Row vRow = vParam?[row.ID]; + Param.Row vRow = vParam?[row.Item2.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate aux row {row.ID}"); + throw new MEOperationException($@"Could not locate aux row {row.Item2.ID}"); } var v = vRow.Get(col).ToParamEditorString(); @@ -548,7 +548,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("paramlookup", newGetter(["param name", "row id", "field name"], + argumentGetters.Add("paramlookup", newGetter<(bool, bool)>(["param name", "row id", "field name"], "Returns the specific value specified by the exact param, row and field.", address => { Param param = ParamBank.PrimaryBank.Params[address[0]]; @@ -564,11 +564,11 @@ private void Setup() var value = row.Get(field).ToParamEditorString(); return (i, c) => value; }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("average", newGetter(["field internalName", "row selector"], + argumentGetters.Add("average", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); @@ -581,74 +581,74 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + RowSearchEngine.rse.Search(param, field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); return avg.ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("median", newGetter(["field internalName", "row selector"], + argumentGetters.Add("median", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], "Gives the median value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + RowSearchEngine.rse.Search(param, field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("mode", newGetter(["field internalName", "row selector"], + argumentGetters.Add("mode", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", field => (i, param) => { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + RowSearchEngine.rse.Search(param, field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("min", newGetter(["field internalName", "row selector"], + argumentGetters.Add("min", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], "Gives the smallest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + RowSearchEngine.rse.Search(param, field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("max", newGetter(["field internalName", "row selector"], + argumentGetters.Add("max", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], "Gives the largest value from the cells/fields found using the given param, row selector and field", field => (i, param) => { - (PseudoColumn, Param.Column) col = param.GetCol(field[0]); + (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((ParamBank.PrimaryBank, param), field[1], false, false); + RowSearchEngine.rse.Search(param, field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); return max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("random", newGetter( + argumentGetters.Add("random", newGetter<(bool, bool)>( ["minimum number (inclusive)", "maximum number (exclusive)"], "Gives a random decimal number between the given values for each selected value", minAndMax => { @@ -667,7 +667,7 @@ private void Setup() var range = max - min; return (i, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randint", newGetter( + argumentGetters.Add("randint", newGetter<(bool, bool)>( ["minimum integer (inclusive)", "maximum integer (inclusive)"], "Gives a random integer between the given values for each selected value", minAndMax => { @@ -685,7 +685,7 @@ private void Setup() return (i, c) => Random.Shared.NextInt64(min, max + 1).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randFrom", newGetter(["param name", "field internalName", "row selector"], + argumentGetters.Add("randFrom", newGetter<(bool, bool)>(["param name", "field internalName", "row selector"], "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", paramFieldRowSelector => { @@ -695,13 +695,13 @@ private void Setup() var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("paramIndex", newGetter([], + argumentGetters.Add("paramIndex", newGetter<(ParamBank, Param)>([], "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", empty => (i, param) => { return i.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("rowIndex", newGetter([], + argumentGetters.Add("rowIndex", newGetter<(string, Param.Row)>([], "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", empty => (j, row) => { From 5e70bd6be43aaeac511a8087c03a920876dce887 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 00:06:39 +0100 Subject: [PATCH 46/61] Add static context items --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 5 +++++ src/StudioCore/Editor/MassEdit/SearchEngine.cs | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 9a9bd6bd0..f88e2948b 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -307,6 +307,11 @@ private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine { var editCount = -1; filterDepth++; + var contexts = engine.GetStaticContextItems(); + foreach (var context in contexts) + { + argFuncs = argFuncs.Select((func, i) => func.tryFoldAsFunc(editCount, context.Item2)); + } foreach ((object, object) currentObject in engine.SearchNoType(contextObject, info.command, false, false)) { editCount++; diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 60713170f..8cebb1b49 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -38,6 +38,10 @@ internal static void AddSearchEngine SearchNoType((object, object) container, string command, bool lenient, bool failureAllOrNone); internal abstract bool HandlesCommand(string command); + internal virtual IEnumerable<(Type, (object, object))> GetStaticContextItems() + { + return []; + } } internal class SearchEngine : TypelessSearchEngine { @@ -280,6 +284,10 @@ internal override void Setup() "Selects param rows selected in the current param window", noArgs(noContext(param => true)))); } + internal override IEnumerable<(Type, (object, object))> GetStaticContextItems() + { + return [(typeof((ParamBank, Param)), (ParamBank.PrimaryBank, ParamBank.PrimaryBank.Params[MassParamEditRegex.totalHackPleaseKillme.GetActiveParam()]))]; + } } internal class ParamRowClipBoardSearchEngine : SearchEngine { @@ -296,6 +304,10 @@ internal override void Setup() "Selects param rows copied in the clipboard", noArgs(noContext(param => true)))); } + internal override IEnumerable<(Type, (object, object))> GetStaticContextItems() + { + return [(typeof((ParamBank, Param)), (ParamBank.PrimaryBank, ParamBank.PrimaryBank.Params[ParamBank.ClipboardParam]))]; + } } internal class ParamSearchEngine : SearchEngine From 10ba09e1f503f68bf6d3296104936a3e77262f13 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 00:52:00 +0100 Subject: [PATCH 47/61] Unpack tuples because they causes type check failures when attempting to fold argGetters --- .../Editor/MassEdit/EditOperation.cs | 179 +++++++++--------- 1 file changed, 90 insertions(+), 89 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 1e7ea28ac..ddb5283ec 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -266,8 +266,7 @@ internal override void Setup() "Adds the number to the selected values, or appends text if that is the data type of the values", (value, args) => MassParamEdit.WithDynamicOf(value, v => { - double val; - if (double.TryParse(args[0], out val)) + if (double.TryParse(args[0], out double val)) { return v + val; } @@ -299,7 +298,7 @@ internal override void Setup() } ); NewCmd("replace", - new[] { "text to replace", "new text" }, + ["text to replace", "new text"], "Interprets the selected values as text and replaces all occurances of the text to replace with the new text", (value, args) => MassParamEdit.WithDynamicOf(value, v => v.Replace(args[0], args[1]))); NewCmd("replacex", ["text to replace (regex)", "new text (w/ groups)"], @@ -364,20 +363,20 @@ private MEOperationArgument() { Setup(); } - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func> + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); } - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func>> + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); } - private OperationArgumentGetter newGetter(string[] args, string wiki, - Func>>> + private OperationArgumentGetter newGetter(string[] args, string wiki, + Func>>> func, Func shouldShow = null) { return new OperationArgumentGetter(args, wiki, func, shouldShow); @@ -385,64 +384,64 @@ private OperationArgumentGetter newGetter([], "Gives the specified value", - value => (i, c) => value[0]); - argumentGetters.Add("self", newGetter<(string, Param.Row), (PseudoColumn, Param.Column)>([], "Gives the value of the currently selected value", - empty => (j, row) => (k, col) => + defaultGetter = newGetter([], "Gives the specified value", + value => (i, c, c2) => value[0]); + argumentGetters.Add("self", newGetter([], "Gives the value of the currently selected value", + empty => (j, rowP, rowR) => (k, colE, colC) => { - return row.Item2.Get(col).ToParamEditorString(); + return rowR.Get((colE, colC)).ToParamEditorString(); })); - argumentGetters.Add("field", newGetter<(ParamBank, Param), (string, Param.Row)>(["field internalName"], + argumentGetters.Add("field", newGetter(["field internalName"], "Gives the value of the given cell/field for the currently selected row and param", field => - (i, param) => + (i, paramB, paramP) => { - (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); + (PseudoColumn, Param.Column) col = paramP.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } - return (j, row) => + return (j, rowP, rowR) => { - var v = row.Item2.Get(col).ToParamEditorString(); + var v = rowR.Get(col).ToParamEditorString(); return v; }; })); - argumentGetters.Add("vanilla", newGetter<(ParamBank, Param), (string, Param.Row), (PseudoColumn, Param.Column)>([], + argumentGetters.Add("vanilla", newGetter([], "Gives the value of the equivalent cell/field in the vanilla regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", empty => { ParamBank bank = ParamBank.VanillaBank; - return (i, param) => + return (i, paramB, paramP) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(paramP); if (!bank.Params.ContainsKey(paramName)) { - throw new MEOperationException($@"Could not locate vanilla param for {param.Item2.ParamType}"); + throw new MEOperationException($@"Could not locate vanilla param for {paramP.ParamType}"); } Param vParam = bank.Params[paramName]; - return (j, row) => + return (j, rowP, rowR) => { - Param.Row vRow = vParam?[row.Item2.ID]; + Param.Row vRow = vParam?[rowR.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate vanilla row {row.Item2.ID}"); + throw new MEOperationException($@"Could not locate vanilla row {rowR.ID}"); } - return (k, col) => + return (k, colE, colC) => { - if (col.Item1 == PseudoColumn.None && col.Item2 == null) + if (colE == PseudoColumn.None && colC == null) { throw new MEOperationException(@"Could not locate given field or property"); } - return vRow.Get(col).ToParamEditorString(); + return vRow.Get((colE, colC)).ToParamEditorString(); }; }; }; })); - argumentGetters.Add("aux", newGetter<(ParamBank, Param), (string, Param.Row), (PseudoColumn, Param.Column)>(["parambank name"], + argumentGetters.Add("aux", newGetter(["parambank name"], "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankName => { @@ -452,44 +451,44 @@ private void Setup() } ParamBank bank = ParamBank.AuxBanks[bankName[0]]; - return (i, param) => + return (i, paramB, paramP) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(paramP); if (!bank.Params.ContainsKey(paramName)) { - throw new MEOperationException($@"Could not locate aux param for {param.Item2.ParamType}"); + throw new MEOperationException($@"Could not locate aux param for {paramP.ParamType}"); } Param vParam = bank.Params[paramName]; - return (j, row) => + return (j, rowP, rowR) => { - Param.Row vRow = vParam?[row.Item2.ID]; + Param.Row vRow = vParam?[rowR.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate aux row {row.Item2.ID}"); + throw new MEOperationException($@"Could not locate aux row {rowR.ID}"); } - return (k, col) => + return (k, colE, colC) => { - if (!col.IsColumnValid()) + if (!(colE, colC).IsColumnValid()) { throw new MEOperationException(@"Could not locate given field or property"); } - return vRow.Get(col).ToParamEditorString(); + return vRow.Get((colE, colC)).ToParamEditorString(); }; }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("vanillafield", newGetter<(ParamBank, Param), (string, Param.Row)>(["field internalName"], + argumentGetters.Add("vanillafield", newGetter(["field internalName"], "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", - field => (i, param) => + field => (i, paramB, paramP) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(paramP); Param? vParam = ParamBank.VanillaBank.GetParamFromName(paramName); if (vParam == null) { - throw new MEOperationException($@"Could not locate vanilla param for {param.Item2.ParamType}"); + throw new MEOperationException($@"Could not locate vanilla param for {paramP.ParamType}"); } (PseudoColumn, Param.Column) col = vParam.GetCol(field[0]); @@ -498,19 +497,19 @@ private void Setup() throw new MEOperationException($@"Could not locate field {field[0]}"); } - return (j, row) => + return (j, rowP, rowR) => { - Param.Row vRow = vParam?[row.Item2.ID]; + Param.Row vRow = vParam?[rowR.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate vanilla row {row.Item2.ID}"); + throw new MEOperationException($@"Could not locate vanilla row {rowR.ID}"); } var v = vRow.Get(col).ToParamEditorString(); return v; }; })); - argumentGetters.Add("auxfield", newGetter<(ParamBank, Param), (string, Param.Row)>(["parambank name", "field internalName"], + argumentGetters.Add("auxfield", newGetter(["parambank name", "field internalName"], "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankAndField => { @@ -520,12 +519,12 @@ private void Setup() } ParamBank bank = ParamBank.AuxBanks[bankAndField[0]]; - return (i, param) => + return (i, paramB, paramP) => { - var paramName = ParamBank.PrimaryBank.GetKeyForParam(param.Item2); + var paramName = ParamBank.PrimaryBank.GetKeyForParam(paramP); if (!bank.Params.ContainsKey(paramName)) { - throw new MEOperationException($@"Could not locate aux param for {param.Item2.ParamType}"); + throw new MEOperationException($@"Could not locate aux param for {paramP.ParamType}"); } Param vParam = bank.Params[paramName]; @@ -535,12 +534,12 @@ private void Setup() throw new MEOperationException($@"Could not locate field {bankAndField[1]}"); } - return (j, row) => + return (j, rowP, rowR) => { - Param.Row vRow = vParam?[row.Item2.ID]; + Param.Row vRow = vParam?[rowR.ID]; if (vRow == null) { - throw new MEOperationException($@"Could not locate aux row {row.Item2.ID}"); + throw new MEOperationException($@"Could not locate aux row {rowR.ID}"); } var v = vRow.Get(col).ToParamEditorString(); @@ -548,7 +547,7 @@ private void Setup() }; }; }, () => ParamBank.AuxBanks.Count > 0)); - argumentGetters.Add("paramlookup", newGetter<(bool, bool)>(["param name", "row id", "field name"], + argumentGetters.Add("paramlookup", newGetter(["param name", "row id", "field name"], "Returns the specific value specified by the exact param, row and field.", address => { Param param = ParamBank.PrimaryBank.Params[address[0]]; @@ -562,13 +561,13 @@ private void Setup() if (row == null) throw new MEOperationException($@"Could not find row {id} in param {address[0]}"); var value = row.Get(field).ToParamEditorString(); - return (i, c) => value; + return (i, c, c2) => value; }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("average", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], + argumentGetters.Add("average", newGetter(["field internalName", "row selector"], "Gives the mean value of the cells/fields found using the given selector, for the currently selected param", - field => (i, param) => + field => (i, paramB, paramP) => { - (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); + (PseudoColumn, Param.Column) col = paramP.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); @@ -581,74 +580,74 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search(param, field[1], false, false); + RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); return avg.ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("median", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], + argumentGetters.Add("median", newGetter(["field internalName", "row selector"], "Gives the median value of the cells/fields found using the given selector, for the currently selected param", - field => (i, param) => + field => (i, paramB, paramP) => { - (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); + (PseudoColumn, Param.Column) col = paramP.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search(param, field[1], false, false); + RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("mode", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], + argumentGetters.Add("mode", newGetter(["field internalName", "row selector"], "Gives the most common value of the cells/fields found using the given selector, for the currently selected param", - field => (i, param) => + field => (i, paramB, paramP) => { - (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); + (PseudoColumn, Param.Column) col = paramP.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search(param, field[1], false, false); + RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; return avg.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("min", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], + argumentGetters.Add("min", newGetter(["field internalName", "row selector"], "Gives the smallest value from the cells/fields found using the given param, row selector and field", - field => (i, param) => + field => (i, paramB, paramP) => { - (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); + (PseudoColumn, Param.Column) col = paramP.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search(param, field[1], false, false); + RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("max", newGetter<(ParamBank, Param)>(["field internalName", "row selector"], + argumentGetters.Add("max", newGetter(["field internalName", "row selector"], "Gives the largest value from the cells/fields found using the given param, row selector and field", - field => (i, param) => + field => (i, paramB, paramP) => { - (PseudoColumn, Param.Column) col = param.Item2.GetCol(field[0]); + (PseudoColumn, Param.Column) col = paramP.GetCol(field[0]); if (!col.IsColumnValid()) { throw new MEOperationException($@"Could not locate field {field[0]}"); } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search(param, field[1], false, false); + RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); return max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("random", newGetter<(bool, bool)>( + argumentGetters.Add("random", newGetter( ["minimum number (inclusive)", "maximum number (exclusive)"], "Gives a random decimal number between the given values for each selected value", minAndMax => { @@ -665,9 +664,9 @@ private void Setup() } var range = max - min; - return (i, c) => ((Random.Shared.NextDouble() * range) + min).ToString(); + return (i, c, c2) => ((Random.Shared.NextDouble() * range) + min).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randint", newGetter<(bool, bool)>( + argumentGetters.Add("randint", newGetter( ["minimum integer (inclusive)", "maximum integer (inclusive)"], "Gives a random integer between the given values for each selected value", minAndMax => { @@ -683,9 +682,9 @@ private void Setup() throw new MEOperationException(@"Random max must be greater than min"); } - return (i, c) => Random.Shared.NextInt64(min, max + 1).ToString(); + return (i, c, c2) => Random.Shared.NextInt64(min, max + 1).ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("randFrom", newGetter<(bool, bool)>(["param name", "field internalName", "row selector"], + argumentGetters.Add("randFrom", newGetter(["param name", "field internalName", "row selector"], "Gives a random value from the cells/fields found using the given param, row selector and field, for each selected value", paramFieldRowSelector => { @@ -693,23 +692,23 @@ private void Setup() List<(string, Param.Row)> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); - return (i, c) => values[Random.Shared.NextInt64(values.Length)].ToString(); + return (i, c, c2) => values[Random.Shared.NextInt64(values.Length)].ToString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("paramIndex", newGetter<(ParamBank, Param)>([], + argumentGetters.Add("paramIndex", newGetter([], "Gives an integer for the current selected param, beginning at 0 and increasing by 1 for each param selected", - empty => (i, param) => + empty => (i, paramB, paramP) => { return i.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("rowIndex", newGetter<(string, Param.Row)>([], + argumentGetters.Add("rowIndex", newGetter([], "Gives an integer for the current selected row, beginning at 0 and increasing by 1 for each row selected", - empty => (j, row) => + empty => (j, rowP, rowR) => { return j.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); - argumentGetters.Add("fieldIndex", newGetter<(PseudoColumn, Param.Column)>([], + argumentGetters.Add("fieldIndex", newGetter([], "Gives an integer for the current selected cell/field, beginning at 0 and increasing by 1 for each cell/field selected", - empty => (k, col) => + empty => (k, colE, colC) => { return k.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -828,8 +827,10 @@ internal static object tryFoldAsFunc(this object maybeFunc, int editIndex, (obje return maybeFunc; Delegate func = (Delegate)maybeFunc; var parameters = func.Method.GetParameters(); - if (parameters.Length == 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == newContextInput.GetType()) - return func.DynamicInvoke(editIndex, newContextInput); + var a = newContextInput.Item1.GetType(); + var b = newContextInput.Item2.GetType(); + if (parameters.Length == 3 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == newContextInput.Item1.GetType() && parameters[2].ParameterType == newContextInput.Item2.GetType()) + return func.DynamicInvoke(editIndex, newContextInput.Item1, newContextInput.Item2); return func; } internal static object assertCompleteContextOrThrow(this object maybeFunc, int editIndex) From 5264eb5f19426c3468005f735e31013fb7e4ab15 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 01:09:07 +0100 Subject: [PATCH 48/61] Move all searchengines to fix initialisation --- src/StudioCore/Editor/EditorDecorations.cs | 4 +-- src/StudioCore/Editor/MassEdit/AutoFill.cs | 19 +++++--------- .../Editor/MassEdit/EditOperation.cs | 12 ++++----- .../Editor/MassEdit/SearchEngine.cs | 26 +++++++++---------- .../ParamEditor/ParamEditorScreen.cs | 2 +- src/StudioCore/ParamEditor/ParamEditorView.cs | 4 +-- src/StudioCore/ParamEditor/ParamRowEditor.cs | 2 +- 7 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index 449ba0159..f53442cd9 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -556,7 +556,7 @@ public static bool PropertyRowRefsContextItems(ParamBank bank, List re ParamMetaData meta = ParamMetaData.Get(bank.Params[rt].AppliedParamdef); var maxResultsPerRefType = 15 / reftypes.Count; - List<(string, Param.Row)> rows = RowSearchEngine.rse.Search((bank, bank.Params[rt]), + List<(string, Param.Row)> rows = TypelessSearchEngine.row.Search((bank, bank.Params[rt]), _refContextCurrentAutoComplete, true, true); foreach ((string param, Param.Row r) in rows) { @@ -792,7 +792,7 @@ public static void DrawCalcCorrectGraph(EditorScreen screen, ParamMetaData meta, var searchTerm = pref.conditionField != null ? $@"prop {fieldName} ^{currentID}$ && prop {pref.conditionField} ^{pref.conditionValue}$" : $@"prop {fieldName} ^{currentID}$"; - return RowSearchEngine.rse.Search((bank, bank.Params[paramName]), searchTerm, false, false).Select((x, i) => x.Item2).ToList(); + return TypelessSearchEngine.row.Search((bank, bank.Params[paramName]), searchTerm, false, false).Select((x, i) => x.Item2).ToList(); } public static bool ImguiTableSeparator() diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index dfbd410b6..0f8e703cd 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -173,19 +173,12 @@ internal string getCurrentStepText(bool valid, string command, int[] argIndices, internal class AutoFill { - private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", ParamRowSelectionSearchEngine.prsse); - private static readonly AutoFillSearchEngine autoFillPrcse = new("prcse", ParamRowClipBoardSearchEngine.prcse); - - private static readonly AutoFillSearchEngine autoFillVse = new("vse", VarSearchEngine.vse); - - private static readonly AutoFillSearchEngine autoFillPse = - new("pse", ParamRowSelectionSearchEngine.prsse); - - private static readonly AutoFillSearchEngine autoFillRse = - new("rse", RowSearchEngine.rse); - - private static readonly AutoFillSearchEngine autoFillCse = - new("cse", CellSearchEngine.cse); + private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", TypelessSearchEngine.paramRowSelection); + private static readonly AutoFillSearchEngine autoFillPrcse = new("prcse", TypelessSearchEngine.paramRowClipboard); + private static readonly AutoFillSearchEngine autoFillPse = new("pse", TypelessSearchEngine.paramRowSelection); + private static readonly AutoFillSearchEngine autoFillRse = new("rse", TypelessSearchEngine.row); + private static readonly AutoFillSearchEngine autoFillCse = new("cse", TypelessSearchEngine.cell); + private static readonly AutoFillSearchEngine autoFillVse = new("vse", TypelessSearchEngine.var); private static string[] _autoFillArgsGop = Enumerable.Repeat("", MEGlobalOperation.globalOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); private static string[] _autoFillArgsRop = Enumerable.Repeat("", MERowOperation.rowOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index ddb5283ec..58c011326 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -580,7 +580,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); + TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); return avg.ToString(); @@ -596,7 +596,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); + TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return avg.ToParamEditorString(); @@ -612,7 +612,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); + TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; return avg.ToParamEditorString(); @@ -628,7 +628,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); + TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -643,7 +643,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - RowSearchEngine.rse.Search((paramB, paramP), field[1], false, false); + TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); return max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -689,7 +689,7 @@ private void Setup() paramFieldRowSelector => { Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; - List<(string, Param.Row)> srcRows = RowSearchEngine.rse.Search((ParamBank.PrimaryBank, srcParam), + List<(string, Param.Row)> srcRows = TypelessSearchEngine.row.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, c, c2) => values[Random.Shared.NextInt64(values.Length)].ToString(); diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 8cebb1b49..084eca4c2 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -17,6 +17,14 @@ namespace StudioCore.Editor.MassEdit; */ internal abstract class TypelessSearchEngine { + // Listing engines here so they are initialised always + public static ParamRowSelectionSearchEngine paramRowSelection = new(); + public static ParamRowClipBoardSearchEngine paramRowClipboard = new(); + public static ParamSearchEngine param = new(ParamBank.PrimaryBank); + public static RowSearchEngine row = new(ParamBank.PrimaryBank); + public static CellSearchEngine cell = new(); + public static VarSearchEngine var = new(); + private static Dictionary> searchEngines = new(); internal static void AddSearchEngine(SearchEngine engine) { @@ -271,8 +279,6 @@ internal SearchEngineCommand(string[] args, string wiki, Func { - public static ParamRowSelectionSearchEngine prsse = new(); - internal override void Setup() { name = "selection"; @@ -291,8 +297,6 @@ internal override void Setup() } internal class ParamRowClipBoardSearchEngine : SearchEngine { - public static ParamRowClipBoardSearchEngine prcse = new(); - internal override void Setup() { name = "clipboard"; @@ -312,10 +316,8 @@ internal override void Setup() internal class ParamSearchEngine : SearchEngine { - public static ParamSearchEngine pse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; - - private ParamSearchEngine(ParamBank bank) + internal ParamSearchEngine(ParamBank bank) { this.bank = bank; } @@ -378,10 +380,9 @@ internal override void Setup() internal class RowSearchEngine : SearchEngine { - public static RowSearchEngine rse = new(ParamBank.PrimaryBank); private readonly ParamBank bank; - private RowSearchEngine(ParamBank bank) + internal RowSearchEngine(ParamBank bank) { this.bank = bank; } @@ -549,7 +550,7 @@ internal override void Setup() return row => { (string paramName, Param.Row row) cseSearchContext = (paramName, row.Item2); - List<(PseudoColumn, Param.Column)> res = CellSearchEngine.cse.Search(cseSearchContext, + List<(PseudoColumn, Param.Column)> res = cell.Search(cseSearchContext, new List<(PseudoColumn, Param.Column)> { testCol }, args[1], lenient, false); return res.Contains(testCol); }; @@ -743,7 +744,7 @@ internal override void Setup() throw new Exception("Could not find param " + otherParam); } - List<(string, Param.Row)> rows = rse.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, + List<(string, Param.Row)> rows = row.Search((ParamBank.PrimaryBank, otherParamReal), otherSearchTerm, lenient, false); (PseudoColumn, Param.Column) otherFieldReal = otherParamReal.GetCol(otherField); if (!otherFieldReal.IsColumnValid()) @@ -842,7 +843,6 @@ internal override void Setup() internal class CellSearchEngine : SearchEngine { - public static CellSearchEngine cse = new(); internal override void Setup() { @@ -983,8 +983,6 @@ internal override void Setup() internal class VarSearchEngine : SearchEngine { - public static VarSearchEngine vse = new(); - internal override void Setup() { name = "variable"; diff --git a/src/StudioCore/ParamEditor/ParamEditorScreen.cs b/src/StudioCore/ParamEditor/ParamEditorScreen.cs index 48062bf5a..056e67674 100644 --- a/src/StudioCore/ParamEditor/ParamEditorScreen.cs +++ b/src/StudioCore/ParamEditor/ParamEditorScreen.cs @@ -840,7 +840,7 @@ public unsafe void OnGUI(string[] initcmd) ParamBank.ClipboardParam = _activeView._selection.GetActiveParam(); foreach (Param.Row row in UICache.GetCached(this, (_activeView._viewIndex, _activeView._selection.GetActiveParam()), - () => RowSearchEngine.rse.Search( + () => TypelessSearchEngine.row.Search( (ParamBank.PrimaryBank, ParamBank.PrimaryBank.Params[_activeView._selection.GetActiveParam()]), _activeView._selection.GetCurrentRowSearchString(), true, true).Select((x, i) => x.Item2))) diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index 35059b3c2..6d9803f7e 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -161,7 +161,7 @@ private void ParamView_ParamList_Main(bool doFocus, float scale, float scrollTo) List paramKeyList = UICache.GetCached(_paramEditor, _viewIndex, () => { List<(ParamBank, Param)> list = - ParamSearchEngine.pse.Search((true, true), _selection.currentParamSearchString, true, true); + TypelessSearchEngine.param.Search((true, true), _selection.currentParamSearchString, true, true); List keyList = list.Where(param => param.Item1 == ParamBank.PrimaryBank) .Select(param => ParamBank.PrimaryBank.GetKeyForParam(param.Item2)).ToList(); @@ -439,7 +439,7 @@ private void ParamView_RowList(bool doFocus, bool isActiveView, float scrollTo, } List rows = UICache.GetCached(_paramEditor, (_viewIndex, activeParam), - () => RowSearchEngine.rse.Search((ParamBank.PrimaryBank, para), + () => TypelessSearchEngine.row.Search((ParamBank.PrimaryBank, para), _selection.GetCurrentRowSearchString(), true, true).Select((x, i) => x.Item2).ToList()); var enableGrouping = !CFG.Current.Param_DisableRowGrouping && ParamMetaData diff --git a/src/StudioCore/ParamEditor/ParamRowEditor.cs b/src/StudioCore/ParamEditor/ParamRowEditor.cs index c1ec3671f..31cea9d2e 100644 --- a/src/StudioCore/ParamEditor/ParamRowEditor.cs +++ b/src/StudioCore/ParamEditor/ParamRowEditor.cs @@ -206,7 +206,7 @@ public void PropEditorParamRow(ParamBank bank, Param.Row row, Param.Row vrow, Li var search = propSearchString; List<(PseudoColumn, Param.Column)> cols = UICache.GetCached(_paramEditor, row, "fieldFilter", - () => CellSearchEngine.cse.Search((activeParam, row), search, true, true).Select(x => (x.Item1, x.Item2)).ToList()); + () => TypelessSearchEngine.cell.Search((activeParam, row), search, true, true).Select(x => (x.Item1, x.Item2)).ToList()); List<(PseudoColumn, Param.Column)> vcols = UICache.GetCached(_paramEditor, vrow, "vFieldFilter", () => cols.Select((x, i) => x.GetAs(ParamBank.VanillaBank.GetParamFromName(activeParam))).ToList()); List> auxCols = UICache.GetCached(_paramEditor, auxRows, From f3b7fe39e8c2ff3d09af4589b80d5ed2a0b3df4a Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 01:10:06 +0100 Subject: [PATCH 49/61] Rename SearchEngine and Typed/lessSearchEngine --- src/StudioCore/Editor/EditorDecorations.cs | 4 +-- src/StudioCore/Editor/MassEdit/AutoFill.cs | 16 +++++------ .../Editor/MassEdit/EditOperation.cs | 12 ++++---- src/StudioCore/Editor/MassEdit/MassEdit.cs | 16 +++++------ .../Editor/MassEdit/SearchEngine.cs | 28 +++++++++---------- .../ParamEditor/ParamEditorScreen.cs | 2 +- src/StudioCore/ParamEditor/ParamEditorView.cs | 4 +-- src/StudioCore/ParamEditor/ParamRowEditor.cs | 2 +- 8 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index f53442cd9..0306b3acf 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -556,7 +556,7 @@ public static bool PropertyRowRefsContextItems(ParamBank bank, List re ParamMetaData meta = ParamMetaData.Get(bank.Params[rt].AppliedParamdef); var maxResultsPerRefType = 15 / reftypes.Count; - List<(string, Param.Row)> rows = TypelessSearchEngine.row.Search((bank, bank.Params[rt]), + List<(string, Param.Row)> rows = SearchEngine.row.Search((bank, bank.Params[rt]), _refContextCurrentAutoComplete, true, true); foreach ((string param, Param.Row r) in rows) { @@ -792,7 +792,7 @@ public static void DrawCalcCorrectGraph(EditorScreen screen, ParamMetaData meta, var searchTerm = pref.conditionField != null ? $@"prop {fieldName} ^{currentID}$ && prop {pref.conditionField} ^{pref.conditionValue}$" : $@"prop {fieldName} ^{currentID}$"; - return TypelessSearchEngine.row.Search((bank, bank.Params[paramName]), searchTerm, false, false).Select((x, i) => x.Item2).ToList(); + return SearchEngine.row.Search((bank, bank.Params[paramName]), searchTerm, false, false).Select((x, i) => x.Item2).ToList(); } public static bool ImguiTableSeparator() diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index 0f8e703cd..d72cd3f5b 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -11,13 +11,13 @@ namespace StudioCore.Editor.MassEdit; internal class AutoFillSearchEngine { private readonly string[] _autoFillArgs; - private readonly TypelessSearchEngine engine; + private readonly SearchEngine engine; private readonly string id; private AutoFillSearchEngine _additionalCondition; private bool _autoFillNotToggle; private bool _useAdditionalCondition; - internal AutoFillSearchEngine(string id, TypelessSearchEngine searchEngine) + internal AutoFillSearchEngine(string id, SearchEngine searchEngine) { this.id = id; engine = searchEngine; @@ -173,12 +173,12 @@ internal string getCurrentStepText(bool valid, string command, int[] argIndices, internal class AutoFill { - private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", TypelessSearchEngine.paramRowSelection); - private static readonly AutoFillSearchEngine autoFillPrcse = new("prcse", TypelessSearchEngine.paramRowClipboard); - private static readonly AutoFillSearchEngine autoFillPse = new("pse", TypelessSearchEngine.paramRowSelection); - private static readonly AutoFillSearchEngine autoFillRse = new("rse", TypelessSearchEngine.row); - private static readonly AutoFillSearchEngine autoFillCse = new("cse", TypelessSearchEngine.cell); - private static readonly AutoFillSearchEngine autoFillVse = new("vse", TypelessSearchEngine.var); + private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", SearchEngine.paramRowSelection); + private static readonly AutoFillSearchEngine autoFillPrcse = new("prcse", SearchEngine.paramRowClipboard); + private static readonly AutoFillSearchEngine autoFillPse = new("pse", SearchEngine.paramRowSelection); + private static readonly AutoFillSearchEngine autoFillRse = new("rse", SearchEngine.row); + private static readonly AutoFillSearchEngine autoFillCse = new("cse", SearchEngine.cell); + private static readonly AutoFillSearchEngine autoFillVse = new("vse", SearchEngine.var); private static string[] _autoFillArgsGop = Enumerable.Repeat("", MEGlobalOperation.globalOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); private static string[] _autoFillArgsRop = Enumerable.Repeat("", MERowOperation.rowOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 58c011326..7363e7716 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -580,7 +580,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); + SearchEngine.row.Search((paramB, paramP), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.Average(val => Convert.ToDouble(val)); return avg.ToString(); @@ -596,7 +596,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); + SearchEngine.row.Search((paramB, paramP), field[1], false, false); IEnumerable vals = rows.Select((row, i) => row.Item2.Get(col)); var avg = vals.OrderBy(val => Convert.ToDouble(val)).ElementAt(vals.Count() / 2); return avg.ToParamEditorString(); @@ -612,7 +612,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); + SearchEngine.row.Search((paramB, paramP), field[1], false, false); var avg = ParamUtils.GetParamValueDistribution(rows.Select((x, i) => x.Item2), col).OrderByDescending(g => g.Item2) .First().Item1; return avg.ToParamEditorString(); @@ -628,7 +628,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); + SearchEngine.row.Search((paramB, paramP), field[1], false, false); var min = rows.Min(r => r.Item2[field[0]].Value.Value); return min.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -643,7 +643,7 @@ private void Setup() } List<(string, Param.Row)>? rows = - TypelessSearchEngine.row.Search((paramB, paramP), field[1], false, false); + SearchEngine.row.Search((paramB, paramP), field[1], false, false); var max = rows.Max(r => r.Item2[field[0]].Value.Value); return max.ToParamEditorString(); }, () => CFG.Current.Param_AdvancedMassedit)); @@ -689,7 +689,7 @@ private void Setup() paramFieldRowSelector => { Param srcParam = ParamBank.PrimaryBank.Params[paramFieldRowSelector[0]]; - List<(string, Param.Row)> srcRows = TypelessSearchEngine.row.Search((ParamBank.PrimaryBank, srcParam), + List<(string, Param.Row)> srcRows = SearchEngine.row.Search((ParamBank.PrimaryBank, srcParam), paramFieldRowSelector[2], false, false); var values = srcRows.Select((r, i) => r.Item2[paramFieldRowSelector[1]].Value.Value).ToArray(); return (i, c, c2) => values[Random.Shared.NextInt64(values.Length)].ToString(); diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index f88e2948b..a0b4480a6 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -46,9 +46,9 @@ internal MEOperationException(string? message) : base(message) internal struct MEFilterStage { internal string command; - internal TypelessSearchEngine engine; + internal SearchEngine engine; // No arguments because this is handled separately in SearchEngine - internal MEFilterStage(string toParse, int line, string stageName, TypelessSearchEngine stageEngine) + internal MEFilterStage(string toParse, int line, string stageName, SearchEngine stageEngine) { command = toParse.Trim(); if (command.Equals("")) @@ -216,9 +216,9 @@ private MassEditResult ParseCommand(string command) if (op != null && op.HandlesCommand(firstStageKeyword)) return ParseOpStep(stage[1], op.NameForHelpTexts(), op); - var nextStage = TypelessSearchEngine.GetSearchEngines(currentType); + var nextStage = SearchEngine.GetSearchEngines(currentType); // Try out each defined search engine for the current type - foreach ((TypelessSearchEngine engine, Type t) in nextStage) + foreach ((SearchEngine engine, Type t) in nextStage) { if (engine.HandlesCommand(firstStageKeyword)) { @@ -229,7 +229,7 @@ private MassEditResult ParseCommand(string command) return ParseFilterStep(command, nextStage.Last().Item1); } - private MassEditResult ParseFilterStep(string stageText, TypelessSearchEngine expectedSearchEngine) + private MassEditResult ParseFilterStep(string stageText, SearchEngine expectedSearchEngine) { var stage = stageText.Split(":", 2); string stageName = expectedSearchEngine.NameForHelpTexts(); @@ -257,9 +257,9 @@ private MassEditResult ParseFilterStep(string stageText, TypelessSearchEngine ex if (op != null && op.HandlesCommand(nextStageKeyword)) return ParseOpStep(stage[1], op.NameForHelpTexts(), op); - var nextStage = TypelessSearchEngine.GetSearchEngines(currentType); + var nextStage = SearchEngine.GetSearchEngines(currentType); // Try out each defined search engine for the current type - foreach ((TypelessSearchEngine engine, Type t) in nextStage) + foreach ((SearchEngine engine, Type t) in nextStage) { if (engine.HandlesCommand(nextStageKeyword)) return ParseFilterStep(restOfStages, engine); @@ -303,7 +303,7 @@ private MassEditResult SandboxMassEditExecution(Func innerFunc) } } - private MassEditResult ExecStage(MEFilterStage info, TypelessSearchEngine engine, int filterDepth, (object, object) contextObject, Dictionary contextObjects, IEnumerable argFuncs) + private MassEditResult ExecStage(MEFilterStage info, SearchEngine engine, int filterDepth, (object, object) contextObject, Dictionary contextObjects, IEnumerable argFuncs) { var editCount = -1; filterDepth++; diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 084eca4c2..7ce4f59da 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -15,7 +15,7 @@ namespace StudioCore.Editor.MassEdit; /* Restricted characters: colon, space, forward slash, ampersand, exclamation mark * */ -internal abstract class TypelessSearchEngine +internal abstract class SearchEngine { // Listing engines here so they are initialised always public static ParamRowSelectionSearchEngine paramRowSelection = new(); @@ -25,21 +25,21 @@ internal abstract class TypelessSearchEngine public static CellSearchEngine cell = new(); public static VarSearchEngine var = new(); - private static Dictionary> searchEngines = new(); - internal static void AddSearchEngine(SearchEngine engine) + private static Dictionary> searchEngines = new(); + internal static void AddSearchEngine(TypedSearchEngine engine) { if (!searchEngines.ContainsKey(typeof((TContextObject, TContextField)))) searchEngines.Add(typeof((TContextObject, TContextField)), new()); searchEngines[typeof((TContextObject, TContextField))].Add((engine, typeof((TElementObject, TElementField)))); } - internal static List<(TypelessSearchEngine, Type)> GetSearchEngines(Type t) //Type t is expected to be (TContextObject, TContextField) + internal static List<(SearchEngine, Type)> GetSearchEngines(Type t) //Type t is expected to be (TContextObject, TContextField) { return searchEngines.GetValueOrDefault(t) ?? ([]); } internal abstract List<(string, string[], string)> VisibleCommands(bool includeDefault); internal abstract List<(string, string[])> AllCommands(); internal abstract List AvailableCommandsForHelpText(); - internal abstract List<(TypelessSearchEngine, Type)> NextSearchEngines(); //Type t is expected to be (TContextObject, TContextField) + internal abstract List<(SearchEngine, Type)> NextSearchEngines(); //Type t is expected to be (TContextObject, TContextField) internal abstract METypelessOperation NextOperation(); internal abstract string NameForHelpTexts(); internal abstract Type getContainerType(); @@ -51,7 +51,7 @@ internal static void AddSearchEngine : TypelessSearchEngine +internal class TypedSearchEngine : SearchEngine { internal SearchEngineCommand<(TContextObject, TContextField), (TElementObject, TElementField)> defaultFilter; @@ -59,7 +59,7 @@ internal class SearchEngine> unpacker; internal string name = "[unnamed search engine]"; - internal SearchEngine() + internal TypedSearchEngine() { Setup(); AddSearchEngine(this); @@ -235,7 +235,7 @@ internal override List AvailableCommandsForHelpText() return liveSet; } - internal override List<(TypelessSearchEngine, Type)> NextSearchEngines() + internal override List<(SearchEngine, Type)> NextSearchEngines() { return GetSearchEngines(typeof((TElementObject, TElementField))); } @@ -277,7 +277,7 @@ internal SearchEngineCommand(string[] args, string wiki, Func +internal class ParamRowSelectionSearchEngine : TypedSearchEngine { internal override void Setup() { @@ -295,7 +295,7 @@ internal override void Setup() return [(typeof((ParamBank, Param)), (ParamBank.PrimaryBank, ParamBank.PrimaryBank.Params[MassParamEditRegex.totalHackPleaseKillme.GetActiveParam()]))]; } } -internal class ParamRowClipBoardSearchEngine : SearchEngine +internal class ParamRowClipBoardSearchEngine : TypedSearchEngine { internal override void Setup() { @@ -314,7 +314,7 @@ internal override void Setup() } } -internal class ParamSearchEngine : SearchEngine +internal class ParamSearchEngine : TypedSearchEngine { private readonly ParamBank bank; internal ParamSearchEngine(ParamBank bank) @@ -378,7 +378,7 @@ internal override void Setup() } } -internal class RowSearchEngine : SearchEngine +internal class RowSearchEngine : TypedSearchEngine { private readonly ParamBank bank; @@ -841,7 +841,7 @@ internal override void Setup() } } -internal class CellSearchEngine : SearchEngine +internal class CellSearchEngine : TypedSearchEngine { internal override void Setup() @@ -981,7 +981,7 @@ internal override void Setup() } } -internal class VarSearchEngine : SearchEngine +internal class VarSearchEngine : TypedSearchEngine { internal override void Setup() { diff --git a/src/StudioCore/ParamEditor/ParamEditorScreen.cs b/src/StudioCore/ParamEditor/ParamEditorScreen.cs index 056e67674..b930e0dac 100644 --- a/src/StudioCore/ParamEditor/ParamEditorScreen.cs +++ b/src/StudioCore/ParamEditor/ParamEditorScreen.cs @@ -840,7 +840,7 @@ public unsafe void OnGUI(string[] initcmd) ParamBank.ClipboardParam = _activeView._selection.GetActiveParam(); foreach (Param.Row row in UICache.GetCached(this, (_activeView._viewIndex, _activeView._selection.GetActiveParam()), - () => TypelessSearchEngine.row.Search( + () => SearchEngine.row.Search( (ParamBank.PrimaryBank, ParamBank.PrimaryBank.Params[_activeView._selection.GetActiveParam()]), _activeView._selection.GetCurrentRowSearchString(), true, true).Select((x, i) => x.Item2))) diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index 6d9803f7e..6e7365a3d 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -161,7 +161,7 @@ private void ParamView_ParamList_Main(bool doFocus, float scale, float scrollTo) List paramKeyList = UICache.GetCached(_paramEditor, _viewIndex, () => { List<(ParamBank, Param)> list = - TypelessSearchEngine.param.Search((true, true), _selection.currentParamSearchString, true, true); + SearchEngine.param.Search((true, true), _selection.currentParamSearchString, true, true); List keyList = list.Where(param => param.Item1 == ParamBank.PrimaryBank) .Select(param => ParamBank.PrimaryBank.GetKeyForParam(param.Item2)).ToList(); @@ -439,7 +439,7 @@ private void ParamView_RowList(bool doFocus, bool isActiveView, float scrollTo, } List rows = UICache.GetCached(_paramEditor, (_viewIndex, activeParam), - () => TypelessSearchEngine.row.Search((ParamBank.PrimaryBank, para), + () => SearchEngine.row.Search((ParamBank.PrimaryBank, para), _selection.GetCurrentRowSearchString(), true, true).Select((x, i) => x.Item2).ToList()); var enableGrouping = !CFG.Current.Param_DisableRowGrouping && ParamMetaData diff --git a/src/StudioCore/ParamEditor/ParamRowEditor.cs b/src/StudioCore/ParamEditor/ParamRowEditor.cs index 31cea9d2e..06df16b8c 100644 --- a/src/StudioCore/ParamEditor/ParamRowEditor.cs +++ b/src/StudioCore/ParamEditor/ParamRowEditor.cs @@ -206,7 +206,7 @@ public void PropEditorParamRow(ParamBank bank, Param.Row row, Param.Row vrow, Li var search = propSearchString; List<(PseudoColumn, Param.Column)> cols = UICache.GetCached(_paramEditor, row, "fieldFilter", - () => TypelessSearchEngine.cell.Search((activeParam, row), search, true, true).Select(x => (x.Item1, x.Item2)).ToList()); + () => SearchEngine.cell.Search((activeParam, row), search, true, true).Select(x => (x.Item1, x.Item2)).ToList()); List<(PseudoColumn, Param.Column)> vcols = UICache.GetCached(_paramEditor, vrow, "vFieldFilter", () => cols.Select((x, i) => x.GetAs(ParamBank.VanillaBank.GetParamFromName(activeParam))).ToList()); List> auxCols = UICache.GetCached(_paramEditor, auxRows, From 6c5d448ad1cf50bae38434e44f55f6d1df5ffeba Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 01:11:17 +0100 Subject: [PATCH 50/61] The bigger initialisation meme maybe this shouldn't be class initalised huh --- src/StudioCore/Editor/MassEdit/SearchEngine.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 7ce4f59da..78d5590fe 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -17,6 +17,8 @@ namespace StudioCore.Editor.MassEdit; */ internal abstract class SearchEngine { + + private static Dictionary> searchEngines = new(); // Listing engines here so they are initialised always public static ParamRowSelectionSearchEngine paramRowSelection = new(); public static ParamRowClipBoardSearchEngine paramRowClipboard = new(); @@ -24,8 +26,6 @@ internal abstract class SearchEngine public static RowSearchEngine row = new(ParamBank.PrimaryBank); public static CellSearchEngine cell = new(); public static VarSearchEngine var = new(); - - private static Dictionary> searchEngines = new(); internal static void AddSearchEngine(TypedSearchEngine engine) { if (!searchEngines.ContainsKey(typeof((TContextObject, TContextField)))) From bda69090f36768ca2eb03f7c63b103bb253c7f0a Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 01:28:00 +0100 Subject: [PATCH 51/61] Same for Operations --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 24 +++++++++---------- .../Editor/MassEdit/EditOperation.cs | 22 +++++++++++------ .../Editor/MassEdit/SearchEngine.cs | 24 +++++++++++++------ 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index d72cd3f5b..b99a7e6b0 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -180,9 +180,9 @@ internal class AutoFill private static readonly AutoFillSearchEngine autoFillCse = new("cse", SearchEngine.cell); private static readonly AutoFillSearchEngine autoFillVse = new("vse", SearchEngine.var); - private static string[] _autoFillArgsGop = Enumerable.Repeat("", MEGlobalOperation.globalOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); - private static string[] _autoFillArgsRop = Enumerable.Repeat("", MERowOperation.rowOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); - private static string[] _autoFillArgsCop = Enumerable.Repeat("", MECellOperation.cellOps.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); + private static string[] _autoFillArgsGop = Enumerable.Repeat("", METypelessOperation.global.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); + private static string[] _autoFillArgsRop = Enumerable.Repeat("", METypelessOperation.row.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); + private static string[] _autoFillArgsCop = Enumerable.Repeat("", METypelessOperation.cell.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length)).ToArray(); @@ -262,11 +262,11 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); + return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = MassEditAutoFillForOperation(MERowOperation.rowOps, ref _autoFillArgsRop, ";", null); + var res2 = MassEditAutoFillForOperation(METypelessOperation.row, ref _autoFillArgsRop, ";", null); if (res1 != null) { return res1; @@ -292,11 +292,11 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); + return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = MassEditAutoFillForOperation(MERowOperation.rowOps, ref _autoFillArgsRop, ";", null); + var res2 = MassEditAutoFillForOperation(METypelessOperation.row, ref _autoFillArgsRop, ";", null); if (res1 != null) { return res1; @@ -333,7 +333,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", + return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); }); string res2 = null; @@ -341,7 +341,7 @@ public static string MassEditCompleteAutoFill() { ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - res2 = MassEditAutoFillForOperation(MERowOperation.rowOps, ref _autoFillArgsRop, ";", null); + res2 = MassEditAutoFillForOperation(METypelessOperation.row, ref _autoFillArgsRop, ";", null); } if (res1 != null) @@ -360,7 +360,7 @@ public static string MassEditCompleteAutoFill() ImGui.Separator(); ImGui.PushID("globalop"); ImGui.TextColored(HINTCOLOUR, "Select global operation..."); - result3 = MassEditAutoFillForOperation(MEGlobalOperation.globalOps, ref _autoFillArgsGop, ";", + result3 = MassEditAutoFillForOperation(METypelessOperation.global, ref _autoFillArgsGop, ";", null); ImGui.PopID(); if (MassParamEdit.massEditVars.Count != 0) @@ -376,7 +376,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select value operation..."); - return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", + return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); }); } @@ -406,7 +406,7 @@ public static string MassEditCompleteAutoFill() public static string MassEditOpAutoFill() { - return MassEditAutoFillForOperation(MECellOperation.cellOps, ref _autoFillArgsCop, ";", null); + return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); } private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 7363e7716..bdce71739 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -38,7 +38,21 @@ internal MEOperationDef(string[] args, string tooltip, Func editOperations = new(); + private static Dictionary editOperations; + + internal static MEGlobalOperation global; + internal static MERowOperation row; + internal static MECellOperation cell; + internal static MEVarOperation var; + static METypelessOperation() + { + editOperations = new(); + global = new(); + row = new(); + cell = new(); + var = new(); + } + internal static void AddEditOperation(MEOperation engine) { editOperations[typeof(TMECategory)] = engine; @@ -95,8 +109,6 @@ internal override string NameForHelpTexts() internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool, bool> { - internal static MEGlobalOperation globalOps = new(); - internal override void Setup() { name = "global"; @@ -150,8 +162,6 @@ internal override void UseResult(List actionList, (object, object) internal class MERowOperation : MEOperation<(string, Param.Row), string, Param.Row, (Param, Param.Row)> //technically we're still using string as the containing object in place of Param { - public static MERowOperation rowOps = new(); - internal override void Setup() { name = "row"; @@ -325,7 +335,6 @@ internal override bool ValidateResult(object res) } internal class MECellOperation : MEValueOperation<(PseudoColumn, Param.Column)> { - public static MECellOperation cellOps = new(); internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { (string param, Param.Row row) = ((string, Param.Row))contextObjects[typeof((string, Param.Row))]; @@ -341,7 +350,6 @@ internal override void UseResult(List actionList, (object, object) } internal class MEVarOperation : MEValueOperation { - public static MEVarOperation varOps = new(); internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { return MassParamEdit.massEditVars[(string)currentObject.Item2]; diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index 78d5590fe..bf294f42f 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -18,14 +18,24 @@ namespace StudioCore.Editor.MassEdit; internal abstract class SearchEngine { - private static Dictionary> searchEngines = new(); + private static Dictionary> searchEngines; // Listing engines here so they are initialised always - public static ParamRowSelectionSearchEngine paramRowSelection = new(); - public static ParamRowClipBoardSearchEngine paramRowClipboard = new(); - public static ParamSearchEngine param = new(ParamBank.PrimaryBank); - public static RowSearchEngine row = new(ParamBank.PrimaryBank); - public static CellSearchEngine cell = new(); - public static VarSearchEngine var = new(); + public static ParamRowSelectionSearchEngine paramRowSelection; + public static ParamRowClipBoardSearchEngine paramRowClipboard; + public static ParamSearchEngine param; + public static RowSearchEngine row; + public static CellSearchEngine cell; + public static VarSearchEngine var; + static SearchEngine(){ + searchEngines = new(); + paramRowSelection = new(); + paramRowClipboard = new(); + param = new(ParamBank.PrimaryBank); + row = new(ParamBank.PrimaryBank); + cell = new(); + var = new(); + } + internal static void AddSearchEngine(TypedSearchEngine engine) { if (!searchEngines.ContainsKey(typeof((TContextObject, TContextField)))) From 8f8d6ba98fd205bf6d051e17e777a9de71fa6efa Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 01:43:05 +0100 Subject: [PATCH 52/61] Better control over how results are used. Actual 0 argument arggetter fix. --- .../Editor/MassEdit/EditOperation.cs | 37 +++++++++++-------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 8 +++- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index bdce71739..05d16cbc7 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -65,7 +65,7 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract Dictionary AllCommands(); internal abstract string NameForHelpTexts(); internal abstract object GetElementValue((object, object) currentObject, Dictionary contextObjects); - internal abstract bool ValidateResult(object res); + internal abstract ResultValidity ValidateResult(object res); internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); internal abstract bool HandlesCommand(string command); } @@ -149,9 +149,9 @@ internal override object GetElementValue((object, object) currentObject, Diction return true; //Global op technically has no context / uses the dummy context of boolean } - internal override bool ValidateResult(object res) + internal override ResultValidity ValidateResult(object res) { - return true; + return ResultValidity.SKIP; //Glocal ops don't do anything with the resulting obj } internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) @@ -245,14 +245,16 @@ internal override object GetElementValue((object, object) currentObject, Diction return currentObject.Item2; } - internal override bool ValidateResult(object res) + internal override ResultValidity ValidateResult(object res) { if (res.GetType() != typeof((Param, Param.Row))) - return false; + return ResultValidity.ERROR; (Param, Param.Row) r2 = ((Param, Param.Row))res; if (r2.Item1 == null) - return false; - return true; + return ResultValidity.ERROR; + if (r2.Item2 == null) + return ResultValidity.SKIP; + return ResultValidity.OK; } internal override void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res) @@ -326,11 +328,11 @@ internal override void Setup() (value, args) => MassParamEdit.WithDynamicOf(value, v => Math.Min(v, double.Parse(args[0]))), () => CFG.Current.Param_AdvancedMassedit); } - internal override bool ValidateResult(object res) + internal override ResultValidity ValidateResult(object res) { if (res == null) - return false; - return true; + return ResultValidity.ERROR; + return ResultValidity.OK; } } internal class MECellOperation : MEValueOperation<(PseudoColumn, Param.Column)> @@ -361,6 +363,13 @@ internal override void UseResult(List actionList, (object, object) } } +internal enum ResultValidity +{ + OK, + SKIP, + ERROR +} + internal class MEOperationArgument { internal static MEOperationArgument arg = new(); @@ -816,10 +825,8 @@ internal OperationArgumentGetter(string[] args, string wiki, this.func = func; this.shouldShow = shouldShow; } - - - } + internal static class OAGFuncExtension { /*internal static object tryFold(this Func func, object newContextInput) @@ -848,8 +855,8 @@ internal static object assertCompleteContextOrThrow(this object maybeFunc, int e Delegate func = (Delegate)maybeFunc; var parameters = func.Method.GetParameters(); /* bool is provided as a special context argument for no context */ - if (parameters.Length == 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(bool)) - return assertCompleteContextOrThrow(func.DynamicInvoke(editIndex, false), editIndex); + if (parameters.Length == 3 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(bool) && parameters[2].ParameterType == typeof(bool)) + return assertCompleteContextOrThrow(func.DynamicInvoke(editIndex, false, false), editIndex); else throw new MEOperationException("Argument getter did not have enough context to determine the value to use."); } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index a0b4480a6..119846ab0 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -341,11 +341,15 @@ private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerabl { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(_currentLine).ToParamEditorString()).ToArray(); var opResult = parsedOp.function(currentObject.Item1, opType.GetElementValue(currentObject, contextObjects), argValues); - if (!opType.ValidateResult(opResult)) + ResultValidity res = opType.ValidateResult(opResult); + if (res == ResultValidity.ERROR) { return new MassEditResult(MassEditResultType.OPERATIONERROR, $@"Error performing {opName} operation {opInfo.command} (line {_currentLine})"); } - opType.UseResult(_partialActions, currentObject, contextObjects, opResult); + if (res == ResultValidity.OK) + { + opType.UseResult(_partialActions, currentObject, contextObjects, opResult); + } return new MassEditResult(MassEditResultType.SUCCESS, ""); } } From b91d510a86c41dcb94da93121125240a461afb75 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 01:50:57 +0100 Subject: [PATCH 53/61] fix parsing global ops --- src/StudioCore/Editor/MassEdit/MassEdit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index 119846ab0..b74ac472c 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -214,7 +214,7 @@ private MassEditResult ParseCommand(string command) var op = METypelessOperation.GetEditOperation(currentType); // Try run an operation if (op != null && op.HandlesCommand(firstStageKeyword)) - return ParseOpStep(stage[1], op.NameForHelpTexts(), op); + return ParseOpStep(command, op.NameForHelpTexts(), op); var nextStage = SearchEngine.GetSearchEngines(currentType); // Try out each defined search engine for the current type From dd3dbfcad8f1e52125e4bd0cc486d8798310247f Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 03:05:31 +0100 Subject: [PATCH 54/61] Move operation autofill into its own object --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 224 +++++++++++---------- 1 file changed, 118 insertions(+), 106 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index b99a7e6b0..0876836bc 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -171,6 +171,103 @@ internal string getCurrentStepText(bool valid, string command, int[] argIndices, } } +internal class AutoFillOperation +{ + private readonly string[] _autoFillArgs; + private readonly METypelessOperation op; + private readonly string id; + + internal AutoFillOperation(string id, METypelessOperation operation) + { + this.id = id; + op = operation; + _autoFillArgs = Enumerable.Repeat("", op.AllCommands().Sum(x => x.Value.argNames.Length)).ToArray(); + + } + + internal string MassEditAutoFillForOperation(string suffix, Func subMenu) + { + var currentArgIndex = 0; + string result = null; + foreach (KeyValuePair cmd in op.AllCommands()) + { + string cmdName = cmd.Key; + METypelessOperationDef cmdData = cmd.Value; + var argIndices = new int[cmdData.argNames.Length]; + var valid = true; + for (var i = 0; i < argIndices.Length; i++) + { + argIndices[i] = currentArgIndex; + currentArgIndex++; + if (string.IsNullOrEmpty(_autoFillArgs[argIndices[i]])) + { + valid = false; + } + } + if (cmdData.shouldShow != null && !cmdData.shouldShow()) + continue; + + var wiki = cmdData.wiki; + UIHints.AddImGuiHintButton(cmdName, ref wiki, false, true); + if (subMenu != null) + { + if (ImGui.BeginMenu(cmdName, valid)) + { + result = subMenu(); + ImGui.EndMenu(); + } + } + else + { + result = ImGui.Selectable(cmdName, false, + valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) + ? suffix + : null; + } + + ImGui.Indent(); + for (var i = 0; i < argIndices.Length; i++) + { + if (i != 0) + { + ImGui.SameLine(); + } + + ImGui.InputTextWithHint("##meautoinputop" + argIndices[i], cmdData.argNames[i], + ref _autoFillArgs[argIndices[i]], 256); + ImGui.SameLine(); + ImGui.Button($@"{ForkAwesome.CaretDown}"); + if (ImGui.BeginPopupContextItem("##meautoinputoapopup" + argIndices[i], + ImGuiPopupFlags.MouseButtonLeft)) + { + var opargResult = AutoFill.MassEditAutoFillForArguments(); + if (opargResult != null) + { + _autoFillArgs[argIndices[i]] = opargResult; + } + + ImGui.EndPopup(); + } + } + + ImGui.Unindent(); + if (result != null && valid) + { + var argText = argIndices.Length > 0 ? _autoFillArgs[argIndices[0]] : null; + for (var i = 1; i < argIndices.Length; i++) + { + argText += ":" + _autoFillArgs[argIndices[i]]; + } + + result = cmdName + (argText != null ? " " + argText + result : result); + return result; + } + } + + return result; + } +} + internal class AutoFill { private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", SearchEngine.paramRowSelection); @@ -180,11 +277,12 @@ internal class AutoFill private static readonly AutoFillSearchEngine autoFillCse = new("cse", SearchEngine.cell); private static readonly AutoFillSearchEngine autoFillVse = new("vse", SearchEngine.var); - private static string[] _autoFillArgsGop = Enumerable.Repeat("", METypelessOperation.global.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); - private static string[] _autoFillArgsRop = Enumerable.Repeat("", METypelessOperation.row.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); - private static string[] _autoFillArgsCop = Enumerable.Repeat("", METypelessOperation.cell.AllCommands().Sum((x) => x.Value.argNames.Length)).ToArray(); - private static string[] _autoFillArgsOa = - Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length)).ToArray(); + private static readonly AutoFillOperation autoFillGo = new("go", METypelessOperation.global); + private static readonly AutoFillOperation autoFillRo = new("ro", METypelessOperation.row); + private static readonly AutoFillOperation autoFillCo = new("co", METypelessOperation.cell); + private static readonly AutoFillOperation autoFillVo = new("vo", METypelessOperation.var); + + private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length)).ToArray(); private static string _literalArg = ""; @@ -262,11 +360,11 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); + return autoFillCo.MassEditAutoFillForOperation(";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = MassEditAutoFillForOperation(METypelessOperation.row, ref _autoFillArgsRop, ";", null); + var res2 = autoFillRo.MassEditAutoFillForOperation(";", null); if (res1 != null) { return res1; @@ -292,11 +390,11 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); + return autoFillCo.MassEditAutoFillForOperation(";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = MassEditAutoFillForOperation(METypelessOperation.row, ref _autoFillArgsRop, ";", null); + var res2 = autoFillRo.MassEditAutoFillForOperation(";", null); if (res1 != null) { return res1; @@ -333,15 +431,14 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", - null); + return autoFillCo.MassEditAutoFillForOperation(";", null); }); string res2 = null; if (CFG.Current.Param_AdvancedMassedit) { ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - res2 = MassEditAutoFillForOperation(METypelessOperation.row, ref _autoFillArgsRop, ";", null); + res2 = autoFillRo.MassEditAutoFillForOperation(";", null); } if (res1 != null) @@ -360,8 +457,7 @@ public static string MassEditCompleteAutoFill() ImGui.Separator(); ImGui.PushID("globalop"); ImGui.TextColored(HINTCOLOUR, "Select global operation..."); - result3 = MassEditAutoFillForOperation(METypelessOperation.global, ref _autoFillArgsGop, ";", - null); + result3 = autoFillGo.MassEditAutoFillForOperation(";", null); ImGui.PopID(); if (MassParamEdit.massEditVars.Count != 0) { @@ -376,8 +472,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select value operation..."); - return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", - null); + return autoFillVo.MassEditAutoFillForOperation(";", null); }); } } @@ -406,97 +501,14 @@ public static string MassEditCompleteAutoFill() public static string MassEditOpAutoFill() { - return MassEditAutoFillForOperation(METypelessOperation.cell, ref _autoFillArgsCop, ";", null); - } - - private static string MassEditAutoFillForOperation(MEOperation ops, ref string[] staticArgs, - string suffix, Func subMenu) - { - var currentArgIndex = 0; - string result = null; - foreach (KeyValuePair cmd in ops.AllCommands()) - { - string cmdName = cmd.Key; - METypelessOperationDef cmdData = cmd.Value; - var argIndices = new int[cmdData.argNames.Length]; - var valid = true; - for (var i = 0; i < argIndices.Length; i++) - { - argIndices[i] = currentArgIndex; - currentArgIndex++; - if (string.IsNullOrEmpty(staticArgs[argIndices[i]])) - { - valid = false; - } - } - if (cmdData.shouldShow != null && !cmdData.shouldShow()) - continue; - - var wiki = cmdData.wiki; - UIHints.AddImGuiHintButton(cmdName, ref wiki, false, true); - if (subMenu != null) - { - if (ImGui.BeginMenu(cmdName, valid)) - { - result = subMenu(); - ImGui.EndMenu(); - } - } - else - { - result = ImGui.Selectable(cmdName, false, - valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) - ? suffix - : null; - } - - ImGui.Indent(); - for (var i = 0; i < argIndices.Length; i++) - { - if (i != 0) - { - ImGui.SameLine(); - } - - ImGui.InputTextWithHint("##meautoinputop" + argIndices[i], cmdData.argNames[i], - ref staticArgs[argIndices[i]], 256); - ImGui.SameLine(); - ImGui.Button($@"{ForkAwesome.CaretDown}"); - if (ImGui.BeginPopupContextItem("##meautoinputoapopup" + argIndices[i], - ImGuiPopupFlags.MouseButtonLeft)) - { - var opargResult = MassEditAutoFillForArguments(MEOperationArgument.arg, ref _autoFillArgsOa); - if (opargResult != null) - { - staticArgs[argIndices[i]] = opargResult; - } - - ImGui.EndPopup(); - } - } - - ImGui.Unindent(); - if (result != null && valid) - { - var argText = argIndices.Length > 0 ? staticArgs[argIndices[0]] : null; - for (var i = 1; i < argIndices.Length; i++) - { - argText += ":" + staticArgs[argIndices[i]]; - } - - result = cmdName + (argText != null ? " " + argText + result : result); - return result; - } - } - - return result; + return autoFillCo.MassEditAutoFillForOperation(";", null); } - private static string MassEditAutoFillForArguments(MEOperationArgument oa, ref string[] staticArgs) + internal static string MassEditAutoFillForArguments() { var currentArgIndex = 0; string result = null; - foreach ((string, string, string[]) arg in oa.VisibleArguments()) + foreach ((string, string, string[]) arg in MEOperationArgument.arg.VisibleArguments()) { var argIndices = new int[arg.Item3.Length]; var valid = true; @@ -504,7 +516,7 @@ private static string MassEditAutoFillForArguments(MEOperationArgument oa, ref s { argIndices[i] = currentArgIndex; currentArgIndex++; - if (string.IsNullOrEmpty(staticArgs[argIndices[i]])) + if (string.IsNullOrEmpty(_autoFillArgsOa[argIndices[i]])) { valid = false; } @@ -520,7 +532,7 @@ private static string MassEditAutoFillForArguments(MEOperationArgument oa, ref s var argText = ""; for (var i = 0; i < argIndices.Length; i++) { - argText += " " + staticArgs[argIndices[i]]; + argText += " " + _autoFillArgsOa[argIndices[i]]; } return arg.Item1 + argText; @@ -535,11 +547,11 @@ private static string MassEditAutoFillForArguments(MEOperationArgument oa, ref s } ImGui.InputTextWithHint("##meautoinputoa" + argIndices[i], arg.Item3[i], - ref staticArgs[argIndices[i]], 256); + ref _autoFillArgsOa[argIndices[i]], 256); var var = MassEditAutoFillForVars(argIndices[i]); if (var != null) { - staticArgs[argIndices[i]] = var; + _autoFillArgsOa[argIndices[i]] = var; } } From dbc9d519d29c2d6e12ce97daf355a852ff183e61 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 03:08:41 +0100 Subject: [PATCH 55/61] remove special bonus arg --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index 0876836bc..dd5bf8081 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -282,9 +282,7 @@ internal class AutoFill private static readonly AutoFillOperation autoFillCo = new("co", METypelessOperation.cell); private static readonly AutoFillOperation autoFillVo = new("vo", METypelessOperation.var); - private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length)).ToArray(); - - private static string _literalArg = ""; + private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length) + 1).ToArray(); internal static Vector4 HINTCOLOUR = new(0.3f, 0.5f, 1.0f, 1.0f); internal static Vector4 PREVIEWCOLOUR = new(0.65f, 0.75f, 0.65f, 1.0f); @@ -574,10 +572,10 @@ internal static string MassEditAutoFillForArguments() ImGui.Separator(); if (ImGui.Selectable("Exactly...")) { - result = '"' + _literalArg + '"'; + result = '"' + _autoFillArgsOa[_autoFillArgsOa.Length-1] + '"'; } - ImGui.InputTextWithHint("##meautoinputoaExact", "literal value...", ref _literalArg, 256); + ImGui.InputTextWithHint("##meautoinputoaExact", "literal value...", ref _autoFillArgsOa[_autoFillArgsOa.Length-1], 256); return result; } From 7863d816bc62de9aef0515e593e3ada2d1a59154 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 03:18:00 +0100 Subject: [PATCH 56/61] Rename, remove defunct multistage option --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 86 ++++++++++------------ 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index dd5bf8081..c1a02c22d 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -17,24 +17,26 @@ internal class AutoFillSearchEngine private bool _autoFillNotToggle; private bool _useAdditionalCondition; - internal AutoFillSearchEngine(string id, SearchEngine searchEngine) + internal AutoFillSearchEngine(SearchEngine searchEngine) { - this.id = id; + AutoFill._imguiID++; + id = "e" + AutoFill._imguiID; engine = searchEngine; _autoFillArgs = Enumerable.Repeat("", engine.AllCommands().Sum(x => x.Item2.Length)).ToArray(); _autoFillNotToggle = false; _useAdditionalCondition = false; _additionalCondition = null; } - - internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, - Func subMenu) + private AutoFillSearchEngine(AutoFillSearchEngine parentEngine) { - return Menu(enableComplexToggles, null, enableDefault, suffix, inheritedCommand, subMenu); + id = parentEngine.id + "+"; + engine = parentEngine.engine; + _autoFillArgs = Enumerable.Repeat("", engine.AllCommands().Sum(x => x.Item2.Length)).ToArray(); + _autoFillNotToggle = false; + _useAdditionalCondition = false; + _additionalCondition = null; } - - internal string Menu(bool enableComplexToggles, AutoFillSearchEngine multiStageSE, - bool enableDefault, string suffix, string inheritedCommand, Func subMenu) + internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, Func subMenu) { var currentArgIndex = 0; if (enableComplexToggles) @@ -44,15 +46,10 @@ internal string Menu(bool enableComplexToggles, AutoFillSearchEngine multiStageS ImGui.Checkbox("Add another condition?##meautoinputadditionalcondition" + id, ref _useAdditionalCondition); } - else if (multiStageSE != null) - { - ImGui.Checkbox("Add another condition?##meautoinputadditionalcondition" + id, - ref _useAdditionalCondition); - } if (_useAdditionalCondition && _additionalCondition == null) { - _additionalCondition = new AutoFillSearchEngine(id + "0", engine); + _additionalCondition = new AutoFillSearchEngine(this); } else if (!_useAdditionalCondition) { @@ -83,12 +80,7 @@ internal string Menu(bool enableComplexToggles, AutoFillSearchEngine multiStageS { var curResult = inheritedCommand + getCurrentStepText(valid, cmd.Item1, argIndices, _additionalCondition != null ? " && " : suffix); - if (_useAdditionalCondition && multiStageSE != null) - { - subResult = multiStageSE.Menu(enableComplexToggles, enableDefault, suffix, curResult, - subMenu); - } - else if (_additionalCondition != null) + if (_additionalCondition != null) { subResult = _additionalCondition.Menu(enableComplexToggles, enableDefault, suffix, curResult, subMenu); @@ -177,15 +169,16 @@ internal class AutoFillOperation private readonly METypelessOperation op; private readonly string id; - internal AutoFillOperation(string id, METypelessOperation operation) + internal AutoFillOperation(METypelessOperation operation) { - this.id = id; + AutoFill._imguiID++; + id = "e" + AutoFill._imguiID; op = operation; _autoFillArgs = Enumerable.Repeat("", op.AllCommands().Sum(x => x.Value.argNames.Length)).ToArray(); } - internal string MassEditAutoFillForOperation(string suffix, Func subMenu) + internal string Menu(string suffix, Func subMenu) { var currentArgIndex = 0; string result = null; @@ -270,17 +263,18 @@ internal string MassEditAutoFillForOperation(string suffix, Func subMenu internal class AutoFill { - private static readonly AutoFillSearchEngine autoFillPrsse = new("prsse", SearchEngine.paramRowSelection); - private static readonly AutoFillSearchEngine autoFillPrcse = new("prcse", SearchEngine.paramRowClipboard); - private static readonly AutoFillSearchEngine autoFillPse = new("pse", SearchEngine.paramRowSelection); - private static readonly AutoFillSearchEngine autoFillRse = new("rse", SearchEngine.row); - private static readonly AutoFillSearchEngine autoFillCse = new("cse", SearchEngine.cell); - private static readonly AutoFillSearchEngine autoFillVse = new("vse", SearchEngine.var); - - private static readonly AutoFillOperation autoFillGo = new("go", METypelessOperation.global); - private static readonly AutoFillOperation autoFillRo = new("ro", METypelessOperation.row); - private static readonly AutoFillOperation autoFillCo = new("co", METypelessOperation.cell); - private static readonly AutoFillOperation autoFillVo = new("vo", METypelessOperation.var); + internal static int _imguiID = 0; + private static readonly AutoFillSearchEngine autoFillPrsse = new(SearchEngine.paramRowSelection); + private static readonly AutoFillSearchEngine autoFillPrcse = new(SearchEngine.paramRowClipboard); + private static readonly AutoFillSearchEngine autoFillPse = new(SearchEngine.paramRowSelection); + private static readonly AutoFillSearchEngine autoFillRse = new(SearchEngine.row); + private static readonly AutoFillSearchEngine autoFillCse = new(SearchEngine.cell); + private static readonly AutoFillSearchEngine autoFillVse = new(SearchEngine.var); + + private static readonly AutoFillOperation autoFillGo = new(METypelessOperation.global); + private static readonly AutoFillOperation autoFillRo = new(METypelessOperation.row); + private static readonly AutoFillOperation autoFillCo = new(METypelessOperation.cell); + private static readonly AutoFillOperation autoFillVo = new(METypelessOperation.var); private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length) + 1).ToArray(); @@ -342,7 +336,7 @@ public static string MassEditCompleteAutoFill() /*special case*/ ImGui.PushID("paramrowselection"); ImGui.TextColored(HINTCOLOUR, "Select param and rows..."); - var result0 = autoFillPrsse.Menu(false, autoFillRse, false, ": ", null, inheritedCommand => + var result0 = autoFillPrsse.Menu(false, false, ": ", null, inheritedCommand => { if (inheritedCommand != null) { @@ -358,11 +352,11 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.MassEditAutoFillForOperation(";", null); + return autoFillCo.Menu(";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = autoFillRo.MassEditAutoFillForOperation(";", null); + var res2 = autoFillRo.Menu(";", null); if (res1 != null) { return res1; @@ -372,7 +366,7 @@ public static string MassEditCompleteAutoFill() }); ImGui.PopID(); ImGui.PushID("paramrowclipboard"); - var result1 = autoFillPrcse.Menu(false, autoFillRse, false, ": ", null, inheritedCommand => + var result1 = autoFillPrcse.Menu(false, false, ": ", null, inheritedCommand => { if (inheritedCommand != null) { @@ -388,11 +382,11 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.MassEditAutoFillForOperation(";", null); + return autoFillCo.Menu(";", null); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = autoFillRo.MassEditAutoFillForOperation(";", null); + var res2 = autoFillRo.Menu(";", null); if (res1 != null) { return res1; @@ -429,14 +423,14 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.MassEditAutoFillForOperation(";", null); + return autoFillCo.Menu(";", null); }); string res2 = null; if (CFG.Current.Param_AdvancedMassedit) { ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - res2 = autoFillRo.MassEditAutoFillForOperation(";", null); + res2 = autoFillRo.Menu(";", null); } if (res1 != null) @@ -455,7 +449,7 @@ public static string MassEditCompleteAutoFill() ImGui.Separator(); ImGui.PushID("globalop"); ImGui.TextColored(HINTCOLOUR, "Select global operation..."); - result3 = autoFillGo.MassEditAutoFillForOperation(";", null); + result3 = autoFillGo.Menu(";", null); ImGui.PopID(); if (MassParamEdit.massEditVars.Count != 0) { @@ -470,7 +464,7 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select value operation..."); - return autoFillVo.MassEditAutoFillForOperation(";", null); + return autoFillVo.Menu(";", null); }); } } @@ -499,7 +493,7 @@ public static string MassEditCompleteAutoFill() public static string MassEditOpAutoFill() { - return autoFillCo.MassEditAutoFillForOperation(";", null); + return autoFillCo.Menu(";", null); } internal static string MassEditAutoFillForArguments() From f9a96f41a8865d5fe0499321068edddfa4a7aceb Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Thu, 18 Apr 2024 03:20:29 +0100 Subject: [PATCH 57/61] rename operation stuff --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 16 ++++++------ .../Editor/MassEdit/EditOperation.cs | 26 +++++++++---------- src/StudioCore/Editor/MassEdit/MassEdit.cs | 14 +++++----- .../Editor/MassEdit/SearchEngine.cs | 6 ++--- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index c1a02c22d..f880016f8 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -166,10 +166,10 @@ internal string getCurrentStepText(bool valid, string command, int[] argIndices, internal class AutoFillOperation { private readonly string[] _autoFillArgs; - private readonly METypelessOperation op; + private readonly OperationCategory op; private readonly string id; - internal AutoFillOperation(METypelessOperation operation) + internal AutoFillOperation(OperationCategory operation) { AutoFill._imguiID++; id = "e" + AutoFill._imguiID; @@ -271,12 +271,12 @@ internal class AutoFill private static readonly AutoFillSearchEngine autoFillCse = new(SearchEngine.cell); private static readonly AutoFillSearchEngine autoFillVse = new(SearchEngine.var); - private static readonly AutoFillOperation autoFillGo = new(METypelessOperation.global); - private static readonly AutoFillOperation autoFillRo = new(METypelessOperation.row); - private static readonly AutoFillOperation autoFillCo = new(METypelessOperation.cell); - private static readonly AutoFillOperation autoFillVo = new(METypelessOperation.var); + private static readonly AutoFillOperation autoFillGo = new(OperationCategory.global); + private static readonly AutoFillOperation autoFillRo = new(OperationCategory.row); + private static readonly AutoFillOperation autoFillCo = new(OperationCategory.cell); + private static readonly AutoFillOperation autoFillVo = new(OperationCategory.var); - private static string[] _autoFillArgsOa = Enumerable.Repeat("", MEOperationArgument.arg.AllArguments().Sum(x => x.Item2.Length) + 1).ToArray(); + private static string[] _autoFillArgsOa = Enumerable.Repeat("", OperationArguments.arg.AllArguments().Sum(x => x.Item2.Length) + 1).ToArray(); internal static Vector4 HINTCOLOUR = new(0.3f, 0.5f, 1.0f, 1.0f); internal static Vector4 PREVIEWCOLOUR = new(0.65f, 0.75f, 0.65f, 1.0f); @@ -500,7 +500,7 @@ internal static string MassEditAutoFillForArguments() { var currentArgIndex = 0; string result = null; - foreach ((string, string, string[]) arg in MEOperationArgument.arg.VisibleArguments()) + foreach ((string, string, string[]) arg in OperationArguments.arg.VisibleArguments()) { var argIndices = new int[arg.Item3.Length]; var valid = true; diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 05d16cbc7..9813938da 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -36,15 +36,15 @@ internal MEOperationDef(string[] args, string tooltip, Func editOperations; + private static Dictionary editOperations; internal static MEGlobalOperation global; internal static MERowOperation row; internal static MECellOperation cell; internal static MEVarOperation var; - static METypelessOperation() + static OperationCategory() { editOperations = new(); global = new(); @@ -53,11 +53,11 @@ static METypelessOperation() var = new(); } - internal static void AddEditOperation(MEOperation engine) + internal static void AddEditOperation(TypedOperationCategory engine) { editOperations[typeof(TMECategory)] = engine; } - internal static METypelessOperation GetEditOperation(Type t) + internal static OperationCategory GetEditOperation(Type t) { return editOperations.GetValueOrDefault(t); } @@ -69,12 +69,12 @@ internal static METypelessOperation GetEditOperation(Type t) internal abstract void UseResult(List actionList, (object, object) currentObject, Dictionary contextObjects, object res); internal abstract bool HandlesCommand(string command); } -internal abstract class MEOperation : METypelessOperation +internal abstract class TypedOperationCategory : OperationCategory { internal Dictionary operations = new(); internal string name = "[Unnamed operation type]"; - internal MEOperation() + internal TypedOperationCategory() { Setup(); AddEditOperation(this); @@ -107,7 +107,7 @@ internal override string NameForHelpTexts() } } -internal class MEGlobalOperation : MEOperation<(bool, bool), bool, bool, bool> +internal class MEGlobalOperation : TypedOperationCategory<(bool, bool), bool, bool, bool> { internal override void Setup() { @@ -160,7 +160,7 @@ internal override void UseResult(List actionList, (object, object) } } -internal class MERowOperation : MEOperation<(string, Param.Row), string, Param.Row, (Param, Param.Row)> //technically we're still using string as the containing object in place of Param +internal class MERowOperation : TypedOperationCategory<(string, Param.Row), string, Param.Row, (Param, Param.Row)> //technically we're still using string as the containing object in place of Param { internal override void Setup() { @@ -265,7 +265,7 @@ internal override void UseResult(List actionList, (object, object) } } -internal abstract class MEValueOperation : MEOperation +internal abstract class MEValueOperation : TypedOperationCategory { internal override void Setup() { @@ -370,13 +370,13 @@ internal enum ResultValidity ERROR } -internal class MEOperationArgument +internal class OperationArguments { - internal static MEOperationArgument arg = new(); + internal static OperationArguments arg = new(); private readonly Dictionary argumentGetters = new(); private OperationArgumentGetter defaultGetter; - private MEOperationArgument() + private OperationArguments() { Setup(); } diff --git a/src/StudioCore/Editor/MassEdit/MassEdit.cs b/src/StudioCore/Editor/MassEdit/MassEdit.cs index b74ac472c..c2dec0783 100644 --- a/src/StudioCore/Editor/MassEdit/MassEdit.cs +++ b/src/StudioCore/Editor/MassEdit/MassEdit.cs @@ -62,8 +62,8 @@ internal struct MEOperationStage { internal string command; internal string arguments; - internal METypelessOperation operation; - internal MEOperationStage(string toParse, int line, string stageName, METypelessOperation operationType) + internal OperationCategory operation; + internal MEOperationStage(string toParse, int line, string stageName, OperationCategory operationType) { var stage = toParse.TrimStart().Split(' ', 2); command = stage[0].Trim(); @@ -211,7 +211,7 @@ private MassEditResult ParseCommand(string command) string firstStage = stage[0]; string firstStageKeyword = firstStage.Trim().Split(" ", 2)[0]; - var op = METypelessOperation.GetEditOperation(currentType); + var op = OperationCategory.GetEditOperation(currentType); // Try run an operation if (op != null && op.HandlesCommand(firstStageKeyword)) return ParseOpStep(command, op.NameForHelpTexts(), op); @@ -252,7 +252,7 @@ private MassEditResult ParseFilterStep(string stageText, SearchEngine expectedSe string restOfStages = stage[1]; string nextStageKeyword = restOfStages.Trim().Split(" ", 2)[0]; - var op = METypelessOperation.GetEditOperation(currentType); + var op = OperationCategory.GetEditOperation(currentType); // Try run an operation if (op != null && op.HandlesCommand(nextStageKeyword)) return ParseOpStep(stage[1], op.NameForHelpTexts(), op); @@ -267,12 +267,12 @@ private MassEditResult ParseFilterStep(string stageText, SearchEngine expectedSe //Assume it's default search of last search option return ParseFilterStep(restOfStages, nextStage.Last().Item1); } - private MassEditResult ParseOpStep(string stageText, string stageName, METypelessOperation operation) + private MassEditResult ParseOpStep(string stageText, string stageName, OperationCategory operation) { this.operation = new MEOperationStage(stageText, _currentLine, stageName, operation); parsedOp = operation.AllCommands()[this.operation.command]; - argFuncs = MEOperationArgument.arg.getContextualArguments(parsedOp.argNames.Length, this.operation.arguments); + argFuncs = OperationArguments.arg.getContextualArguments(parsedOp.argNames.Length, this.operation.arguments); if (parsedOp.argNames.Length != argFuncs.Length) { return new MassEditResult(MassEditResultType.PARSEERROR, $@"Invalid number of arguments for operation {this.operation.command} (line {_currentLine})"); @@ -337,7 +337,7 @@ private MassEditResult ExecStage(MEFilterStage info, SearchEngine engine, int fi return new MassEditResult(MassEditResultType.SUCCESS, ""); } - private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, METypelessOperation opType) + private MassEditResult ExecOp(MEOperationStage opInfo, string opName, IEnumerable argFuncs, (object, object) currentObject, Dictionary contextObjects, OperationCategory opType) { var argValues = argFuncs.Select(f => f.assertCompleteContextOrThrow(_currentLine).ToParamEditorString()).ToArray(); var opResult = parsedOp.function(currentObject.Item1, opType.GetElementValue(currentObject, contextObjects), argValues); diff --git a/src/StudioCore/Editor/MassEdit/SearchEngine.cs b/src/StudioCore/Editor/MassEdit/SearchEngine.cs index bf294f42f..b7507abcb 100644 --- a/src/StudioCore/Editor/MassEdit/SearchEngine.cs +++ b/src/StudioCore/Editor/MassEdit/SearchEngine.cs @@ -50,7 +50,7 @@ internal static void AddSearchEngine AllCommands(); internal abstract List AvailableCommandsForHelpText(); internal abstract List<(SearchEngine, Type)> NextSearchEngines(); //Type t is expected to be (TContextObject, TContextField) - internal abstract METypelessOperation NextOperation(); + internal abstract OperationCategory NextOperation(); internal abstract string NameForHelpTexts(); internal abstract Type getContainerType(); internal abstract Type getElementType(); @@ -249,9 +249,9 @@ internal override List AvailableCommandsForHelpText() { return GetSearchEngines(typeof((TElementObject, TElementField))); } - internal override METypelessOperation NextOperation() + internal override OperationCategory NextOperation() { - return METypelessOperation.GetEditOperation(typeof((TElementObject, TElementField))); + return OperationCategory.GetEditOperation(typeof((TElementObject, TElementField))); } internal override string NameForHelpTexts() From dd7076cce0b118c8ef6c5e80a7b6ce314161d2a3 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sun, 21 Apr 2024 21:14:31 +0100 Subject: [PATCH 58/61] Autofill now based on type pattern (stage names wrong) --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 194 +++++++++++++-------- 1 file changed, 124 insertions(+), 70 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index f880016f8..ed7286e36 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -5,6 +5,9 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; +using Octokit; +using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; +using DotNext.Collections.Generic; namespace StudioCore.Editor.MassEdit; @@ -26,6 +29,7 @@ internal AutoFillSearchEngine(SearchEngine searchEngine) _autoFillNotToggle = false; _useAdditionalCondition = false; _additionalCondition = null; + AutoFill.autoFillersSE[searchEngine] = this; } private AutoFillSearchEngine(AutoFillSearchEngine parentEngine) { @@ -36,7 +40,7 @@ private AutoFillSearchEngine(AutoFillSearchEngine parentEngine) _useAdditionalCondition = false; _additionalCondition = null; } - internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, Func subMenu) + internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, bool terminal) { var currentArgIndex = 0; if (enableComplexToggles) @@ -74,32 +78,25 @@ internal string Menu(bool enableComplexToggles, bool enableDefault, string suffi var wiki = cmd.Item3; UIHints.AddImGuiHintButton(cmd.Item1 == null ? "hintdefault" : "hint" + cmd.Item1, ref wiki, false, true); - if (subMenu != null || _additionalCondition != null) + if (ImGui.BeginMenu(cmd.Item1 == null ? "Default filter..." : cmd.Item1, valid)) { - if (ImGui.BeginMenu(cmd.Item1 == null ? "Default filter..." : cmd.Item1, valid)) + var curResult = inheritedCommand + getCurrentStepText(valid, cmd.Item1, argIndices, _additionalCondition != null ? " && " : suffix); + if (_additionalCondition != null) { - var curResult = inheritedCommand + getCurrentStepText(valid, cmd.Item1, argIndices, - _additionalCondition != null ? " && " : suffix); - if (_additionalCondition != null) - { - subResult = _additionalCondition.Menu(enableComplexToggles, enableDefault, suffix, - curResult, subMenu); - } - else - { - subResult = subMenu(curResult); - } - - ImGui.EndMenu(); + subResult = _additionalCondition.Menu(enableComplexToggles, enableDefault, suffix, curResult, terminal); + } + else + { + subResult = SubMenu(curResult, suffix); } + + ImGui.EndMenu(); } + /* else { - subResult = ImGui.Selectable(cmd.Item1 == null ? "Default filter..." : cmd.Item1, false, - valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) - ? suffix - : null; - } + subResult = ImGui.Selectable(cmd.Item1 == null ? "Default filter..." : cmd.Item1, false, valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) ? suffix : null; + }*/ //ImGui.Indent(); for (var i = 0; i < argIndices.Length; i++) @@ -130,6 +127,53 @@ internal string Menu(bool enableComplexToggles, bool enableDefault, string suffi return null; } + private string SubMenu(string inheritedCommand, string suffix) + { + if (inheritedCommand != null) + { + ImGui.TextColored(AutoFill.PREVIEWCOLOUR, inheritedCommand); + } + + IEnumerable afses = getChildAutoFillSearchEngines(); + string res1 = null; + foreach (AutoFillSearchEngine afse in afses) + { + ImGui.Separator(); + ImGui.TextColored(AutoFill.HINTCOLOUR, "Select fields..."); + res1 = afse.Menu(true, true, ": ", inheritedCommand, false); + if (res1 != null) + { + return res1; + } + } + AutoFillOperation afo = getChildAutoFillOperation(); + if (afo != null) + { + ImGui.Separator(); + ImGui.TextColored(AutoFill.HINTCOLOUR, "Select row operation..."); + var res2 = afo.Menu(";"); + if (res2 != null) + { + return res2; + } + } + + return res1; + } + + private AutoFillOperation getChildAutoFillOperation() + { + var nextOp = engine.NextOperation(); + if (nextOp == null) + return null; + return AutoFill.autoFillersO.GetValueOrDefault(nextOp); + } + + private IEnumerable getChildAutoFillSearchEngines() + { + return engine.NextSearchEngines().Select(x => AutoFill.autoFillersSE.GetValueOrDefault(x.Item1)).Where(x => x != null); + } + internal string getCurrentStepText(bool valid, string command, int[] argIndices, string suffixToUse) { if (!valid) @@ -175,10 +219,10 @@ internal AutoFillOperation(OperationCategory operation) id = "e" + AutoFill._imguiID; op = operation; _autoFillArgs = Enumerable.Repeat("", op.AllCommands().Sum(x => x.Value.argNames.Length)).ToArray(); - + AutoFill.autoFillersO[operation] = this; } - internal string Menu(string suffix, Func subMenu) + internal string Menu(string suffix) { var currentArgIndex = 0; string result = null; @@ -202,21 +246,10 @@ internal string Menu(string suffix, Func subMenu) var wiki = cmdData.wiki; UIHints.AddImGuiHintButton(cmdName, ref wiki, false, true); - if (subMenu != null) - { - if (ImGui.BeginMenu(cmdName, valid)) - { - result = subMenu(); - ImGui.EndMenu(); - } - } - else - { - result = ImGui.Selectable(cmdName, false, - valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) - ? suffix - : null; - } + result = ImGui.Selectable(cmdName, false, + valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) + ? suffix + : null; ImGui.Indent(); for (var i = 0; i < argIndices.Length; i++) @@ -264,20 +297,38 @@ internal string Menu(string suffix, Func subMenu) internal class AutoFill { internal static int _imguiID = 0; - private static readonly AutoFillSearchEngine autoFillPrsse = new(SearchEngine.paramRowSelection); - private static readonly AutoFillSearchEngine autoFillPrcse = new(SearchEngine.paramRowClipboard); - private static readonly AutoFillSearchEngine autoFillPse = new(SearchEngine.paramRowSelection); - private static readonly AutoFillSearchEngine autoFillRse = new(SearchEngine.row); - private static readonly AutoFillSearchEngine autoFillCse = new(SearchEngine.cell); - private static readonly AutoFillSearchEngine autoFillVse = new(SearchEngine.var); - - private static readonly AutoFillOperation autoFillGo = new(OperationCategory.global); - private static readonly AutoFillOperation autoFillRo = new(OperationCategory.row); - private static readonly AutoFillOperation autoFillCo = new(OperationCategory.cell); - private static readonly AutoFillOperation autoFillVo = new(OperationCategory.var); + + static AutoFill() + { + autoFillPrsse = new(SearchEngine.paramRowSelection); + autoFillPrcse = new(SearchEngine.paramRowClipboard); + autoFillPse = new(SearchEngine.param); + autoFillRse = new(SearchEngine.row); + autoFillCse = new(SearchEngine.cell); + autoFillVse = new(SearchEngine.var); + + autoFillGo = new(OperationCategory.global); + autoFillRo = new(OperationCategory.row); + autoFillCo = new(OperationCategory.cell); + autoFillVo = new(OperationCategory.var); + } + private static readonly AutoFillSearchEngine autoFillPrsse; + private static readonly AutoFillSearchEngine autoFillPrcse; + private static readonly AutoFillSearchEngine autoFillPse; + private static readonly AutoFillSearchEngine autoFillRse; + private static readonly AutoFillSearchEngine autoFillCse; + private static readonly AutoFillSearchEngine autoFillVse; + + private static readonly AutoFillOperation autoFillGo; + private static readonly AutoFillOperation autoFillRo; + private static readonly AutoFillOperation autoFillCo; + private static readonly AutoFillOperation autoFillVo; private static string[] _autoFillArgsOa = Enumerable.Repeat("", OperationArguments.arg.AllArguments().Sum(x => x.Item2.Length) + 1).ToArray(); + internal static Dictionary autoFillersSE = new(); + internal static Dictionary autoFillersO = new(); + internal static Vector4 HINTCOLOUR = new(0.3f, 0.5f, 1.0f, 1.0f); internal static Vector4 PREVIEWCOLOUR = new(0.65f, 0.75f, 0.65f, 1.0f); @@ -288,7 +339,7 @@ public static string ParamSearchBarAutoFill() if (ImGui.BeginPopupContextItem("##psbautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { ImGui.TextColored(HINTCOLOUR, "Select params..."); - var result = autoFillPse.Menu(true, false, "", null, null); + var result = autoFillPse.Menu(true, false, "", null, true); ImGui.EndPopup(); return result; } @@ -303,7 +354,7 @@ public static string RowSearchBarAutoFill() if (ImGui.BeginPopupContextItem("##rsbautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { ImGui.TextColored(HINTCOLOUR, "Select rows..."); - var result = autoFillRse.Menu(true, false, "", null, null); + var result = autoFillRse.Menu(true, false, "", null, true); ImGui.EndPopup(); return result; } @@ -318,7 +369,7 @@ public static string ColumnSearchBarAutoFill() if (ImGui.BeginPopupContextItem("##csbautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { ImGui.TextColored(HINTCOLOUR, "Select fields..."); - var result = autoFillCse.Menu(true, false, "", null, null); + var result = autoFillCse.Menu(true, false, "", null, true); ImGui.EndPopup(); return result; } @@ -336,7 +387,7 @@ public static string MassEditCompleteAutoFill() /*special case*/ ImGui.PushID("paramrowselection"); ImGui.TextColored(HINTCOLOUR, "Select param and rows..."); - var result0 = autoFillPrsse.Menu(false, false, ": ", null, inheritedCommand => + var result0 = autoFillPrsse.Menu(false, false, ": ", null, false);/*, inheritedCommand => { if (inheritedCommand != null) { @@ -352,21 +403,21 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.Menu(";", null); + return autoFillCo.Menu(";"); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = autoFillRo.Menu(";", null); + var res2 = autoFillRo.Menu(";"); if (res1 != null) { return res1; } return res2; - }); + });*/ ImGui.PopID(); ImGui.PushID("paramrowclipboard"); - var result1 = autoFillPrcse.Menu(false, false, ": ", null, inheritedCommand => + var result1 = autoFillPrcse.Menu(false, false, ": ", null, false);/*, inheritedCommand => { if (inheritedCommand != null) { @@ -382,24 +433,24 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.Menu(";", null); + return autoFillCo.Menu(";"); }); ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = autoFillRo.Menu(";", null); + var res2 = autoFillRo.Menu(";"); if (res1 != null) { return res1; } return res2; - }); + });*/ ImGui.PopID(); /*end special case*/ ImGui.Separator(); ImGui.PushID("param"); ImGui.TextColored(HINTCOLOUR, "Select params..."); - var result2 = autoFillPse.Menu(true, false, ": ", null, inheritedCommand => + var result2 = autoFillPse.Menu(true, false, ": ", null, false);/*, inheritedCommand => { if (inheritedCommand != null) { @@ -423,14 +474,14 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.Menu(";", null); + return autoFillCo.Menu(";"); }); string res2 = null; if (CFG.Current.Param_AdvancedMassedit) { ImGui.Separator(); ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - res2 = autoFillRo.Menu(";", null); + res2 = autoFillRo.Menu(";"); } if (res1 != null) @@ -449,7 +500,7 @@ public static string MassEditCompleteAutoFill() ImGui.Separator(); ImGui.PushID("globalop"); ImGui.TextColored(HINTCOLOUR, "Select global operation..."); - result3 = autoFillGo.Menu(";", null); + result3 = autoFillGo.Menu(";"); ImGui.PopID(); if (MassParamEdit.massEditVars.Count != 0) { @@ -464,28 +515,31 @@ public static string MassEditCompleteAutoFill() } ImGui.TextColored(HINTCOLOUR, "Select value operation..."); - return autoFillVo.Menu(";", null); + return autoFillVo.Menu(";"); }); } - } + }*/ ImGui.EndPopup(); + if (result0 != null) + { + return result0; + } if (result1 != null) { return result1; } - if (result2 != null) { return result2; } - if (result3 != null) + /*if (result3 != null) { return result3; } - return result4; + return result4;*/ } return null; @@ -493,7 +547,7 @@ public static string MassEditCompleteAutoFill() public static string MassEditOpAutoFill() { - return autoFillCo.Menu(";", null); + return autoFillCo.Menu(";"); } internal static string MassEditAutoFillForArguments() From c9a6ac1aed12b45eff22325c3d4662c3e9903dc4 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sun, 21 Apr 2024 21:26:51 +0100 Subject: [PATCH 59/61] Names --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 35 ++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index ed7286e36..bda2eba88 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -16,11 +16,12 @@ internal class AutoFillSearchEngine private readonly string[] _autoFillArgs; private readonly SearchEngine engine; private readonly string id; + internal string displayedCategory; private AutoFillSearchEngine _additionalCondition; private bool _autoFillNotToggle; private bool _useAdditionalCondition; - internal AutoFillSearchEngine(SearchEngine searchEngine) + internal AutoFillSearchEngine(SearchEngine searchEngine, string dispCat) { AutoFill._imguiID++; id = "e" + AutoFill._imguiID; @@ -29,6 +30,7 @@ internal AutoFillSearchEngine(SearchEngine searchEngine) _autoFillNotToggle = false; _useAdditionalCondition = false; _additionalCondition = null; + displayedCategory = dispCat; AutoFill.autoFillersSE[searchEngine] = this; } private AutoFillSearchEngine(AutoFillSearchEngine parentEngine) @@ -39,6 +41,7 @@ private AutoFillSearchEngine(AutoFillSearchEngine parentEngine) _autoFillNotToggle = false; _useAdditionalCondition = false; _additionalCondition = null; + displayedCategory = $@"where {parentEngine.displayedCategory} also"; } internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, bool terminal) { @@ -139,7 +142,7 @@ private string SubMenu(string inheritedCommand, string suffix) foreach (AutoFillSearchEngine afse in afses) { ImGui.Separator(); - ImGui.TextColored(AutoFill.HINTCOLOUR, "Select fields..."); + ImGui.TextColored(AutoFill.HINTCOLOUR, @$"Select {afse.displayedCategory}..."); res1 = afse.Menu(true, true, ": ", inheritedCommand, false); if (res1 != null) { @@ -150,7 +153,7 @@ private string SubMenu(string inheritedCommand, string suffix) if (afo != null) { ImGui.Separator(); - ImGui.TextColored(AutoFill.HINTCOLOUR, "Select row operation..."); + ImGui.TextColored(AutoFill.HINTCOLOUR, @$"Select {afo.displayedCategory} operation..."); var res2 = afo.Menu(";"); if (res2 != null) { @@ -212,13 +215,15 @@ internal class AutoFillOperation private readonly string[] _autoFillArgs; private readonly OperationCategory op; private readonly string id; + internal string displayedCategory; - internal AutoFillOperation(OperationCategory operation) + internal AutoFillOperation(OperationCategory operation, string dispCat) { AutoFill._imguiID++; id = "e" + AutoFill._imguiID; op = operation; _autoFillArgs = Enumerable.Repeat("", op.AllCommands().Sum(x => x.Value.argNames.Length)).ToArray(); + displayedCategory = dispCat; AutoFill.autoFillersO[operation] = this; } @@ -300,17 +305,17 @@ internal class AutoFill static AutoFill() { - autoFillPrsse = new(SearchEngine.paramRowSelection); - autoFillPrcse = new(SearchEngine.paramRowClipboard); - autoFillPse = new(SearchEngine.param); - autoFillRse = new(SearchEngine.row); - autoFillCse = new(SearchEngine.cell); - autoFillVse = new(SearchEngine.var); - - autoFillGo = new(OperationCategory.global); - autoFillRo = new(OperationCategory.row); - autoFillCo = new(OperationCategory.cell); - autoFillVo = new(OperationCategory.var); + autoFillPrsse = new(SearchEngine.paramRowSelection, "param and rows"); + autoFillPrcse = new(SearchEngine.paramRowClipboard, "param and rows"); + autoFillPse = new(SearchEngine.param, "params"); + autoFillRse = new(SearchEngine.row, "rows"); + autoFillCse = new(SearchEngine.cell, "cells"); + autoFillVse = new(SearchEngine.var, "variables"); + + autoFillGo = new(OperationCategory.global, "global"); + autoFillRo = new(OperationCategory.row, "row"); + autoFillCo = new(OperationCategory.cell, "cell"); + autoFillVo = new(OperationCategory.var, "variable"); } private static readonly AutoFillSearchEngine autoFillPrsse; private static readonly AutoFillSearchEngine autoFillPrcse; From dcb44c271af3122eef405dba4e50b12c58f4a6c6 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sun, 21 Apr 2024 22:33:43 +0100 Subject: [PATCH 60/61] fix varOps --- src/StudioCore/Editor/MassEdit/EditOperation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StudioCore/Editor/MassEdit/EditOperation.cs b/src/StudioCore/Editor/MassEdit/EditOperation.cs index 9813938da..891be77c4 100644 --- a/src/StudioCore/Editor/MassEdit/EditOperation.cs +++ b/src/StudioCore/Editor/MassEdit/EditOperation.cs @@ -350,7 +350,7 @@ internal override void UseResult(List actionList, (object, object) actionList.AppendParamEditAction(row, col, res); } } -internal class MEVarOperation : MEValueOperation +internal class MEVarOperation : MEValueOperation<(bool, string)> { internal override object GetElementValue((object, object) currentObject, Dictionary contextObjects) { From d6e5c1709f493acf1a89117fed069c47fb76c8a0 Mon Sep 17 00:00:00 2001 From: Philiquaz Date: Sun, 21 Apr 2024 22:36:36 +0100 Subject: [PATCH 61/61] Move headers (slightly repetitive), remove commented code, re-enable globalOps+var stuff --- src/StudioCore/Editor/MassEdit/AutoFill.cs | 195 ++++----------------- 1 file changed, 30 insertions(+), 165 deletions(-) diff --git a/src/StudioCore/Editor/MassEdit/AutoFill.cs b/src/StudioCore/Editor/MassEdit/AutoFill.cs index bda2eba88..f2fac74e7 100644 --- a/src/StudioCore/Editor/MassEdit/AutoFill.cs +++ b/src/StudioCore/Editor/MassEdit/AutoFill.cs @@ -45,6 +45,8 @@ private AutoFillSearchEngine(AutoFillSearchEngine parentEngine) } internal string Menu(bool enableComplexToggles, bool enableDefault, string suffix, string inheritedCommand, bool terminal) { + ImGui.Separator(); + ImGui.TextColored(AutoFill.HINTCOLOUR, @$"Select {displayedCategory}..."); var currentArgIndex = 0; if (enableComplexToggles) { @@ -79,27 +81,28 @@ internal string Menu(bool enableComplexToggles, bool enableDefault, string suffi string subResult = null; var wiki = cmd.Item3; - UIHints.AddImGuiHintButton(cmd.Item1 == null ? "hintdefault" : "hint" + cmd.Item1, ref wiki, false, - true); - if (ImGui.BeginMenu(cmd.Item1 == null ? "Default filter..." : cmd.Item1, valid)) + UIHints.AddImGuiHintButton(cmd.Item1 == null ? "hintdefault" : "hint" + cmd.Item1, ref wiki, false, true); + if (!terminal || _additionalCondition != null) { - var curResult = inheritedCommand + getCurrentStepText(valid, cmd.Item1, argIndices, _additionalCondition != null ? " && " : suffix); - if (_additionalCondition != null) - { - subResult = _additionalCondition.Menu(enableComplexToggles, enableDefault, suffix, curResult, terminal); - } - else + if (ImGui.BeginMenu(cmd.Item1 == null ? "Default filter..." : cmd.Item1, valid)) { - subResult = SubMenu(curResult, suffix); - } + var curResult = inheritedCommand + getCurrentStepText(valid, cmd.Item1, argIndices, _additionalCondition != null ? " && " : suffix); + if (_additionalCondition != null) + { + subResult = _additionalCondition.Menu(enableComplexToggles, enableDefault, suffix, curResult, terminal); + } + else + { + subResult = SubMenu(curResult, suffix); + } - ImGui.EndMenu(); + ImGui.EndMenu(); + } } - /* else { subResult = ImGui.Selectable(cmd.Item1 == null ? "Default filter..." : cmd.Item1, false, valid ? ImGuiSelectableFlags.None : ImGuiSelectableFlags.Disabled) ? suffix : null; - }*/ + } //ImGui.Indent(); for (var i = 0; i < argIndices.Length; i++) @@ -132,17 +135,12 @@ internal string Menu(bool enableComplexToggles, bool enableDefault, string suffi private string SubMenu(string inheritedCommand, string suffix) { - if (inheritedCommand != null) - { - ImGui.TextColored(AutoFill.PREVIEWCOLOUR, inheritedCommand); - } + ImGui.TextColored(AutoFill.PREVIEWCOLOUR, inheritedCommand); IEnumerable afses = getChildAutoFillSearchEngines(); string res1 = null; foreach (AutoFillSearchEngine afse in afses) { - ImGui.Separator(); - ImGui.TextColored(AutoFill.HINTCOLOUR, @$"Select {afse.displayedCategory}..."); res1 = afse.Menu(true, true, ": ", inheritedCommand, false); if (res1 != null) { @@ -152,8 +150,6 @@ private string SubMenu(string inheritedCommand, string suffix) AutoFillOperation afo = getChildAutoFillOperation(); if (afo != null) { - ImGui.Separator(); - ImGui.TextColored(AutoFill.HINTCOLOUR, @$"Select {afo.displayedCategory} operation..."); var res2 = afo.Menu(";"); if (res2 != null) { @@ -229,6 +225,8 @@ internal AutoFillOperation(OperationCategory operation, string dispCat) internal string Menu(string suffix) { + ImGui.Separator(); + ImGui.TextColored(AutoFill.HINTCOLOUR, @$"Select {displayedCategory} operation..."); var currentArgIndex = 0; string result = null; foreach (KeyValuePair cmd in op.AllCommands()) @@ -343,7 +341,6 @@ public static string ParamSearchBarAutoFill() ImGui.Button($@"{ForkAwesome.CaretDown}"); if (ImGui.BeginPopupContextItem("##psbautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { - ImGui.TextColored(HINTCOLOUR, "Select params..."); var result = autoFillPse.Menu(true, false, "", null, true); ImGui.EndPopup(); return result; @@ -358,7 +355,6 @@ public static string RowSearchBarAutoFill() ImGui.Button($@"{ForkAwesome.CaretDown}"); if (ImGui.BeginPopupContextItem("##rsbautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { - ImGui.TextColored(HINTCOLOUR, "Select rows..."); var result = autoFillRse.Menu(true, false, "", null, true); ImGui.EndPopup(); return result; @@ -373,7 +369,6 @@ public static string ColumnSearchBarAutoFill() ImGui.Button($@"{ForkAwesome.CaretDown}"); if (ImGui.BeginPopupContextItem("##csbautoinputoapopup", ImGuiPopupFlags.MouseButtonLeft)) { - ImGui.TextColored(HINTCOLOUR, "Select fields..."); var result = autoFillCse.Menu(true, false, "", null, true); ImGui.EndPopup(); return result; @@ -391,160 +386,30 @@ public static string MassEditCompleteAutoFill() { /*special case*/ ImGui.PushID("paramrowselection"); - ImGui.TextColored(HINTCOLOUR, "Select param and rows..."); - var result0 = autoFillPrsse.Menu(false, false, ": ", null, false);/*, inheritedCommand => - { - if (inheritedCommand != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand); - } - - ImGui.TextColored(HINTCOLOUR, "Select fields..."); - var res1 = autoFillCse.Menu(true, true, ": ", inheritedCommand, inheritedCommand2 => - { - if (inheritedCommand2 != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand2); - } - - ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.Menu(";"); - }); - ImGui.Separator(); - ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = autoFillRo.Menu(";"); - if (res1 != null) - { - return res1; - } - - return res2; - });*/ + var result = autoFillPrsse.Menu(false, false, ": ", null, false); ImGui.PopID(); ImGui.PushID("paramrowclipboard"); - var result1 = autoFillPrcse.Menu(false, false, ": ", null, false);/*, inheritedCommand => - { - if (inheritedCommand != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand); - } - - ImGui.TextColored(HINTCOLOUR, "Select fields..."); - var res1 = autoFillCse.Menu(true, true, ": ", inheritedCommand, inheritedCommand2 => - { - if (inheritedCommand2 != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand2); - } - - ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.Menu(";"); - }); - ImGui.Separator(); - ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - var res2 = autoFillRo.Menu(";"); - if (res1 != null) - { - return res1; - } - - return res2; - });*/ + result ??= autoFillPrcse.Menu(false, false, ": ", null, false); ImGui.PopID(); /*end special case*/ - ImGui.Separator(); ImGui.PushID("param"); - ImGui.TextColored(HINTCOLOUR, "Select params..."); - var result2 = autoFillPse.Menu(true, false, ": ", null, false);/*, inheritedCommand => - { - if (inheritedCommand != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand); - } - - ImGui.TextColored(HINTCOLOUR, "Select rows..."); - return autoFillRse.Menu(true, false, ": ", inheritedCommand, inheritedCommand2 => - { - if (inheritedCommand2 != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand2); - } - - ImGui.TextColored(HINTCOLOUR, "Select fields..."); - var res1 = autoFillCse.Menu(true, true, ": ", inheritedCommand2, inheritedCommand3 => - { - if (inheritedCommand3 != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand3); - } - - ImGui.TextColored(HINTCOLOUR, "Select field operation..."); - return autoFillCo.Menu(";"); - }); - string res2 = null; - if (CFG.Current.Param_AdvancedMassedit) - { - ImGui.Separator(); - ImGui.TextColored(HINTCOLOUR, "Select row operation..."); - res2 = autoFillRo.Menu(";"); - } - - if (res1 != null) - { - return res1; - } - - return res2; - }); - }); + result ??= autoFillPse.Menu(true, false, ": ", null, false); ImGui.PopID(); - string result3 = null; - string result4 = null; if (CFG.Current.Param_AdvancedMassedit) { - ImGui.Separator(); ImGui.PushID("globalop"); - ImGui.TextColored(HINTCOLOUR, "Select global operation..."); - result3 = autoFillGo.Menu(";"); + result ??= autoFillGo.Menu(";"); ImGui.PopID(); - if (MassParamEdit.massEditVars.Count != 0) - { - ImGui.Separator(); - ImGui.PushID("var"); - ImGui.TextColored(HINTCOLOUR, "Select variables..."); - result4 = autoFillVse.Menu(false, false, ": ", null, inheritedCommand => - { - if (inheritedCommand != null) - { - ImGui.TextColored(PREVIEWCOLOUR, inheritedCommand); - } - - ImGui.TextColored(HINTCOLOUR, "Select value operation..."); - return autoFillVo.Menu(";"); - }); - } - }*/ - - ImGui.EndPopup(); - if (result0 != null) - { - return result0; } - if (result1 != null) + if (CFG.Current.Param_AdvancedMassedit && MassParamEdit.massEditVars.Count != 0) { - return result1; - } - if (result2 != null) - { - return result2; - } - - /*if (result3 != null) - { - return result3; + ImGui.PushID("var"); + result ??= autoFillVse.Menu(false, false, ": ", null, false); + ImGui.PopID(); } - return result4;*/ + ImGui.EndPopup(); + return result; } return null;