From 9c97be6c827b338d8e410d9dc05afd54cbaf727c Mon Sep 17 00:00:00 2001 From: M_SERVER <150300918+M-Server-BOT@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:58:49 +0300 Subject: [PATCH 1/3] feat: allow trimming of region path segments --- README.md | 18 +++++++++++++-- src/PluginMerge/Configuration/MergeConfig.cs | 18 +++++++++++++++ .../Configuration/PluginMergeConfig.cs | 8 +++++++ src/PluginMerge/Merge/FileHandler.cs | 22 +++++++++++++++++-- src/PluginMerge/Merge/MergeHandler.cs | 2 +- 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 860d5aa..86077b3 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,16 @@ Add the following to your csproj file to have the merge tool run after build: ### Creator Modes There are 3 types of merge options when using Plugin Merge. `Plugin` - will merge all files into a final Plugin to be used. -`Framework` - Will output a framework file that can be copied into another plugin that isn't a merge framework plugin -`MergeFramework` - Will output a framework file that can be used with a plugin that is a merge framework plugin +`Framework` - Will output a framework file that can be copied into another plugin that isn't a merge framework plugin +`MergeFramework` - Will output a framework file that can be used with a plugin that is a merge framework plugin + +#### Region Path Trim Left/Right +These keys control how much of the file path appears in the generated region names. +`Region Path Trim Left` removes directory segments from the start of the relative path (use `-1` to keep only the file name). +`Region Path Trim Right` removes segments from the end of the path. The defaults are `-1` and `0` respectively. +For example, for a file located at `src/Plugins/Foo.cs` relative to the current directory: +* `Region Path Trim Left: 1` results in the region name `Plugins/Foo.cs`. +* `Region Path Trim Right: 1` results in the region name `src/Plugins`. ### YAML Configuration File ```yaml @@ -127,6 +135,10 @@ Merge Settings: # Namespaces to ignore when processing output file Ignore Namespaces: - IgnoreThisNameSpace + # Segments to trim from the start of region names (-1 keeps only the file name) + Region Path Trim Left: -1 + # Segments to trim from the end of region names + Region Path Trim Right: 0 Code Style: # Character to use for code indents Indent Character: ' ' @@ -181,6 +193,8 @@ Compile Settings: "Ignore Namespaces": [ "IgnoreThisNameSpace" ], + "Region Path Trim Left": -1, + "Region Path Trim Right": 0, "Code Style": { "Indent Character": " ", "Indent Char Amount": 4, diff --git a/src/PluginMerge/Configuration/MergeConfig.cs b/src/PluginMerge/Configuration/MergeConfig.cs index 5d264d8..e314da0 100644 --- a/src/PluginMerge/Configuration/MergeConfig.cs +++ b/src/PluginMerge/Configuration/MergeConfig.cs @@ -45,6 +45,14 @@ public class MergeConfig [JsonPropertyName("Ignore Namespaces")] [YamlMember(Alias = "Ignore Namespaces", Description = "Namespaces to ignore when processing output file")] public List IgnoreNameSpaces { get; set; } + + [JsonPropertyName("Region Path Trim Left")] + [YamlMember(Alias = "Region Path Trim Left", Description = "Segments to trim from the start of region names (-1 to keep only the file name)")] + public int RegionPathTrimLeft { get; set; } = -1; + + [JsonPropertyName("Region Path Trim Right")] + [YamlMember(Alias = "Region Path Trim Right", Description = "Segments to trim from the end of region names")] + public int RegionPathTrimRight { get; set; } = 0; [JsonPropertyName("Code Style")] [YamlMember(Alias = "Code Style")] @@ -69,5 +77,15 @@ public void Initialize() IgnoreNameSpaces ??= new List {"IgnoreThisNameSpace"}; CodeStyle ??= new CodeStyleConfig(); CodeStyle.Initialize(); + + if (RegionPathTrimLeft < -1) + { + RegionPathTrimLeft = -1; + } + + if (RegionPathTrimRight < -1) + { + RegionPathTrimRight = 0; + } } } \ No newline at end of file diff --git a/src/PluginMerge/Configuration/PluginMergeConfig.cs b/src/PluginMerge/Configuration/PluginMergeConfig.cs index e86cd45..e1acbbf 100644 --- a/src/PluginMerge/Configuration/PluginMergeConfig.cs +++ b/src/PluginMerge/Configuration/PluginMergeConfig.cs @@ -12,6 +12,14 @@ public class PluginMergeConfig [JsonPropertyName("Merge Settings")] [YamlMember(Alias = "Merge Settings")] public MergeConfig Merge { get; set; } + + [JsonIgnore] + [YamlIgnore] + public int RegionPathTrimLeft => Merge.RegionPathTrimLeft; + + [JsonIgnore] + [YamlIgnore] + public int RegionPathTrimRight => Merge.RegionPathTrimRight; [JsonPropertyName("Preprocessor Directive Settings")] [YamlMember(Alias = "Preprocessor Directive Settings")] diff --git a/src/PluginMerge/Merge/FileHandler.cs b/src/PluginMerge/Merge/FileHandler.cs index bdd33fd..769c8e2 100644 --- a/src/PluginMerge/Merge/FileHandler.cs +++ b/src/PluginMerge/Merge/FileHandler.cs @@ -63,11 +63,29 @@ public class FileHandler /// Sets the file path /// /// - public FileHandler(ScannedFile file) + public FileHandler(ScannedFile file, int trimLeft, int trimRight) { _logger = LogBuilder.GetLogger(); FilePath = file.FileName; - RegionName = FilePath.Replace(file.InputPath, "").TrimStart(Path.DirectorySeparatorChar); + + string relative = Path.GetRelativePath(Directory.GetCurrentDirectory(), FilePath); + List parts = relative.Split(Path.DirectorySeparatorChar).ToList(); + + if (trimLeft == -1) + { + parts = parts.TakeLast(1).ToList(); + } + else if (trimLeft > 0) + { + parts = parts.Skip(Math.Min(trimLeft, parts.Count - 1)).ToList(); + } + + if (trimRight > 0) + { + parts = parts.Take(Math.Max(parts.Count - trimRight, 1)).ToList(); + } + + RegionName = string.Join(Path.DirectorySeparatorChar, parts); } /// diff --git a/src/PluginMerge/Merge/MergeHandler.cs b/src/PluginMerge/Merge/MergeHandler.cs index 0fb2cf6..6df22a2 100644 --- a/src/PluginMerge/Merge/MergeHandler.cs +++ b/src/PluginMerge/Merge/MergeHandler.cs @@ -37,7 +37,7 @@ public async Task Run() FileScanner scanner = new(_merge.InputPaths, "*.cs", _merge.IgnorePaths, _merge.IgnoreFiles.Concat(finalFiles)); foreach (ScannedFile file in scanner.ScanFiles()) { - _files.Add(new FileHandler(file)); + _files.Add(new FileHandler(file, _config.RegionPathTrimLeft, _config.RegionPathTrimRight)); } CSharpParseOptions options = new(_config.PlatformSettings.Lang); From 7b838b00bb61b402147973aa15728640089e031d Mon Sep 17 00:00:00 2001 From: M_SERVER <150300918+M-Server-BOT@users.noreply.github.com> Date: Wed, 13 Aug 2025 11:25:24 +0300 Subject: [PATCH 2/3] Infer plugin name from output paths and write merged code accordingly --- src/PluginMerge/Merge/MergeHandler.cs | 33 ++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/PluginMerge/Merge/MergeHandler.cs b/src/PluginMerge/Merge/MergeHandler.cs index 6df22a2..d851f71 100644 --- a/src/PluginMerge/Merge/MergeHandler.cs +++ b/src/PluginMerge/Merge/MergeHandler.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp; +using System.IO; namespace PluginMerge.Merge; @@ -22,18 +23,38 @@ public async Task Run() Stopwatch sw = Stopwatch.StartNew(); _logger.LogInformation("Starting Plugin Merge Version: {Version} Mode: {Mode}", typeof(Program).Assembly.GetName().Version, _merge.CreatorMode); _logger.LogInformation("Input Paths: {Input}", string.Join(", ", _merge.InputPaths.Select(p => p.ToFullPath()))); - - foreach (string path in _merge.OutputPaths) + + for (int i = 0; i < _merge.OutputPaths.Count; i++) { - if (!string.IsNullOrEmpty(path) && !Directory.Exists(path)) + string path = _merge.OutputPaths[i]; + if (string.IsNullOrEmpty(path)) + { + continue; + } + + if (Path.GetExtension(path).Equals(".cs", StringComparison.OrdinalIgnoreCase)) + { + string fileName = Path.GetFileName(path); + if (string.IsNullOrWhiteSpace(_merge.PluginName) || _merge.PluginName == "MyPluginName") + { + _merge.PluginName = Path.GetFileNameWithoutExtension(fileName); + } + + path = Path.GetDirectoryName(path) ?? string.Empty; + _merge.OutputPaths[i] = path; + } + + if (!Directory.Exists(path)) { _logger.LogDebug("Output path doesn't exist. Creating output path: {Path}", path); Directory.CreateDirectory(path); } } - - List finalFiles = _merge.FinalFiles.ToList(); - + + List finalFiles = _merge.OutputPaths + .Select(p => Path.Combine(p, $"{_merge.PluginName}.cs").ToFullPath()) + .ToList(); + FileScanner scanner = new(_merge.InputPaths, "*.cs", _merge.IgnorePaths, _merge.IgnoreFiles.Concat(finalFiles)); foreach (ScannedFile file in scanner.ScanFiles()) { From bcb109cba9e3751c7360e30138d32c892a4df0af Mon Sep 17 00:00:00 2001 From: M_SERVER <150300918+M-Server-BOT@users.noreply.github.com> Date: Wed, 13 Aug 2025 12:42:44 +0300 Subject: [PATCH 3/3] Infer plugin name and remove default --- src/PluginMerge/Configuration/MergeConfig.cs | 14 +++++++++-- src/PluginMerge/Creator/FileCreator.cs | 3 ++- src/PluginMerge/Merge/MergeHandler.cs | 25 ++++++++++++++------ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/PluginMerge/Configuration/MergeConfig.cs b/src/PluginMerge/Configuration/MergeConfig.cs index e314da0..3ae7cf9 100644 --- a/src/PluginMerge/Configuration/MergeConfig.cs +++ b/src/PluginMerge/Configuration/MergeConfig.cs @@ -60,13 +60,23 @@ public class MergeConfig [JsonIgnore] [YamlIgnore] - public IEnumerable FinalFiles => OutputPaths.Select(p => Path.Combine(p, $"{PluginName}.cs").ToFullPath()); + public IEnumerable FinalFiles + { + get + { + if (string.IsNullOrEmpty(PluginName)) + { + return Enumerable.Empty(); + } + + return OutputPaths.Select(p => Path.Combine(p, $"{PluginName}.cs").ToFullPath()); + } + } private bool ShouldSerializeNamespaceOverride() => CreatorMode == CreatorMode.MergeFramework; public void Initialize() { - PluginName ??= "MyPluginName"; NamespaceOverride ??= string.Empty; InputPaths ??= new List { "./" }; OutputPaths ??= new List {"./build"}; diff --git a/src/PluginMerge/Creator/FileCreator.cs b/src/PluginMerge/Creator/FileCreator.cs index f048739..8f8d59b 100644 --- a/src/PluginMerge/Creator/FileCreator.cs +++ b/src/PluginMerge/Creator/FileCreator.cs @@ -68,7 +68,8 @@ public bool Create() } FilterFiles(_plugin.PluginData); - + + _settings.Merge.PluginName ??= _plugin.PluginData.ClassName; _writer = new CodeWriter(_plugin.PluginData, _settings.Merge); WriteReferences(); diff --git a/src/PluginMerge/Merge/MergeHandler.cs b/src/PluginMerge/Merge/MergeHandler.cs index d851f71..e5ccf8a 100644 --- a/src/PluginMerge/Merge/MergeHandler.cs +++ b/src/PluginMerge/Merge/MergeHandler.cs @@ -35,7 +35,7 @@ public async Task Run() if (Path.GetExtension(path).Equals(".cs", StringComparison.OrdinalIgnoreCase)) { string fileName = Path.GetFileName(path); - if (string.IsNullOrWhiteSpace(_merge.PluginName) || _merge.PluginName == "MyPluginName") + if (string.IsNullOrWhiteSpace(_merge.PluginName)) { _merge.PluginName = Path.GetFileNameWithoutExtension(fileName); } @@ -51,11 +51,7 @@ public async Task Run() } } - List finalFiles = _merge.OutputPaths - .Select(p => Path.Combine(p, $"{_merge.PluginName}.cs").ToFullPath()) - .ToList(); - - FileScanner scanner = new(_merge.InputPaths, "*.cs", _merge.IgnorePaths, _merge.IgnoreFiles.Concat(finalFiles)); + FileScanner scanner = new(_merge.InputPaths, "*.cs", _merge.IgnorePaths, _merge.IgnoreFiles); foreach (ScannedFile file in scanner.ScanFiles()) { _files.Add(new FileHandler(file, _config.RegionPathTrimLeft, _config.RegionPathTrimRight)); @@ -67,6 +63,21 @@ public async Task Run() _files = _files.Where(f => !f.IsExcludedFile()).OrderBy(f => f.Order).ToList(); + if (string.IsNullOrWhiteSpace(_merge.PluginName)) + { + FileHandler? pluginFile = _files.FirstOrDefault(f => f.PluginData is { } data && + !string.IsNullOrWhiteSpace(data.Title) && + !string.IsNullOrWhiteSpace(data.Description)); + + if (pluginFile is not null) + { + _merge.PluginName = pluginFile.PluginData.ClassName; + } + } + + List finalFiles = _merge.FinalFiles.ToList(); + _files = _files.Where(f => !finalFiles.Contains(f.FilePath)).ToList(); + FileCreator creator = new(_config, _files); if (!creator.Create()) { @@ -79,7 +90,7 @@ public async Task Run() // SourceText text = await parsed.NormalizeWhitespace("\n").SyntaxTree.GetTextAsync().ConfigureAwait(false); // // code = text.ToString(); - + await Task.WhenAll(finalFiles.Select(f => File.WriteAllTextAsync(f, code))).ConfigureAwait(false); sw.Stop();