Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0de4b1d
Update README.md
zhenyatnk Dec 21, 2021
08e885a
Merge branch 'pekabon:master' into master
zhenyatnk Dec 23, 2021
5199bd4
Скорректирована логика выделения закладок (#6)
zhenyatnk Dec 25, 2021
a3326a9
Update README.md
zhenyatnk Dec 25, 2021
c41b53e
Update README.md
zhenyatnk Dec 25, 2021
cb7f667
Merge branch 'pekabon:master' into master
zhenyatnk Dec 26, 2021
0eba3f9
Merge branch 'pekabon:master' into master
zhenyatnk Dec 28, 2021
eb8935f
Merge branch 'pekabon:master' into master
zhenyatnk Dec 28, 2021
4e9807f
Merge branch 'pekabon:master' into master
zhenyatnk Jan 14, 2022
f1474d0
Merge branch 'pekabon:master' into master
zhenyatnk Apr 1, 2022
16b4fa8
Merge branch 'pekabon:master' into master
zhenyatnk Apr 12, 2022
1c94909
Merge branch 'pekabon:master' into master
zhenyatnk Jun 3, 2022
ba9b272
Merge branch 'pekabon:master' into master
zhenyatnk Sep 26, 2022
f540127
Merge branch 'pekabon:master' into master
zhenyatnk Nov 20, 2022
45810ca
Merge branch 'pekabon:master' into master
zhenyatnk Mar 3, 2023
6e85fe6
Merge branch 'pekabon:master' into master
zhenyatnk Sep 10, 2026
25b8ca7
Add saved searches and copy-as-displayed (#7)
zhenyatnk Sep 10, 2026
2db222e
Update README.md
zhenyatnk Sep 11, 2026
414604c
Update README.md
zhenyatnk Sep 11, 2026
b285c8e
Config opencode and upgrade deps (#8)
zhenyatnk Sep 11, 2026
e871f2e
Add time filter, timeline, filter chips, theme switcher and search na…
zhenyatnk Sep 11, 2026
b1f8fc9
Migrate UI to WPF-UI, fix dark theme and share JSON folding across views
zhenyatnk Sep 11, 2026
d2f557c
Update README and AGENTS docs for WPF-UI, theming and JSON folding
zhenyatnk Sep 11, 2026
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
4 changes: 2 additions & 2 deletions .github/workflows/build_upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jobs:
steps:
# Install the .NET Core workload
- name: Install .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 7.0.x
dotnet-version: 10.0.x
include-prerelease: true

# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ jobs:

# Install the .NET Core workload
- name: Install .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 7.0.x
dotnet-version: 10.0.x
include-prerelease: true

# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
Expand Down
13 changes: 13 additions & 0 deletions .opencode/command/verify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
description: Rebuild the whole solution and run all tests
agent: build
---

Rebuild `LogGrokCore.sln` and run the full test suite.

1. Run `dotnet build LogGrokCore.sln -t:Rebuild`.
2. Run `dotnet test LogGrokCore.sln`.
3. Report the number of warnings/errors and the test pass/fail counts.
4. If anything fails, show the relevant compiler or test output and propose a fix.

The build must end with 0 warnings and 0 errors.
48 changes: 48 additions & 0 deletions .opencode/skills/dotnet/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
name: dotnet
description: Use when building, testing, running, formatting, or verifying the C#/.NET solution (LogGrokCore.sln), or when editing .cs, .xaml, .csproj, appsettings.yaml, or nlog.config. Covers the dotnet CLI workflow and this repo's warnings-as-errors rules.
---

# .NET workflow (LogGrokCore)

Windows PowerShell shell, repository root `C:\ai-projects\LogGrokCore`.

## Verify a change

Always finish code changes with a clean rebuild and the full test run:

```powershell
dotnet build LogGrokCore.sln -t:Rebuild
dotnet test LogGrokCore.sln
```

For a faster inner loop, `dotnet build LogGrokCore.sln` and
`dotnet test LogGrokCore.sln` (incremental) are fine; `-t:Rebuild` before the
final check.

## Running the app

```powershell
dotnet run --project LogGrokCore\LogGrokCore.csproj
```

The app is a WPF `WinExe`; it opens a window and keeps running. It writes
diagnostic logs to `%LOCALAPPDATA%\LogGrok2\`. If it exits immediately with
code 0, another instance is already running (single-instance manager).

## Constraints

- `Nullable=enable` and `WarningsAsErrors` for `NU1605` plus the nullable
`CS86xx` family: a valid change has **0 warnings**.
- Prefer `dotnet build`/`dotnet test` over launching MSBuild or VS.
- Do not use `cd`; pass `workdir` to the shell tool or `--project`.
- Do not add comments to code.

## When touching configuration

- `appsettings.yaml` is hot-reloaded at runtime and deserialized into settings
classes; keep YAML keys matching the C# property names.
- `nlog.config` must stay NLog 6 compatible: no `concurrentWrites`, and
`${threadid}` takes no properties.
- AvalonDock layout XML uses the `Dirkster.AvalonDock.Serializer.Xml` package
and the `AvalonDock.Serializer.Xml` namespace.
99 changes: 99 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# AGENTS.md

Guidance for AI agents working in this repository.

## Project

**LogGrokCore** — a fast WPF log viewer for very large log files. It parses
structured log lines with configurable regex formats, builds in-memory indexes,
and supports search, filtering, colorization and marking while streaming files
that may be many gigabytes.

- Platform: **Windows only** (WPF).
- Target framework: `net10.0-windows` / `net10.0`.
- SDK pinned by `global.json` (10.0.100, `rollForward: latestMajor`).

## Commands

Run from the repository root unless noted. The OS shell is Windows PowerShell.

```powershell
dotnet restore
dotnet build LogGrokCore.sln
dotnet test LogGrokCore.sln
dotnet run --project LogGrokCore\LogGrokCore.csproj
dotnet format LogGrokCore.sln
```

- The build treats several warnings as errors (`NU1605` and the nullable
`CS86xx` family). A clean build must have **0 warnings**.
- Build output is redirected to `bin\Debug\` / `bin\Release\` (not the default
per-project `bin`).
- After changing code, always verify with `dotnet build` and `dotnet test`.
- Do not commit unless the user explicitly asks.

## Layout

| Project | Purpose |
| --- | --- |
| `LogGrokCore` | WPF app: views, view models, controls, theming, DI bootstrap. |
| `LogGrokCore.Data` | UI-agnostic core: stream loading, line parsing, indexes, search, virtualization. |
| `LogGrokCore.Tests` | Tests for the UI layer. |
| `LogGrokCore.Data.Tests` | Tests for the core data layer. |

Key areas in `LogGrokCore.Data`: `Loader`/`LoaderImpl` (buffered line-aware
reader), `RegexBasedLineParser`, `IndexTree`/`LineIndex`/`SearchLineIndex`,
`Search`/`Pipeline`, `Virtualization`.

The UI layer uses **WPF-UI 4.3.0** (Fluent controls/theming) and
**AvalonDock 5** for docking. Branding/window title is **LogGrok 2.1**.
JSON folding lives in `Controls/TextRender` (`TextView`,
`TextViewSharedFoldingState`, `CollapsibleRegionsMachine`, `FoldingManager`).

## Conventions

- `LangVersion=latest`, `Nullable=enable`. Prefer file-scoped namespaces.
- **Do not add comments** unless they are necessary to explain non-obvious code.
- Tests use **MSTest** (`[TestClass]`, `[TestMethod]`, `[DataRow]`), not xUnit or
NUnit. Assertion arguments are `(expected, actual)`.
- Keep changes minimal and mirror the style of neighbouring files.

## Gotchas

- **AvalonDock 5**: the XML layout serializer lives in the separate package
`Dirkster.AvalonDock.Serializer.Xml`; its namespace is
`AvalonDock.Serializer.Xml` (not `AvalonDock.Layout.Serialization`).
- **NLog 6**: `nlog.config` must stay compatible with NLog 6 — `concurrentWrites`
was removed, and `${threadid}` accepts no properties.
- **WPF-UI theming**: switch themes through `ApplicationThemeManager` /
`Theming/UiThemeService.cs`. Reference `DynamicResource` brushes
(`ApplicationBackgroundBrush`, `TextFillColorPrimaryBrush`,
`ControlStrokeColorDefaultBrush`, …) instead of hard-coded colors so both
themes work. WPF-UI ships *keyed* styles (e.g. `UiGridViewColumnHeaderStyle`),
so implicit styles are not always picked up — define overrides explicitly in
`Bootstrap/App.xaml`.
- **AvalonDock themes**: the main `DockingManager` uses `Vs2013LightTheme` /
`Vs2013DarkTheme`, but the search pane's inner `DockingManager` merges the
light `AvalonDock.Themes.Metro` theme. Metro keys (e.g.
`AvalonDock_ThemeMetro_BaseColor5`) therefore sometimes need theme-aware
overrides in `Styles/DocumentSearchTemplate.xaml`.
- **JSON folding state** is shared per opened document: `DocumentContainer`
registers one `TextViewSharedFoldingState` (exposed as `FoldingState` on
`LogViewModel` / `SearchDocumentViewModel` / `DocumentViewModel`) and the
templates bind it via `textRender:TextView.SharedFoldingState`. The marked-lines
view must use `Document.FoldingState` and the same `TextModel.UniqueId` as the
grid's JSON component, otherwise expansion falls out of sync.
- The app writes diagnostic logs to `%LOCALAPPDATA%\LogGrok2\`.
- Runtime configuration is `appsettings.yaml` (watched and hot-reloaded),
next to the executable.

## Verification

Minimum bar for any change:

```powershell
dotnet build LogGrokCore.sln -t:Rebuild
dotnet test LogGrokCore.sln
```

Both must succeed with 0 warnings and 0 errors.
73 changes: 73 additions & 0 deletions LogGrokCore.Data.Tests/LineRangeIndexedLinesProviderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using LogGrokCore.Data.Index;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LogGrokCore.Data.Tests;

[TestClass]
public class LineRangeIndexedLinesProviderTests
{
private static readonly int[] Lines = { 2, 5, 7, 10, 11, 20 };

[TestMethod]
public void RestrictsFetchToRequestedLineRange()
{
var provider = new LineRangeIndexedLinesProvider(new FakeIndexedLinesProvider(Lines), 5, 12);

Assert.AreEqual(4, provider.Count);
CollectionAssert.AreEqual(new[] { 5, 7, 10, 11 }, FetchAll(provider, provider.Count));
}

[TestMethod]
public void GetIndexByValueReturnsPositionWithinRange()
{
var provider = new LineRangeIndexedLinesProvider(new FakeIndexedLinesProvider(Lines), 5, 12);

Assert.AreEqual(0, provider.GetIndexByValue(5));
Assert.AreEqual(2, provider.GetIndexByValue(10));
Assert.AreEqual(4, provider.GetIndexByValue(100));
Assert.AreEqual(0, provider.GetIndexByValue(1));
}

[TestMethod]
public void EmptyRangeProducesEmptyProvider()
{
var provider = new LineRangeIndexedLinesProvider(new FakeIndexedLinesProvider(Lines), 30, 40);

Assert.AreEqual(0, provider.Count);
}

private static int[] FetchAll(IIndexedLinesProvider provider, int count)
{
var result = new int[count];
provider.Fetch(0, result);
return result;
}

private sealed class FakeIndexedLinesProvider : IIndexedLinesProvider
{
private readonly IReadOnlyList<int> _lines;

public FakeIndexedLinesProvider(IReadOnlyList<int> lines) => _lines = lines;

public int Count => _lines.Count;

public void Fetch(int start, Span<int> values)
{
for (var i = 0; i < values.Length; i++)
values[i] = _lines[start + i];
}

public int GetIndexByValue(int value)
{
for (var i = 0; i < _lines.Count; i++)
{
if (_lines[i] >= value)
return i;
}

return _lines.Count - 1;
}
}
}
9 changes: 5 additions & 4 deletions LogGrokCore.Data.Tests/LogGrokCore.Data.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
<Nullable>enable</Nullable>
<WarningsAsErrors>NU1605, CS8604, CS8625, CS8602, CS8618, CS8601, CS8603, CS8614, CS8600, CS8610</WarningsAsErrors>
<IsPackable>false</IsPackable>
<TargetFrameworks>net7.0-windows</TargetFrameworks>
<TargetFrameworks>net10.0-windows</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.4.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 4 additions & 4 deletions LogGrokCore.Data.Tests/StringTokenizerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public void SimpleTest()
var source = "a\r\nb";
var tokens = source.Tokenize().ToList();
Assert.AreEqual(2, tokens.Count);
Assert.AreEqual(tokens[0].ToString(), "a");
Assert.AreEqual(tokens[1].ToString(), "b");
Assert.AreEqual("a", tokens[0].ToString());
Assert.AreEqual("b", tokens[1].ToString());
}

[TestMethod]
Expand All @@ -22,7 +22,7 @@ public void TailingCrLf()
var source = "a\r\nb\r\n";
var tokens = source.Tokenize().ToList();
Assert.AreEqual(2, tokens.Count);
Assert.AreEqual(tokens[0].ToString(), "a");
Assert.AreEqual(tokens[1].ToString(), "b");
Assert.AreEqual("a", tokens[0].ToString());
Assert.AreEqual("b", tokens[1].ToString());
}
}
Loading
Loading