Add CSV/TSV/PSV rainbow highlighters (light/dark) support
build / build (push) Has been cancelled
build / publish (push) Has been cancelled

This commit is contained in:
ema
2026-04-17 11:18:49 +08:00
parent ed8c2997f5
commit 0cda83c26d
12 changed files with 436 additions and 5 deletions
@@ -0,0 +1,94 @@
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using System.Windows.Media;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Dark;
/// <summary>
/// Rainbow CSV Highlighting Definition
/// </summary>
public class CSVHighlightingDefinition : DarkHighlightingDefinition
{
public override string Name => "CSV";
public override string Extension => ".csv";
public override DocumentColorizingTransformer[] LineTransformers { get; } = [new RainbowTransformer(',')];
public class RainbowTransformer(char sep) : DocumentColorizingTransformer
{
private readonly char _sep = sep;
private readonly Brush[] _brushes =
[
Colors.OrangeRed.ToBrush(),
Colors.CornflowerBlue.ToBrush(),
Colors.LimeGreen.ToBrush(),
Colors.MediumVioletRed.ToBrush(),
Colors.Peru.ToBrush(),
Colors.CadetBlue.ToBrush(),
Colors.Khaki.ToBrush(),
Colors.MediumSlateBlue.ToBrush(),
];
protected override void ColorizeLine(DocumentLine line)
{
var text = CurrentContext.Document.GetText(line);
if (string.IsNullOrEmpty(text))
return;
int offset = line.Offset;
int i = 0;
int col = 0;
int len = text.Length;
while (i < len)
{
int contentStart = i;
int contentEnd = i;
if (text[i] == '"')
{
contentStart = i + 1;
i++;
while (i < len)
{
if (text[i] == '"')
{
if (i + 1 < len && text[i + 1] == '"')
{
i += 2;
continue;
}
else
{
contentEnd = i;
i++;
break;
}
}
i++;
}
while (i < len && text[i] != _sep) i++;
}
else
{
contentStart = i;
while (i < len && text[i] != _sep) i++;
contentEnd = i;
}
if (contentEnd > contentStart)
{
int a = offset + contentStart;
int b = offset + contentEnd;
var brush = _brushes[col % _brushes.Length];
ChangeLinePart(a, b, el => el.TextRunProperties.SetForegroundBrush(brush));
}
if (i < len && text[i] == _sep) i++;
col++;
}
}
}
}
@@ -0,0 +1,15 @@
using ICSharpCode.AvalonEdit.Rendering;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Dark;
/// <summary>
/// Rainbow PSV Highlighting Definition
/// </summary>
public class PSVHighlightingDefinition : DarkHighlightingDefinition
{
public override string Name => "PSV";
public override string Extension => ".psv";
public override DocumentColorizingTransformer[] LineTransformers { get; } = [new CSVHighlightingDefinition.RainbowTransformer('|')];
}
@@ -0,0 +1,15 @@
using ICSharpCode.AvalonEdit.Rendering;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Dark;
/// <summary>
/// Rainbow TSV Highlighting Definition
/// </summary>
public class TSVHighlightingDefinition : DarkHighlightingDefinition
{
public override string Name => "TSV";
public override string Extension => ".tsv";
public override DocumentColorizingTransformer[] LineTransformers { get; } = [new CSVHighlightingDefinition.RainbowTransformer('\t')];
}
@@ -0,0 +1,102 @@
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using System.Windows.Media;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Light;
/// <summary>
/// Rainbow CSV Highlighting Definition
/// </summary>
public class CSVHighlightingDefinition : LightHighlightingDefinition
{
public override string Name => "CSV";
public override string Extension => ".csv";
public override DocumentColorizingTransformer[] LineTransformers { get; } = [new RainbowTransformer(',')];
public class RainbowTransformer(char sep) : DocumentColorizingTransformer
{
private readonly char _sep = sep;
private readonly Brush[] _brushes =
[
Colors.DarkRed.ToBrush(),
Colors.DarkBlue.ToBrush(),
Colors.DarkGreen.ToBrush(),
Colors.DarkMagenta.ToBrush(),
Colors.SaddleBrown.ToBrush(),
Colors.Teal.ToBrush(),
Colors.Olive.ToBrush(),
Colors.SlateBlue.ToBrush(),
];
protected override void ColorizeLine(DocumentLine line)
{
var text = CurrentContext.Document.GetText(line);
if (string.IsNullOrEmpty(text))
return;
int offset = line.Offset;
int i = 0;
int col = 0;
int len = text.Length;
while (i < len)
{
int fieldStart = i;
int contentStart = i;
int contentEnd = i;
if (text[i] == '"')
{
// quoted field
contentStart = i + 1;
i++;
while (i < len)
{
if (text[i] == '"')
{
if (i + 1 < len && text[i + 1] == '"')
{
// escaped quote
i += 2;
continue;
}
else
{
// end quote
contentEnd = i;
i++;
break;
}
}
i++;
}
// skip to separator
while (i < len && text[i] != _sep) i++;
}
else
{
// unquoted
contentStart = i;
while (i < len && text[i] != _sep) i++;
contentEnd = i;
}
// color content [contentStart, contentEnd)
if (contentEnd > contentStart)
{
int a = offset + contentStart;
int b = offset + contentEnd;
var brush = _brushes[col % _brushes.Length];
ChangeLinePart(a, b, el => el.TextRunProperties.SetForegroundBrush(brush));
}
// advance past separator
if (i < len && text[i] == _sep) i++;
col++;
}
}
}
}
@@ -0,0 +1,15 @@
using ICSharpCode.AvalonEdit.Rendering;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Light;
/// <summary>
/// Rainbow PSV Highlighting Definition
/// </summary>
public class PSVHighlightingDefinition : LightHighlightingDefinition
{
public override string Name => "PSV";
public override string Extension => ".psv";
public override DocumentColorizingTransformer[] LineTransformers { get; } = [new CSVHighlightingDefinition.RainbowTransformer('|')];
}
@@ -0,0 +1,15 @@
using ICSharpCode.AvalonEdit.Rendering;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Light;
/// <summary>
/// Rainbow TSV Highlighting Definition
/// </summary>
public class TSVHighlightingDefinition : LightHighlightingDefinition
{
public override string Name => "TSV";
public override string Extension => ".tsv";
public override DocumentColorizingTransformer[] LineTransformers { get; } = [new CSVHighlightingDefinition.RainbowTransformer('\t')];
}