Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4793787
replace fixed regex with regex properties and regex attributes
Hirogen Nov 30, 2025
039b19b
Merge branch 'Development' into performance_optimizations
Dec 2, 2025
ffa5ecc
optimization, added ISpan stuff
Dec 2, 2025
f54bcc4
pipelines docs for implementation
Dec 2, 2025
76a42f2
Pipeline added
Hirogen Dec 2, 2025
02108cd
Merge branch 'Development' into new_reader
Dec 3, 2025
2fbc998
pipelines update
Dec 4, 2025
90ef20b
locks
Dec 4, 2025
5040622
update reader
Dec 6, 2025
ea35028
chore: update plugin hashes [skip ci]
github-actions[bot] Dec 6, 2025
cceaa03
Update src/ColumnizerLib/ILogLineSpanColumnizer.cs
Hirogen Dec 6, 2025
a2e43ff
Update src/LogExpert.Core/Interface/ILogStreamReaderSpan.cs
Hirogen Dec 6, 2025
0765822
Update src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
Hirogen Dec 6, 2025
a76efa0
Update src/LogExpert.Core/Interface/ILogStreamReaderSpan.cs
Hirogen Dec 6, 2025
91f5c30
Update src/LogExpert.Core/Classes/Log/LogBuffer.cs
Hirogen Dec 6, 2025
f846922
chore: update plugin hashes [skip ci]
github-actions[bot] Dec 6, 2025
97808ba
Update src/ColumnizerLib/ITextValue.cs
Hirogen Dec 6, 2025
433ba41
Update src/ColumnizerLib/ILogLine.cs
Hirogen Dec 6, 2025
6a3b31d
review comments
Hirogen Dec 6, 2025
262fab1
chore: update plugin hashes [skip ci]
github-actions[bot] Dec 6, 2025
f163dab
benchmakr summary
Dec 6, 2025
a039252
Merge branch 'new_reader' of https://github.com/LogExperts/LogExpert …
Dec 6, 2025
b28a006
chore: update plugin hashes [skip ci]
github-actions[bot] Dec 6, 2025
3f8dde4
benchmark md updates
Hirogen Dec 6, 2025
0a2f759
Merge branch 'new_reader' of https://github.com/LogExperts/LogExpert …
Hirogen Dec 6, 2025
33fa73e
chore: update plugin hashes [skip ci]
github-actions[bot] Dec 6, 2025
7051b8d
update
Hirogen Dec 7, 2025
316370d
update new line search
Hirogen Dec 7, 2025
3db95b1
more changes
Hirogen Dec 7, 2025
c795053
fixing no lines showing up
Dec 10, 2025
7e32496
filereader documentation
Dec 10, 2025
08db763
missing resources link
Hirogen Dec 10, 2025
056c712
updates
Hirogen Dec 10, 2025
3e7f15c
clear datagrid when exiting logexpert, for faster exit
Dec 11, 2025
d166500
added ReadOnlyMemory<char>
Dec 11, 2025
1e1e620
Memory
Hirogen Dec 11, 2025
791beee
A lot of Memory
Dec 12, 2025
2d84ab1
fixed not showing any lines... now all is shown
Hirogen Dec 12, 2025
b3b95ac
memory, more memory, even more memory
Hirogen Dec 12, 2025
1bbd7b5
fixing unittests
Hirogen Dec 12, 2025
9c4a3d9
Merge branch 'Development' into new_reader
Hirogen Dec 12, 2025
4e3bd3f
chore: update plugin hashes [skip ci]
github-actions[bot] Dec 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 12 additions & 21 deletions src/ColumnizerLib.UnitTests/ColumnTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void Column_TruncatesAtConfiguredDisplayLength ()
Column.SetMaxDisplayLength(10_000);

// Create a line longer than the display max length
var longValue = new StringBuilder().Append('X', 15_000).ToString();
var longValue = new StringBuilder().Append('X', 15_000).ToString().AsMemory();

Column column = new()
{
Expand All @@ -57,8 +57,8 @@ public void Column_TruncatesAtConfiguredDisplayLength ()

// DisplayValue should be truncated at 10,000 with "..." appended
Assert.That(column.DisplayValue.Length, Is.EqualTo(10_003)); // 10000 + "..."
Assert.That(column.DisplayValue.EndsWith("...", StringComparison.OrdinalIgnoreCase), Is.True);
Assert.That(column.DisplayValue.StartsWith("XXX", StringComparison.OrdinalIgnoreCase), Is.True);
Assert.That(column.DisplayValue.ToString().EndsWith("...", StringComparison.OrdinalIgnoreCase), Is.True);
Assert.That(column.DisplayValue.ToString().StartsWith("XXX", StringComparison.OrdinalIgnoreCase), Is.True);

// Reset for other tests
Column.SetMaxDisplayLength(20_000);
Expand All @@ -69,7 +69,7 @@ public void Column_NoTruncationWhenBelowLimit ()
{
Column.SetMaxDisplayLength(20_000);

var normalValue = new StringBuilder().Append('Y', 5_000).ToString();
var normalValue = new StringBuilder().Append('Y', 5_000).ToString().AsMemory();
Column column = new()
{
FullValue = normalValue
Expand All @@ -80,37 +80,28 @@ public void Column_NoTruncationWhenBelowLimit ()
}

[Test]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Unit Test")]
public void Column_NullCharReplacement ()
{
Column column = new()
{
FullValue = "asdf\0"
FullValue = "asdf\0".AsMemory()
};

//Switch between the different implementation for the windows versions
//Not that great solution but currently I'm out of ideas, I know that currently
//only one implementation depending on the windows version is executed
if (Environment.Version >= Version.Parse("6.2"))
{
Assert.That(column.DisplayValue, Is.EqualTo("asdf␀"));
}
else
{
Assert.That(column.DisplayValue, Is.EqualTo("asdf "));
}

Assert.That(column.FullValue, Is.EqualTo("asdf\0"));
Assert.That(column.DisplayValue.ToString(), Is.EqualTo("asdf "));
Assert.That(column.FullValue.ToString(), Is.EqualTo("asdf\0"));
}

[Test]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Unit Test")]
public void Column_TabReplacement ()
{
Column column = new()
{
FullValue = "asdf\t"
FullValue = "asdf\t".AsMemory()
};

Assert.That(column.DisplayValue, Is.EqualTo("asdf "));
Assert.That(column.FullValue, Is.EqualTo("asdf\t"));
Assert.That(column.DisplayValue.ToString(), Is.EqualTo("asdf "));
Assert.That(column.FullValue.ToString(), Is.EqualTo("asdf\t"));
}
}
177 changes: 143 additions & 34 deletions src/ColumnizerLib/Column.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
namespace ColumnizerLib;

public class Column : IColumn
public class Column : IColumnMemory
{
//TODO Memory Functions need implementation
#region Fields

private const string REPLACEMENT = "...";
Expand All @@ -10,14 +11,14 @@ public class Column : IColumn
// Can be configured via SetMaxDisplayLength()
private static int _maxDisplayLength = 20_000;

private static readonly List<Func<string, string>> _replacements = [
private static readonly List<Func<ReadOnlyMemory<char>, ReadOnlyMemory<char>>> _replacementsMemory = [
//replace tab with 3 spaces, from old coding. Needed???
input => input.Replace("\t", " ", StringComparison.Ordinal),
ReplaceTab,

//shorten string if it exceeds maxLength
input => input.Length > _maxDisplayLength
? string.Concat(input.AsSpan(0, _maxDisplayLength), REPLACEMENT)
: input
//shorten string if it exceeds maxLength
input => input.Length > _maxDisplayLength
? ShortenMemory(input, _maxDisplayLength)
: input
];

#endregion
Expand All @@ -26,43 +27,63 @@ public class Column : IColumn

static Column ()
{
if (Environment.Version >= Version.Parse("6.2"))
{
//Win8 or newer support full UTF8 chars with the preinstalled fonts.
//Replace null char with UTF8 Symbol U+2400 (␀)
_replacements.Add(input => input.Replace("\0", "␀", StringComparison.Ordinal));
}
else
{
//Everything below Win8 the installed fonts seems to not to support reliabel
//Replace null char with space
//.net 10 does no longer support windows lower then windows 10
//TODO: remove if with one of the next releases
//https://github.com/dotnet/core/blob/main/release-notes/10.0/supported-os.md
_replacements.Add(input => input.Replace("\0", " ", StringComparison.Ordinal));
}
//.net 10 only supports Windows10+ which has full UTF8-font support
// Replace null char with UTF-8 Symbol U+2400 (␀)
//https://github.com/dotnet/core/blob/main/release-notes/10.0/supported-os.md
_replacementsMemory.Add(input => ReplaceNullChar(input, ' '));

EmptyColumn = new Column { FullValue = string.Empty };
EmptyColumn = new Column { FullValue = ReadOnlyMemory<char>.Empty };
}

#endregion

#region Properties

public static IColumn EmptyColumn { get; }
public static IColumnMemory EmptyColumn { get; }

[Obsolete]
IColumnizedLogLine IColumn.Parent { get; }

[Obsolete]
string IColumn.FullValue
{
get;
//set
//{
// field = value;

// var temp = FullValue.ToString();

// foreach (var replacement in _replacements)
// {
// temp = replacement(temp);
// }

// DisplayValue = temp.AsMemory();
//}
}

[Obsolete("Use the DisplayValue property of IColumnMemory")]
string IColumn.DisplayValue { get; }

[Obsolete("Use Text property of ITextValueMemory")]
string ITextValue.Text => DisplayValue.ToString();

public IColumnizedLogLine Parent { get; set; }
public IColumnizedLogLineMemory Parent
{
get; set => field = value;
}

public string FullValue
public ReadOnlyMemory<char> FullValue
{
get;
set
{
field = value;

var temp = FullValue;
var temp = value;

foreach (var replacement in _replacements)
foreach (var replacement in _replacementsMemory)
{
temp = replacement(temp);
}
Expand All @@ -71,9 +92,9 @@ public string FullValue
}
}

public string DisplayValue { get; private set; }
public ReadOnlyMemory<char> DisplayValue { get; private set; }

public string Text => DisplayValue;
public ReadOnlyMemory<char> Text => DisplayValue;

#endregion

Expand All @@ -99,12 +120,12 @@ public static void SetMaxDisplayLength (int maxLength)
/// </summary>
public static int GetMaxDisplayLength () => _maxDisplayLength;

public static Column[] CreateColumns (int count, IColumnizedLogLine parent)
public static Column[] CreateColumns (int count, IColumnizedLogLineMemory parent)
{
return CreateColumns(count, parent, string.Empty);
return CreateColumns(count, parent, ReadOnlyMemory<char>.Empty);
}

public static Column[] CreateColumns (int count, IColumnizedLogLine parent, string defaultValue)
public static Column[] CreateColumns (int count, IColumnizedLogLineMemory parent, ReadOnlyMemory<char> defaultValue)
{
var output = new Column[count];

Expand All @@ -118,7 +139,95 @@ public static Column[] CreateColumns (int count, IColumnizedLogLine parent, stri

public override string ToString ()
{
return DisplayValue ?? string.Empty;
return DisplayValue.ToString() ?? ReadOnlyMemory<char>.Empty.ToString();
}

#endregion

#region Private Methods

/// <summary>
/// Replaces tab characters with two spaces in the memory buffer.
/// </summary>
private static ReadOnlyMemory<char> ReplaceTab (ReadOnlyMemory<char> input)
{
var span = input.Span;
var tabIndex = span.IndexOf('\t');

if (tabIndex == -1)
{
return input;
}

// Count total tabs to calculate new length
var tabCount = 0;
foreach (var c in span)
{
if (c == '\t')
{
tabCount++;
}
}

// Allocate new buffer: original length + (tabCount * 1) since we replace 1 char with 2
var newLength = input.Length + tabCount;
var buffer = new char[newLength];
var bufferPos = 0;

for (var i = 0; i < span.Length; i++)
{
if (span[i] == '\t')
{
buffer[bufferPos++] = ' ';
buffer[bufferPos++] = ' ';
}
else
{
buffer[bufferPos++] = span[i];
}
}

return buffer;
}

/// <summary>
/// Shortens the memory buffer to the specified maximum length and appends "...".
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Non Localiced Parameter")]
private static ReadOnlyMemory<char> ShortenMemory (ReadOnlyMemory<char> input, int maxLength)
{
var buffer = new char[maxLength + REPLACEMENT.Length];
input.Span[..maxLength].CopyTo(buffer);
REPLACEMENT.AsSpan().CopyTo(buffer.AsSpan(maxLength));
return buffer;
}

/// <summary>
/// Replaces null characters with the specified replacement character.
/// </summary>
private static ReadOnlyMemory<char> ReplaceNullChar (ReadOnlyMemory<char> input, char replacement)
{
var span = input.Span;
var nullIndex = span.IndexOf('\0');

if (nullIndex == -1)
{
return input;
}

// Need to create a new buffer since we're modifying content
var buffer = new char[input.Length];
span.CopyTo(buffer);

for (var i = 0; i < buffer.Length; i++)
{
if (buffer[i] == '\0')
{
buffer[i] = replacement;
}
}

return buffer;
}

#endregion
Expand Down
12 changes: 9 additions & 3 deletions src/ColumnizerLib/ColumnizedLogLine.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
namespace ColumnizerLib;

public class ColumnizedLogLine : IColumnizedLogLine
public class ColumnizedLogLine : IColumnizedLogLineMemory
{
#region Properties

public ILogLine LogLine { get; set; }
[Obsolete("Use the Property of IColumnizedLogLineMemory")]
ILogLine IColumnizedLogLine.LogLine { get; }

public IColumn[] ColumnValues { get; set; }
[Obsolete("Use the Property of IColumnizedLogLineMemory")]
IColumn[] IColumnizedLogLine.ColumnValues { get; }

public ILogLineMemory LogLine { get; set; }

public IColumnMemory[] ColumnValues { get; set; }

#endregion
}
11 changes: 11 additions & 0 deletions src/ColumnizerLib/IAutoLogLineMemoryColumnizerCallback.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace ColumnizerLib;

public interface IAutoLogLineMemoryColumnizerCallback : IAutoLogLineColumnizerCallback
{
/// <summary>
/// Returns the log line with the given index (zero-based).
/// </summary>
/// <param name="lineNum">Number of the line to be retrieved</param>
/// <returns>A string with line content or null if line number is out of range</returns>
ILogLineMemory GetLogLineMemory (int lineNum);
}
5 changes: 0 additions & 5 deletions src/ColumnizerLib/IColumn.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ColumnizerLib;

public interface IColumn : ITextValue
Expand Down
14 changes: 14 additions & 0 deletions src/ColumnizerLib/IColumnMemory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace ColumnizerLib;

public interface IColumnMemory : IColumn, ITextValueMemory
{
#region Properties

new IColumnizedLogLineMemory Parent { get; }

new ReadOnlyMemory<char> FullValue { get; }

new ReadOnlyMemory<char> DisplayValue { get; }

#endregion
}
6 changes: 0 additions & 6 deletions src/ColumnizerLib/IColumnizedLogLine.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ColumnizerLib;

public interface IColumnizedLogLine
Expand All @@ -11,7 +6,6 @@ public interface IColumnizedLogLine

ILogLine LogLine { get; }


IColumn[] ColumnValues { get; }

#endregion
Expand Down
Loading