Pin nixpkgs to the revision used by itc.componentware: the channel version ships a latexminted that crashes on Python 3.14, which made every listing fail and sent latexmk into an endless error prompt. Also force nonstopmode/halt-on-error so a broken listing can never loop again.
50 lines
1.7 KiB
C#
50 lines
1.7 KiB
C#
namespace Houston.Services;
|
|
|
|
public class IniParser
|
|
{
|
|
public async Task<IniDocument> ParseAsync(TextReader reader, CancellationToken cancellationToken)
|
|
{
|
|
var sections = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
|
|
var current = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
sections[String.Empty] = current;
|
|
|
|
while (await reader.ReadLineAsync(cancellationToken) is { } line)
|
|
{
|
|
var trimmed = line.Trim();
|
|
|
|
// Skip blank lines and comments
|
|
if (trimmed.Length == 0 || trimmed[0] is ';' or '#')
|
|
continue;
|
|
|
|
if (trimmed.StartsWith('[') && trimmed.EndsWith(']'))
|
|
{
|
|
var name = trimmed[1..^1].Trim();
|
|
if (!sections.TryGetValue(name, out current!))
|
|
sections[name] = current = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
continue;
|
|
}
|
|
|
|
var separator = trimmed.IndexOf('=');
|
|
if (separator < 0)
|
|
continue;
|
|
|
|
var key = trimmed[..separator].Trim();
|
|
if (key.Length == 0)
|
|
continue;
|
|
|
|
// Last value wins for duplicate keys within a section.
|
|
current[key] = trimmed[(separator + 1)..].Trim();
|
|
}
|
|
|
|
return new(sections);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses INI content from a string.
|
|
/// </summary>
|
|
public Task<IniDocument> ParseAsync(string content, CancellationToken cancellationToken)
|
|
{
|
|
using var reader = new StringReader(content);
|
|
return ParseAsync(reader, cancellationToken);
|
|
}
|