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