using Microsoft.Extensions.Logging; using System.Collections.ObjectModel; namespace File_Folder_Helper.Day; internal static partial class Helper20240623 { private record SubTaskLine(string Text, bool Done, long? Ticks, int? Line); private record Record(int? CodeInsidersLine, string File, string[] Lines, int? StopLine, int? SubTasksLine); private static List GetRecords(string sourceDirectory, string searchPattern, string codeInsiders, string subTasks) { List results = []; int? stopLine; string[] lines; int? subTasksLine; int? codeInsidersLine; string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories); foreach (string file in files) { stopLine = null; subTasksLine = null; codeInsidersLine = null; lines = File.ReadAllLines(file); for (int i = 0; i < lines.Length; i++) { if (lines[i].StartsWith(codeInsiders) && lines[i][^1] == '"') { if (lines.Length > i + 1 && lines[i + 1] == "```") codeInsidersLine = i; } if (lines[i] != subTasks) continue; subTasksLine = i; if (codeInsidersLine is null) break; if (lines.Length > i) { for (int j = i + 1; j < lines.Length; j++) { if (lines[j].Length > 0 && lines[j][0] == '#') { stopLine = j; break; } } } stopLine ??= lines.Length; break; } results.Add(new(codeInsidersLine, file, lines, stopLine, subTasksLine)); } return results; } private static ReadOnlyCollection GetSubTasks(string subTasks, string[] tasks, bool? foundDone, string fallbackLine, FileInfo fileInfo) { List results = []; string line; bool doneValue; string? h1 = null; bool foundSubTasks = false; int tasksZeroLength = tasks[0].Length; string[] lines = File.ReadAllLines(fileInfo.FullName); for (int i = 0; i < lines.Length; i++) { line = lines[i]; if (line.StartsWith("# ")) h1 = line[2..]; if (!foundSubTasks && line == subTasks) foundSubTasks = true; if (!foundSubTasks) continue; if (line.Length <= tasksZeroLength || !line.StartsWith(tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']') continue; doneValue = foundDone is not null && foundDone.Value; results.Add(new($" {line}", doneValue, fileInfo.LastWriteTime.Ticks, i)); } doneValue = foundDone is not null && foundDone.Value; if (h1 is null) results.Add(new(fallbackLine, doneValue, fileInfo.LastWriteTime.Ticks, Line: null)); else results.Add(new(foundDone is null || !foundDone.Value ? $"- [ ] {fileInfo.LastWriteTime.Ticks} ~~~ {h1}" : $"- [x] {fileInfo.LastWriteTime.Ticks} ~~~ {h1}", doneValue, fileInfo.LastWriteTime.Ticks, Line: 0)); return new(results); } internal static void UpdateSubTasksInMarkdownFiles(ILogger logger, List args) { int lineCheck; bool doneValue; bool? foundDone; FileInfo fileInfo; string[] newLines; string[] segments; List lines; string fallbackLine; string[] indexLines; string checkDirectory; string done = args[7]; List indexFiles; string subTasks = args[3]; List oldLines = []; string indexFile = args[5]; string searchPattern = args[2]; string directoryFilter = args[8]; string[] tasks = args[6].Split(','); string codeInsiders = $"{args[4]} \""; List allSubTaskLines = []; ReadOnlyCollection subTaskLines; string sourceDirectory = Path.GetFullPath(args[0]); List records = GetRecords(sourceDirectory, searchPattern, codeInsiders, subTasks); foreach (Record record in from l in records orderby l.SubTasksLine is null, l.CodeInsidersLine is null select l) { if (record.SubTasksLine is null) continue; if (record.CodeInsidersLine is not null) logger.LogInformation("<{file}> has [{subTasks}]", Path.GetFileNameWithoutExtension(record.File), subTasks); else { logger.LogWarning("<{file}> has [{subTasks}] but doesn't have [{codeInsiders}]!", Path.GetFileNameWithoutExtension(record.File), subTasks, codeInsiders); continue; } if (record.StopLine is null) continue; checkDirectory = record.Lines[record.CodeInsidersLine.Value][codeInsiders.Length..^1]; if (!Directory.Exists(checkDirectory)) { logger.LogError("<{checkDirectory}> doesn't exist", Path.GetFileName(checkDirectory)); continue; } indexFiles = Directory.GetFiles(checkDirectory, indexFile, SearchOption.AllDirectories).ToList(); if (indexFiles.Count != 1) { for (int i = indexFiles.Count - 1; i > -1; i--) { if (!indexFiles[i].Contains(directoryFilter, StringComparison.CurrentCultureIgnoreCase)) indexFiles.RemoveAt(i); } if (indexFiles.Count != 1) { logger.LogError("<{checkDirectory}> doesn't have a [{indexFile}]", Path.GetFileName(checkDirectory), indexFile); continue; } } foundDone = null; oldLines.Clear(); allSubTaskLines.Clear(); indexLines = File.ReadAllLines(indexFiles[0]); checkDirectory = Path.GetDirectoryName(indexFiles[0]) ?? throw new Exception(); for (int i = 0; i < indexLines.Length; i++) { if (indexLines[i] == done) foundDone = true; segments = indexLines[i].Split(tasks[1]); doneValue = foundDone is not null && foundDone.Value; if (segments.Length > 2 || !segments[0].StartsWith(tasks[0])) continue; fallbackLine = foundDone is null || !foundDone.Value ? $"- [ ] {segments[0][tasks[0].Length..]}" : $"- [x] {segments[0][tasks[0].Length..]}"; fileInfo = new(Path.GetFullPath(Path.Combine(checkDirectory, segments[1][..^1]))); if (!fileInfo.Exists) { allSubTaskLines.Add(new(fallbackLine, doneValue, Ticks: null, Line: null)); continue; } subTaskLines = GetSubTasks(subTasks, tasks, doneValue, fallbackLine, fileInfo); for (int j = subTaskLines.Count - 1; j >= 0; j--) allSubTaskLines.Add(subTaskLines[j]); } if (allSubTaskLines.Count == 0) continue; lineCheck = 0; for (int i = record.SubTasksLine.Value + 1; i < record.StopLine.Value - 1; i++) oldLines.Add(record.Lines[i]); if (allSubTaskLines.Any(l => l.Ticks is null)) newLines = (from l in allSubTaskLines select l.Text).ToArray(); else newLines = (from l in allSubTaskLines orderby l.Done descending, l.Ticks, l.Line select l.Text).ToArray(); if (newLines.Length == oldLines.Count) { for (int i = 0; i < newLines.Length; i++) { if (newLines[i] != record.Lines[record.SubTasksLine.Value + 1 + i]) continue; lineCheck++; } if (lineCheck == newLines.Length) continue; } checkDirectory = Path.Combine(checkDirectory, DateTime.Now.Ticks.ToString()); _ = Directory.CreateDirectory(checkDirectory); Thread.Sleep(500); Directory.Delete(checkDirectory); lines = record.Lines.ToList(); for (int i = record.StopLine.Value - 1; i > record.SubTasksLine.Value + 1; i--) lines.RemoveAt(i); if (record.StopLine.Value == record.Lines.Length && lines[^1].Length == 0) lines.RemoveAt(lines.Count - 1); for (int i = 0; i < newLines.Length; i++) lines.Insert(record.SubTasksLine.Value + 1 + i, newLines[i]); lines.Insert(record.SubTasksLine.Value + 1, string.Empty); File.WriteAllLines(record.File, lines); } } }