625 lines
27 KiB
C#
625 lines
27 KiB
C#
using File_Folder_Helper.Helpers;
|
|
using File_Folder_Helper.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Collections.ObjectModel;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace File_Folder_Helper.ADO2024.PI2;
|
|
|
|
internal static partial class Helper20240623
|
|
{
|
|
|
|
[GeneratedRegex("([A-Z]+(.))")]
|
|
private static partial Regex UpperCase();
|
|
|
|
[GeneratedRegex("[\\s!?.,@:;|\\\\/\"'`£$%\\^&*{}[\\]()<>~#+\\-=_¬]+")]
|
|
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 Record(int? CodeInsidersLine, FileInfo FileInfo, LineNumber LineNumber, int? StopLine, int? SubTasksLine);
|
|
|
|
private record Input(long? AfterEpochTotalMilliseconds,
|
|
string CodeInsiders,
|
|
ReadOnlyCollection<string> DestinationDirectories,
|
|
string DirectoryFilter,
|
|
string Done,
|
|
string IndexFile,
|
|
string SearchPattern,
|
|
string SubTasks,
|
|
string SourceDirectory,
|
|
ReadOnlyCollection<string> Tasks);
|
|
|
|
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
[JsonSerializable(typeof(Input))]
|
|
private partial class InputSourceGenerationContext : JsonSerializerContext
|
|
{
|
|
}
|
|
|
|
private static Record GetRecord(Input input, FileInfo fileInfo)
|
|
{
|
|
Record result;
|
|
string line;
|
|
int? stopLine = null;
|
|
int? subTasksLine = null;
|
|
int? codeInsidersLine = null;
|
|
LineNumber lineNumber = HelperMarkdown.GetLineNumbers(fileInfo);
|
|
for (int i = 0; i < lineNumber.Lines.Count; i++)
|
|
{
|
|
line = lineNumber.Lines[i];
|
|
if (line.StartsWith(input.CodeInsiders) && line[^1] == ')')
|
|
codeInsidersLine = i;
|
|
if (line != input.SubTasks)
|
|
continue;
|
|
subTasksLine = i;
|
|
if (codeInsidersLine is null)
|
|
break;
|
|
if (lineNumber.Lines.Count > i)
|
|
{
|
|
for (int j = i + 1; j < lineNumber.Lines.Count; j++)
|
|
{
|
|
if (lineNumber.Lines[j].Length > 0 && lineNumber.Lines[j][0] == '#')
|
|
{
|
|
stopLine = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
stopLine ??= lineNumber.Lines.Count;
|
|
break;
|
|
}
|
|
result = new(codeInsidersLine, fileInfo, lineNumber, stopLine, subTasksLine);
|
|
return result;
|
|
}
|
|
|
|
private static List<Record> GetRecords(Input input)
|
|
{
|
|
List<Record> results = [];
|
|
Record record;
|
|
FileInfo fileInfo;
|
|
string sourceDirectory = input.SourceDirectory;
|
|
ReadOnlyCollection<string> directoryNames = HelperDirectory.GetDirectoryNames(input.SourceDirectory);
|
|
if (!directoryNames.Any(l => l.StartsWith(input.DirectoryFilter, StringComparison.CurrentCultureIgnoreCase)))
|
|
{
|
|
string directoryName;
|
|
string[] checkDirectories = Directory.GetDirectories(input.SourceDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
foreach (string checkDirectory in checkDirectories)
|
|
{
|
|
directoryName = Path.GetFileName(checkDirectory);
|
|
if (directoryName.StartsWith(input.DirectoryFilter, StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
sourceDirectory = checkDirectory;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
string[] subDirectories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
List<string> files = Directory.GetFiles(sourceDirectory, input.SearchPattern, SearchOption.TopDirectoryOnly).ToList();
|
|
foreach (string subDirectory in subDirectories)
|
|
files.AddRange(Directory.GetFiles(subDirectory, input.SearchPattern, SearchOption.TopDirectoryOnly));
|
|
foreach (string file in files)
|
|
{
|
|
fileInfo = new(file);
|
|
record = GetRecord(input, fileInfo);
|
|
results.Add(record);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static string GetParamCase(string value)
|
|
{
|
|
string result;
|
|
StringBuilder stringBuilder = new(value);
|
|
Match[] matches = UpperCase().Matches(value).ToArray();
|
|
for (int i = matches.Length - 1; i > -1; i--)
|
|
_ = stringBuilder.Insert(matches[i].Index, '-');
|
|
string[] segments = InvalidCharacter().Split(stringBuilder.ToString().ToLower());
|
|
result = string.Join('-', segments).Trim('-');
|
|
return result;
|
|
}
|
|
|
|
private static ReadOnlyCollection<SubTaskLine> GetSubTaskLines(Input input, bool? foundDone, string fallbackLine, Record record)
|
|
{
|
|
List<SubTaskLine> results = [];
|
|
char done;
|
|
string line;
|
|
string text;
|
|
bool doneValue;
|
|
SubTaskLine subTaskLine;
|
|
bool foundSubTasks = false;
|
|
int tasksZeroLength = input.Tasks[0].Length;
|
|
long ticks = record.FileInfo.LastWriteTime.Ticks;
|
|
for (int i = 0; i < record.LineNumber.Lines.Count; i++)
|
|
{
|
|
line = record.LineNumber.Lines[i];
|
|
if (!foundSubTasks && line == input.SubTasks)
|
|
foundSubTasks = true;
|
|
if (!foundSubTasks)
|
|
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);
|
|
results.Add(subTaskLine);
|
|
}
|
|
doneValue = foundDone is not null && foundDone.Value;
|
|
if (record.LineNumber.H1 is null)
|
|
subTaskLine = new(fallbackLine, doneValue, ticks, Line: null);
|
|
else
|
|
{
|
|
done = foundDone is null || !foundDone.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);
|
|
}
|
|
results.Add(subTaskLine);
|
|
return new(results);
|
|
}
|
|
|
|
private static string GetSeasonName(int dayOfYear)
|
|
{
|
|
string result = dayOfYear switch
|
|
{
|
|
< 78 => "0.Winter",
|
|
< 124 => "1.Spring",
|
|
< 171 => "2.Spring",
|
|
< 217 => "3.Summer",
|
|
< 264 => "4.Summer",
|
|
< 309 => "5.Fall",
|
|
< 354 => "6.Fall",
|
|
_ => "7.Winter"
|
|
};
|
|
return result;
|
|
}
|
|
|
|
private static string[] GetIndexLines(string h1, ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection) =>
|
|
[
|
|
"---",
|
|
"startedColumns:",
|
|
" - 'In Progress'",
|
|
"completedColumns:",
|
|
" - Done",
|
|
"---",
|
|
string.Empty,
|
|
$"# {h1}",
|
|
string.Empty,
|
|
"## Backlog",
|
|
string.Empty,
|
|
string.Join(Environment.NewLine, h1ParamCaseCollection.Select(l => $"- [{l.ParamCase}](tasks/{l.ParamCase}.md)")),
|
|
string.Empty,
|
|
"## Todo",
|
|
string.Empty,
|
|
"## In Progress",
|
|
string.Empty,
|
|
"## Done",
|
|
string.Empty
|
|
];
|
|
|
|
private static string[] GetCascadingStyleSheetsLines() =>
|
|
[
|
|
".kanbn-column-done .kanbn-column-task-list {",
|
|
" border-color: #198038;",
|
|
"}",
|
|
string.Empty,
|
|
".kanbn-task-data-created {",
|
|
" display: none;",
|
|
"}",
|
|
string.Empty,
|
|
".kanbn-task-data-workload {",
|
|
" display: none;",
|
|
"}"
|
|
];
|
|
|
|
private static string GetSettingsLines() =>
|
|
/*lang=json,strict*/ """
|
|
{
|
|
"[markdown]": {
|
|
"editor.wordWrap": "off"
|
|
},
|
|
"cSpell.words": [
|
|
"kanbn"
|
|
]
|
|
}
|
|
""";
|
|
|
|
private static string GetTasksLines(string directory) =>
|
|
/*lang=json,strict*/ """
|
|
{
|
|
"version": "2.0.0",
|
|
"tasks": [
|
|
{
|
|
"label": "File-Folder-Helper AOT s X Day-Helper-2024-06-23",
|
|
"type": "shell",
|
|
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
|
|
"args": [
|
|
"s",
|
|
"X",
|
|
"{}",
|
|
"Day-Helper-2024-06-23",
|
|
"*.md",
|
|
"##_Sub-tasks",
|
|
"-_[code-insiders](",
|
|
"index.md",
|
|
"-_[,](",
|
|
"##_Done",
|
|
".kan",
|
|
"D:/5-Other-Small/Kanban/Year-Season",
|
|
"316940400000"
|
|
],
|
|
"problemMatcher": []
|
|
}
|
|
]
|
|
}
|
|
""".Replace("{}", directory.Replace('\\', '/'));
|
|
|
|
private static void FileWriteAllText(string path, string contents)
|
|
{
|
|
// string checkJson = Regex.Replace(File.ReadAllText(path), @"\s+", " ", RegexOptions.Multiline);
|
|
// if (Regex.Replace(singletonJson, @"\s+", " ", RegexOptions.Multiline) != checkJson)
|
|
// File.WriteAllText(path, singletonJson);
|
|
string old = !File.Exists(path) ? string.Empty : File.ReadAllText(path);
|
|
if (old != contents)
|
|
File.WriteAllText(path, contents);
|
|
}
|
|
|
|
private static void FileWriteAllText(string path, string[] contents) =>
|
|
FileWriteAllText(path, string.Join(Environment.NewLine, contents));
|
|
|
|
private static ReadOnlyCollection<H1AndParamCase> GetH1ParamCaseCollection(Input input, ReadOnlyCollection<string> lines)
|
|
{
|
|
List<H1AndParamCase> results = [];
|
|
string h1;
|
|
string line;
|
|
string paramCase;
|
|
bool foundSubTasks = false;
|
|
H1AndParamCase h1AndParamCase;
|
|
int tasksZeroLength = input.Tasks[0].Length;
|
|
for (int i = 0; i < lines.Count; i++)
|
|
{
|
|
line = lines[i];
|
|
if (!foundSubTasks && line == input.SubTasks)
|
|
foundSubTasks = true;
|
|
if (!foundSubTasks)
|
|
continue;
|
|
if (line.Length <= tasksZeroLength || !line.StartsWith(input.Tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']')
|
|
continue;
|
|
h1 = line[(tasksZeroLength + 3)..];
|
|
if (string.IsNullOrEmpty(h1))
|
|
continue;
|
|
paramCase = GetParamCase(h1);
|
|
h1AndParamCase = new(h1, paramCase);
|
|
results.Add(h1AndParamCase);
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
private static void CreateFiles(string directory, ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection)
|
|
{
|
|
foreach (H1AndParamCase h1ParamCase in h1ParamCaseCollection)
|
|
FileWriteAllText(Path.Combine(directory, $"{h1ParamCase.ParamCase}.md"), $"# {h1ParamCase.H1}");
|
|
}
|
|
|
|
private static string WriteAndGetIndexFile(string h1, string verifiedDirectory, ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection)
|
|
{
|
|
string result;
|
|
string[] indexLines = GetIndexLines(h1, h1ParamCaseCollection);
|
|
string kanbanDirectory = Path.Combine(verifiedDirectory, ".kanbn");
|
|
string tasksKanbanDirectory = Path.Combine(kanbanDirectory, "tasks");
|
|
if (!Directory.Exists(tasksKanbanDirectory))
|
|
_ = Directory.CreateDirectory(tasksKanbanDirectory);
|
|
string verifiedVisualStudioCodeDirectory = Path.Combine(verifiedDirectory, ".vscode");
|
|
if (!Directory.Exists(verifiedVisualStudioCodeDirectory))
|
|
_ = Directory.CreateDirectory(verifiedVisualStudioCodeDirectory);
|
|
result = Path.Combine(kanbanDirectory, "index.md");
|
|
CreateFiles(tasksKanbanDirectory, h1ParamCaseCollection);
|
|
FileWriteAllText(result, indexLines);
|
|
FileWriteAllText(Path.Combine(kanbanDirectory, "board.css"), GetCascadingStyleSheetsLines());
|
|
FileWriteAllText(Path.Combine(verifiedVisualStudioCodeDirectory, "settings.json"), GetSettingsLines());
|
|
FileWriteAllText(Path.Combine(verifiedVisualStudioCodeDirectory, "tasks.json"), GetTasksLines(verifiedDirectory));
|
|
return result;
|
|
}
|
|
|
|
private static ReadOnlyCollection<SubTaskLine> GetSubTaskLines(Input input, FileInfo fileInfo, LineNumber lineNumber)
|
|
{
|
|
List<SubTaskLine> results = [];
|
|
char done;
|
|
FileInfo f;
|
|
Record record;
|
|
bool doneValue;
|
|
string[] segments;
|
|
string fallbackLine;
|
|
bool? foundDone = null;
|
|
ReadOnlyCollection<SubTaskLine> subTaskLines;
|
|
for (int i = 0; i < lineNumber.Lines.Count; i++)
|
|
{
|
|
if (lineNumber.Lines[i] == input.Done)
|
|
foundDone = true;
|
|
segments = lineNumber.Lines[i].Split(input.Tasks[1]);
|
|
doneValue = foundDone is not null && foundDone.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~~";
|
|
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));
|
|
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);
|
|
for (int j = subTaskLines.Count - 1; j >= 0; j--)
|
|
results.Add(subTaskLines[j]);
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
private static Input GetInput(List<string> args)
|
|
{
|
|
string indexFile = args[5];
|
|
string searchPattern = args[2];
|
|
string directoryFilter = args[8];
|
|
string done = args[7].Replace('_', ' ');
|
|
string subTasks = args[3].Replace('_', ' ');
|
|
string codeInsiders = args[4].Replace('_', ' ');
|
|
string sourceDirectory = Path.GetFullPath(args[0]);
|
|
string[] tasks = args[6].Split(',').Select(l => l.Replace('_', ' ')).ToArray();
|
|
long? afterEpochTotalMilliseconds = args.Count < 11 ? null : long.Parse(args[10]);
|
|
string[] destinationDirectories = args.Count < 10 ? [] : args.Count < 12 ? [Path.GetFullPath(args[9])] : [Path.GetFullPath(args[9]), Path.GetFullPath(args[11])];
|
|
Input input = new(AfterEpochTotalMilliseconds: afterEpochTotalMilliseconds,
|
|
CodeInsiders: codeInsiders,
|
|
DestinationDirectories: destinationDirectories.AsReadOnly(),
|
|
DirectoryFilter: directoryFilter,
|
|
Done: done,
|
|
IndexFile: indexFile,
|
|
SearchPattern: searchPattern,
|
|
SubTasks: subTasks,
|
|
SourceDirectory: sourceDirectory,
|
|
Tasks: tasks.AsReadOnly());
|
|
if (input.Tasks[0] != "- [" || input.Tasks[1] != "](")
|
|
throw new Exception(JsonSerializer.Serialize(input, InputSourceGenerationContext.Default.Input));
|
|
return input;
|
|
}
|
|
|
|
private static string? MaybeWriteAndGetIndexFile(Input input, Record record, string? checkDirectory)
|
|
{
|
|
string? result;
|
|
if (string.IsNullOrEmpty(checkDirectory) || input.AfterEpochTotalMilliseconds is null || input.DestinationDirectories.Count == 0)
|
|
result = null;
|
|
else
|
|
{
|
|
if (!input.DestinationDirectories.Any(checkDirectory.Contains))
|
|
result = null;
|
|
else
|
|
{
|
|
if (record.LineNumber.H1 is null)
|
|
result = null;
|
|
else
|
|
{
|
|
string segment = Path.GetFileName(checkDirectory);
|
|
string h1 = record.LineNumber.Lines[record.LineNumber.H1.Value];
|
|
DateTime utcEpochDateTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
long utcEpochTotalMilliseconds = (long)Math.Floor(DateTime.UtcNow.Subtract(utcEpochDateTime).TotalMilliseconds);
|
|
if (!long.TryParse(segment, out long check) || check < input.AfterEpochTotalMilliseconds || check > utcEpochTotalMilliseconds)
|
|
result = null;
|
|
else
|
|
{
|
|
ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection = GetH1ParamCaseCollection(input, record.LineNumber.Lines);
|
|
if (h1ParamCaseCollection.Count == 0)
|
|
result = null;
|
|
else
|
|
{
|
|
DateTime dateTime = utcEpochDateTime.AddMilliseconds(check).ToLocalTime();
|
|
string seasonName = GetSeasonName(dateTime.DayOfYear);
|
|
ReadOnlyCollection<string> directoryNames = HelperDirectory.GetDirectoryNames(checkDirectory);
|
|
if (!directoryNames.Contains(dateTime.Year.ToString()) || !directoryNames.Contains($"{dateTime.Year}-{seasonName}") || !directoryNames.Contains(check.ToString()))
|
|
result = null;
|
|
else
|
|
result = WriteAndGetIndexFile(h1, checkDirectory, h1ParamCaseCollection);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static bool FileWrite(Record record, List<string> newLines, double percent)
|
|
{
|
|
bool result = false;
|
|
if (record.StopLine is not null && record.SubTasksLine is not null)
|
|
{
|
|
string contents;
|
|
string progressLine;
|
|
List<string> resultLines;
|
|
resultLines = record.LineNumber.Lines.ToList();
|
|
if (record.LineNumber.FrontMatterYamlEnd is not null)
|
|
{
|
|
progressLine = $"progress: {percent}";
|
|
if (record.LineNumber.Progress is not null)
|
|
resultLines[record.LineNumber.Progress.Value] = progressLine;
|
|
else
|
|
{
|
|
resultLines.Insert(record.LineNumber.FrontMatterYamlEnd.Value, progressLine);
|
|
contents = string.Join(Environment.NewLine, resultLines);
|
|
FileWriteAllText(record.FileInfo.FullName, contents);
|
|
result = true;
|
|
}
|
|
if (!result && record.LineNumber.Completed is null && percent > 99.9)
|
|
{
|
|
resultLines.Insert(record.LineNumber.FrontMatterYamlEnd.Value, $"completed: {DateTime.Now:yyyy-MM-dd}");
|
|
contents = string.Join(Environment.NewLine, resultLines);
|
|
FileWriteAllText(record.FileInfo.FullName, contents);
|
|
result = true;
|
|
}
|
|
if (!result && record.LineNumber.Completed is not null && percent < 99.9)
|
|
{
|
|
resultLines.RemoveAt(record.LineNumber.Completed.Value);
|
|
contents = string.Join(Environment.NewLine, resultLines);
|
|
FileWriteAllText(record.FileInfo.FullName, contents);
|
|
result = true;
|
|
}
|
|
}
|
|
if (!result)
|
|
{
|
|
for (int i = record.StopLine.Value - 1; i > record.SubTasksLine.Value + 1; i--)
|
|
resultLines.RemoveAt(i);
|
|
if (record.StopLine.Value == record.LineNumber.Lines.Count && resultLines[^1].Length == 0)
|
|
resultLines.RemoveAt(resultLines.Count - 1);
|
|
for (int i = 0; i < newLines.Count; i++)
|
|
resultLines.Insert(record.SubTasksLine.Value + 1 + i, newLines[i]);
|
|
resultLines.Insert(record.SubTasksLine.Value + 1, string.Empty);
|
|
contents = string.Join(Environment.NewLine, resultLines);
|
|
FileWriteAllText(record.FileInfo.FullName, contents);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static FileInfo GetIndexFileInfo(ILogger<Worker> logger, Input input, Record record, string codeInsidersLine)
|
|
{
|
|
FileInfo result;
|
|
string? indexFile;
|
|
List<string> results;
|
|
string raw = codeInsidersLine[input.CodeInsiders.Length..^1];
|
|
string checkDirectory = $"{raw[..2].ToUpper()}{raw[2..]}";
|
|
if (!Directory.Exists(checkDirectory))
|
|
{
|
|
if (input.DestinationDirectories.Count > 0 && input.DestinationDirectories.Any(checkDirectory.Contains))
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
}
|
|
if (!Directory.Exists(checkDirectory))
|
|
results = [];
|
|
else
|
|
{
|
|
results = Directory.GetFiles(checkDirectory, input.IndexFile, SearchOption.AllDirectories).ToList();
|
|
if (results.Count != 1)
|
|
{
|
|
for (int i = results.Count - 1; i > -1; i--)
|
|
{
|
|
if (!results[i].Contains(input.DirectoryFilter, StringComparison.CurrentCultureIgnoreCase))
|
|
results.RemoveAt(i);
|
|
}
|
|
}
|
|
if (results.Count == 0)
|
|
{
|
|
indexFile = MaybeWriteAndGetIndexFile(input, record, checkDirectory);
|
|
if (!string.IsNullOrEmpty(indexFile))
|
|
results.Add(indexFile);
|
|
else
|
|
logger.LogInformation("<{checkDirectory}>", checkDirectory);
|
|
}
|
|
}
|
|
result = results.Count == 0 ? new(Path.Combine(checkDirectory, input.IndexFile)) : new(results[0]);
|
|
return result;
|
|
}
|
|
|
|
internal static void UpdateSubTasksInMarkdownFiles(ILogger<Worker> logger, List<string> args)
|
|
{
|
|
bool reload;
|
|
int allCount;
|
|
int lineCheck;
|
|
double percent;
|
|
double doneCount;
|
|
FileInfo fileInfo;
|
|
List<Record> records;
|
|
LineNumber lineNumber;
|
|
List<string> newLines;
|
|
bool reloadAny = false;
|
|
string? checkDirectory;
|
|
string codeInsidersLine;
|
|
List<string> oldLines = [];
|
|
Input input = GetInput(args);
|
|
string fileNameWithoutExtension;
|
|
ReadOnlyCollection<SubTaskLine> subTaskLines;
|
|
for (int z = 0; z < 9; z++)
|
|
{
|
|
records = GetRecords(input);
|
|
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;
|
|
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(record.FileInfo.FullName);
|
|
if (record.CodeInsidersLine is not null)
|
|
logger.LogInformation("<{file}> has [{subTasks}]", fileNameWithoutExtension, input.SubTasks);
|
|
else
|
|
{
|
|
logger.LogWarning("<{file}> has [{subTasks}] but doesn't have [{codeInsiders}]!", fileNameWithoutExtension, input.SubTasks, input.CodeInsiders);
|
|
continue;
|
|
}
|
|
if (record.StopLine is null)
|
|
continue;
|
|
codeInsidersLine = record.LineNumber.Lines[record.CodeInsidersLine.Value];
|
|
fileInfo = GetIndexFileInfo(logger, input, record, codeInsidersLine);
|
|
if (!fileInfo.Exists)
|
|
{
|
|
checkDirectory = codeInsidersLine[input.CodeInsiders.Length..^1];
|
|
logger.LogError("<{checkDirectory}> doesn't have a [{indexFile}]", Path.GetFileName(checkDirectory), input.IndexFile);
|
|
continue;
|
|
}
|
|
oldLines.Clear();
|
|
checkDirectory = fileInfo.DirectoryName;
|
|
lineNumber = HelperMarkdown.GetLineNumbers(fileInfo);
|
|
subTaskLines = GetSubTaskLines(input, fileInfo, lineNumber);
|
|
if (subTaskLines.Count == 0)
|
|
continue;
|
|
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;
|
|
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);
|
|
// newLines.Insert(0, $"- [{done}] Sub-tasks {doneCount} of {allCount} [{percent * 100}%]");
|
|
}
|
|
if (newLines.Count == oldLines.Count)
|
|
{
|
|
for (int i = 0; i < newLines.Count; i++)
|
|
{
|
|
if (newLines[i] != record.LineNumber.Lines[record.SubTasksLine.Value + 1 + i])
|
|
continue;
|
|
lineCheck++;
|
|
}
|
|
if (lineCheck == newLines.Count)
|
|
continue;
|
|
}
|
|
if (string.IsNullOrEmpty(checkDirectory))
|
|
continue;
|
|
checkDirectory = Path.Combine(checkDirectory, DateTime.Now.Ticks.ToString());
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
Thread.Sleep(500);
|
|
Directory.Delete(checkDirectory);
|
|
reload = FileWrite(record, newLines, percent);
|
|
if (!reloadAny && reload)
|
|
reloadAny = true;
|
|
}
|
|
if (!reloadAny)
|
|
break;
|
|
}
|
|
}
|
|
|
|
} |