diff --git a/ADO2024/PI2/Helper-2024-06-23.cs b/ADO2024/PI2/Helper-2024-06-23.cs index 131dcfe..910df6c 100644 --- a/ADO2024/PI2/Helper-2024-06-23.cs +++ b/ADO2024/PI2/Helper-2024-06-23.cs @@ -19,7 +19,7 @@ internal static partial class Helper20240623 private static partial Regex InvalidCharacter(); private record H1AndParamCase(string H1, string ParamCase); - private record SubTaskLine(string Text, bool Done, long? Ticks, int? Line); + private record SubTaskLine(string Text, bool Started, bool Completed, long? Ticks, int? Line); private record Record(int? CodeInsidersLine, FileInfo FileInfo, LineNumber LineNumber, int? StopLine, int? SubTasksLine); private record Input(long? AfterEpochTotalMilliseconds, @@ -121,13 +121,14 @@ internal static partial class Helper20240623 return result; } - private static ReadOnlyCollection GetSubTaskLines(Input input, bool? foundDone, string fallbackLine, Record record) + private static ReadOnlyCollection GetSubTaskLines(Input input, bool? foundStarted, bool? foundCompleted, string fallbackLine, Record record) { List results = []; char done; string line; string text; - bool doneValue; + bool startedValue; + bool completedValue; SubTaskLine subTaskLine; bool foundSubTasks = false; int tasksZeroLength = input.Tasks[0].Length; @@ -141,19 +142,21 @@ internal static partial class Helper20240623 continue; if (line.Length <= tasksZeroLength || !line.StartsWith(input.Tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']') continue; - doneValue = foundDone is not null && foundDone.Value; - subTaskLine = new($" {line}", doneValue, ticks, i); + startedValue = foundStarted is not null && foundStarted.Value; + completedValue = foundCompleted is not null && foundCompleted.Value; + subTaskLine = new(Text: $" {line}", Started: startedValue, Completed: completedValue, Ticks: ticks, Line: i); results.Add(subTaskLine); } - doneValue = foundDone is not null && foundDone.Value; + startedValue = foundStarted is not null && foundStarted.Value; + completedValue = foundCompleted is not null && foundCompleted.Value; if (record.LineNumber.H1 is null) - subTaskLine = new(fallbackLine, doneValue, ticks, Line: null); + subTaskLine = new(Text: fallbackLine, Started: startedValue, Completed: completedValue, Ticks: ticks, Line: null); else { - done = foundDone is null || !foundDone.Value ? ' ' : 'x'; + done = foundCompleted is null || !foundCompleted.Value ? ' ' : 'x'; string codeInsidersLine = record.CodeInsidersLine is null ? string.Empty : $" ~~{record.LineNumber.Lines[record.CodeInsidersLine.Value]}~~"; text = $"- [{done}] {ticks} {record.LineNumber.Lines[record.LineNumber.H1.Value]}{codeInsidersLine}"; - subTaskLine = new(text, doneValue, ticks, Line: 0); + subTaskLine = new(Text: text, Started: startedValue, Completed: completedValue, Ticks: ticks, Line: 0); } results.Add(subTaskLine); return new(results); @@ -322,48 +325,85 @@ internal static partial class Helper20240623 return result; } + private static ReadOnlyCollection GetXColumns(Input input, int frontMatterYamlEnd, int value, ReadOnlyCollection lines) + { + List results = []; + string[] segments; + for (int i = value + 1; i < frontMatterYamlEnd; i++) + { + segments = lines[i].Replace("\t", " ").Split(" - "); + if (segments.Length != 2) + break; + results.Add($"## {segments[1].Replace("'", string.Empty)}"); + } + if (results.Count == 0) + results.Add(input.Done); + return results.AsReadOnly(); + } + + private static ReadOnlyCollection GetCompletedColumns(Input input, LineNumber lineNumber) + { + List results; + if (lineNumber.FrontMatterYamlEnd is null || lineNumber.CompletedColumns is null) + results = []; + else + results = GetXColumns(input, lineNumber.FrontMatterYamlEnd.Value, lineNumber.CompletedColumns.Value, lineNumber.Lines).ToList(); + if (results.Count == 0) + results.Add(input.Done); + return results.AsReadOnly(); + } + + private static ReadOnlyCollection GetStartedColumns(Input input, LineNumber lineNumber) + { + List results; + if (lineNumber.FrontMatterYamlEnd is null || lineNumber.StartedColumns is null) + results = []; + else + results = GetXColumns(input, lineNumber.FrontMatterYamlEnd.Value, lineNumber.StartedColumns.Value, lineNumber.Lines).ToList(); + if (results.Count == 0) + results.Add(input.Done); + return results.AsReadOnly(); + } + private static ReadOnlyCollection GetSubTaskLines(Input input, FileInfo fileInfo, LineNumber lineNumber) { List results = []; - char done; FileInfo f; Record record; - bool doneValue; + char completed; string[] segments; + bool startedValue; + bool completedValue; string fallbackLine; - bool? foundDone = null; + bool? foundStarted = null; + bool? foundCompleted = null; ReadOnlyCollection subTaskLines; - for (int i = 0; i < lineNumber.Lines.Count; i++) + ReadOnlyCollection startedColumns = GetStartedColumns(input, lineNumber); + ReadOnlyCollection completedColumns = GetCompletedColumns(input, lineNumber); + int start = lineNumber.FrontMatterYamlEnd is null ? 0 : lineNumber.FrontMatterYamlEnd.Value + 1; + for (int i = start; i < lineNumber.Lines.Count; i++) { - if (lineNumber.Lines[i] == input.Done) - foundDone = true; + if ((foundStarted is null || !foundStarted.Value) && startedColumns.Any(lineNumber.Lines[i].StartsWith)) + foundStarted = true; + if ((foundCompleted is null || !foundCompleted.Value) && completedColumns.Any(lineNumber.Lines[i].StartsWith)) + foundCompleted = true; segments = lineNumber.Lines[i].Split(input.Tasks[1]); - doneValue = foundDone is not null && foundDone.Value; + startedValue = foundStarted is not null && foundStarted.Value; + completedValue = foundCompleted is not null && foundCompleted.Value; if (segments.Length > 2 || !segments[0].StartsWith(input.Tasks[0])) continue; - done = foundDone is null || !foundDone.Value ? ' ' : 'x'; - fallbackLine = $"- [{done}] {segments[0][input.Tasks[0].Length..]} ~~FallbackLine~~"; + completed = foundCompleted is null || !foundCompleted.Value ? ' ' : 'x'; + fallbackLine = $"- [{completed}] {segments[0][input.Tasks[0].Length..]} ~~FallbackLine~~"; if (string.IsNullOrEmpty(fileInfo.DirectoryName)) continue; f = new(Path.GetFullPath(Path.Combine(fileInfo.DirectoryName, segments[1][..^1]))); if (!f.Exists) { - results.Add(new(fallbackLine, doneValue, Ticks: null, Line: null)); + results.Add(new(Text: fallbackLine, Started: startedValue, Completed: completedValue, Ticks: null, Line: null)); continue; } record = GetRecord(input, f); - if (lineNumber.H1 is not null && record.LineNumber.H1 is not null) - { - string a = lineNumber.Lines[lineNumber.H1.Value]; - string b = record.LineNumber.Lines[record.LineNumber.H1.Value]; - if (b != a) - { - if (b != a) - { - } - } - } - subTaskLines = GetSubTaskLines(input, doneValue, fallbackLine, record); + subTaskLines = GetSubTaskLines(input, startedValue, completedValue, fallbackLine, record); for (int j = subTaskLines.Count - 1; j >= 0; j--) results.Add(subTaskLines[j]); } @@ -536,9 +576,11 @@ internal static partial class Helper20240623 int allCount; int lineCheck; double percent; - double doneCount; + string replace; FileInfo fileInfo; + double startedCount; List records; + double completedCount; LineNumber lineNumber; List newLines; bool reloadAny = false; @@ -582,19 +624,28 @@ internal static partial class Helper20240623 lineCheck = 0; for (int i = record.SubTasksLine.Value + 1; i < record.StopLine.Value - 1; i++) oldLines.Add(record.LineNumber.Lines[i]); - if (subTaskLines.Any(l => l.Ticks is null)) - newLines = (from l in subTaskLines select l.Text).ToList(); - else - newLines = (from l in subTaskLines orderby l.Done descending, l.Ticks, l.Line select l.Text).ToList(); if (subTaskLines.Count == 0) + { percent = 0; + replace = "0"; + } else { allCount = (from l in subTaskLines where l.Line is not null && l.Line.Value == 0 select 1).Count(); - doneCount = (from l in subTaskLines where l.Line is not null && l.Line.Value == 0 && l.Done select 1).Count(); - // done = allCount != doneCount ? ' ' : 'x'; - percent = allCount == 0 ? 0 : Math.Round(doneCount / allCount, 3); + completedCount = (from l in subTaskLines where l.Line is not null && l.Line.Value == 0 && l.Completed select 1).Count(); + startedCount = (from l in subTaskLines where l.Line is not null && l.Line.Value == 0 && l.Started && !l.Completed select 1).Count(); + percent = allCount == 0 ? 0 : Math.Round(completedCount / allCount, 3); // newLines.Insert(0, $"- [{done}] Sub-tasks {doneCount} of {allCount} [{percent * 100}%]"); + replace = $"{allCount} » {startedCount} ✓ {completedCount} {Math.Floor(percent * 100)}%".Replace(" ✓ 0 0%", string.Empty).Replace(" 100%", string.Empty).Replace(" » 0", string.Empty); + } + if (subTaskLines.Any(l => l.Ticks is null)) + newLines = (from l in subTaskLines + select l.Text).ToList(); + else + { + newLines = (from l in subTaskLines + orderby l.Completed descending, l.Started descending, l.Ticks, l.Line + select l.Text.Replace($"{l.Ticks}", replace)).ToList(); } if (newLines.Count == oldLines.Count) { diff --git a/ADO2025/PI5/Helper-2025-02-19.cs b/ADO2025/PI5/Helper-2025-02-19.cs index aa7a8b1..c83a144 100644 --- a/ADO2025/PI5/Helper-2025-02-19.cs +++ b/ADO2025/PI5/Helper-2025-02-19.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using System.Collections.ObjectModel; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; namespace File_Folder_Helper.ADO2025.PI5; @@ -12,6 +13,12 @@ internal static partial class Helper20250219 ReadOnlyCollection Columns, string Logistics); + [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSerializable(typeof(JsonElement[]))] + private partial class JsonElementCollectionSourceGenerationContext : JsonSerializerContext + { + } + private static ProcessDataStandardFormat GetLogisticsColumnsAndBody(string path, string[]? lines) { ProcessDataStandardFormat result; @@ -74,7 +81,7 @@ internal static partial class Helper20250219 { JsonElement[]? results; if (processDataStandardFormat.Body.Count == 0 || !processDataStandardFormat.Body[0].Contains('\t')) - results = JsonSerializer.Deserialize("[]") ?? throw new Exception(); + results = JsonSerializer.Deserialize("[]", JsonElementCollectionSourceGenerationContext.Default.JsonElementArray) ?? throw new Exception(); else { string value; @@ -112,7 +119,7 @@ internal static partial class Helper20250219 lines.Add(stringBuilder.ToString()); } string json = $"[{string.Join(',', lines)}]"; - results = JsonSerializer.Deserialize(json); + results = JsonSerializer.Deserialize(json, JsonElementCollectionSourceGenerationContext.Default.JsonElementArray); } return results; } @@ -127,6 +134,20 @@ internal static partial class Helper20250219 result = i; break; } + if (result is null) + { + for (int i = 0; i < jsonProperties.Length; i++) + { + if (jsonProperties[i].Name[0] != propertyName[0]) + continue; + if (jsonProperties[i].Name.Length != propertyName.Length) + continue; + if (jsonProperties[i].Name != propertyName) + continue; + result = i; + break; + } + } return result; } @@ -267,9 +288,9 @@ internal static partial class Helper20250219 segmentsB = segment.Split('|'); if (segmentsB.Length != 2) continue; - if (distinct.Contains(segmentsB[1])) + if (distinct.Contains(segmentsB[0])) continue; - distinct.Add(segmentsB[1]); + distinct.Add(segmentsB[0]); keyValuePairs.Add(segmentsB[0], segmentsB[1]); } string sourceDirectory = Path.GetFullPath(args[0]); diff --git a/File-Folder-Helper.csproj b/File-Folder-Helper.csproj index 638a25f..38a5ae9 100644 --- a/File-Folder-Helper.csproj +++ b/File-Folder-Helper.csproj @@ -17,7 +17,7 @@ - + diff --git a/Helpers/HelperMarkdown.cs b/Helpers/HelperMarkdown.cs index b4ccce3..9dd3895 100644 --- a/Helpers/HelperMarkdown.cs +++ b/Helpers/HelperMarkdown.cs @@ -317,6 +317,8 @@ internal static partial class HelperMarkdown int? updatedLineNumber = null; int? progressLineNumber = null; int? completedLineNumber = null; + int? startedColumnsLineNumber = null; + int? completedColumnsLineNumber = null; int? frontMatterYamlEndLineNumber = null; Encoding? encoding = GetEncoding(fileInfo.FullName) ?? Encoding.Default; string[] lines = File.ReadAllLines(fileInfo.FullName, encoding); @@ -362,21 +364,33 @@ internal static partial class HelperMarkdown completedLineNumber = i; continue; } + if (line.Length > 14 && line[..14] == "startedColumns") + { + startedColumnsLineNumber = i; + continue; + } + if (line.Length > 16 && line[..16] == "completedColumns") + { + completedColumnsLineNumber = i; + continue; + } if (h1LineNumber is null && line.Length > 2 && line[0] == '#' && line[1] == ' ') { h1LineNumber = i; continue; } } - LineNumber lineNumber = new(createdLineNumber, - completedLineNumber, - h1LineNumber, - frontMatterYamlEndLineNumber, - lines.AsReadOnly(), - progressLineNumber, - statusLineNumber, - typeLineNumber, - updatedLineNumber); + LineNumber lineNumber = new(Created: createdLineNumber, + Completed: completedLineNumber, + CompletedColumns: completedColumnsLineNumber, + H1: h1LineNumber, + FrontMatterYamlEnd: frontMatterYamlEndLineNumber, + Lines: lines.AsReadOnly(), + Progress: progressLineNumber, + Status: statusLineNumber, + StartedColumns: startedColumnsLineNumber, + Type: typeLineNumber, + Updated: updatedLineNumber); return lineNumber; } diff --git a/Models/LineNumber.cs b/Models/LineNumber.cs index bc1fc64..044bf9f 100644 --- a/Models/LineNumber.cs +++ b/Models/LineNumber.cs @@ -5,11 +5,13 @@ namespace File_Folder_Helper.Models; internal record LineNumber(int? Created, int? Completed, + int? CompletedColumns, int? H1, int? FrontMatterYamlEnd, ReadOnlyCollection Lines, int? Progress, int? Status, + int? StartedColumns, int? Type, int? Updated);