Windows Text Viewer in D
Adam D. Ruppe
destructionator at gmail.com
Sat Apr 11 14:17:40 UTC 2026
On Saturday, 11 April 2026 at 07:46:19 UTC, Paul wrote:
> The goal is to view log files from embedded controllers.
> Filtering and coloring lines based on user regex expressions is
> the long term goal.
I have code that can do this with text, but you might want to
consider alternatives like a table view or list view. If you can
put the logs into structure beyond strings, presenting that
structure to the user as a table might be beneficial so you can
let them sort, filter, etc based on cell contents rather than
just regexs. Think about it as a spreadsheet or database query
result.
With my code, the main difference would be the text is something
you can click and drag to select across lines, but all has to be
loaded up front, whereas a table thing can be lazy loaded but the
user can only interact one item at a time. (also my specific
impl's rich text thing is based on custom code, and table is
based on a win32 api control, so there's some quality of
implementation differences between them)
Really, I think you'd be best off trying to get each log entry
into a struct of some sort just to ensure it is normalized from
the different input formats, then you can display that however
you want.
But going just with strings..... here's something of mine
```
import arsd.minigui;
import arsd.textlayouter;
import std.string;
class LogViewer : EditableTextWidget {
this(Widget parent) {
super(true /* force custom */, parent);
}
// for our highlight to be used later
string searching;
// boilerplate for custom widget appearance (unnecessary but
here for demo purposes)
static class Style : EditableTextWidget.Style {
override WidgetBackground background() {
return
WidgetBackground(WidgetPainter.visualTheme.widgetBackgroundColor);
}
override Color foregroundColor() {
return WidgetPainter.visualTheme.foregroundColor;
}
override OperatingSystemFont font() {
// change the font to whatever you want
return new OperatingSystemFont("monospace", 11);
}
}
mixin OverrideStyle!Style;
// boilerplate to enable custom text styles, some important
stuff is in here
override TextDisplayHelper textDisplayHelperFactory(TextLayouter
textLayout, ScrollMessageWidget smw) {
return new MyTextDisplayHelper(this, textLayout, smw);
}
static class MyTextDisplayHelper : TextDisplayHelper {
this(LogViewer lv, TextLayouter textLayout, ScrollMessageWidget
smw) {
this.lv = lv;
super(textLayout, smw);
this.readonly = true;
}
LogViewer lv;
/+
A text segment in this library is any one-line string that it
thinks has the
same style. Note that when the user highlights some text, it
will break the
segment around the highlight, but still might be the easiest
way to do inline
searches. Otherwise, you'd need to do different TextStyles to
make your own
segments and the api to do that is unfinished lol.
+/
override void drawTextSegment(MyTextStyle ignoredGenericStyle,
WidgetPainter painter, Point upperLeft, scope const(char)[] text)
{
if(lv.searching.length && text.indexOf(lv.searching) != -1) {
// this line matched the search, draw a special background
around it
// a subpainter lets us modify color and then return to
previous
// settings automatically when it goes out of scope
auto subpainter = painter;
subpainter.outlineColor = Color.yellow;
subpainter.fillColor = Color.yellow;
subpainter.drawRectangle(upperLeft,
subpainter.textSize(text));
}
painter.drawText(upperLeft, text);
}
}
}
void main() {
auto window = new MainWindow;
auto lv = new LogViewer(window);
import std.file;
// load your actual file here instead
lv.content = readText("/var/log/Xorg.0.log");
struct Commands {
@menu("View") {
void Search(string what) @accelerator("Ctrl+F") {
lv.searching = what;
lv.redraw();
}
}
}
Commands commands;
window.setMenuAndToolbarFromAnnotatedCode(commands);
window.loop();
}
```
Is it amazing? No, my custom text display has all kinds of minor
bugs still, I'm slowly working them out. But does it work? Sort
of....
Should compile with out of the box `opend logviewer` or if you
use dub these libs are `arsd-official:minigui` and
`arsd-official:textlayouter` .... i think. i haven't updated them
for a while.
On Windows, should all work the same except maybe changing the
font from monospace to Courier New or similar.
but there's a looooooooooooooooong way to go from this to
something legitimately useful to you i think so idk if it even
really helps. Every time you sort, filter, etc, you'd reload the
`lv.content` string with the newly sorted/filtered string. So
like doable but not wonderful.
More information about the Digitalmars-d-learn
mailing list