Scott Hanselman

Dotnet Depends is a great text mode development utility made with Gui.cs

August 02, 2019 Comment on this post [10] Posted in DotNetCore | Open Source
Sponsored By

I love me some text mode. ASCII, ANSI, VT100. Keep your 3D accelerated ray traced graphics and give me a lovely emoji-based progress bar.

Miguel has a nice thing called Gui.cs and I bumped into it in an unexpected and lovely place. There are hundreds of great .NET Global Tools that you can install to make your development lifecycle smoother, and I was installing Martin Björkström's lovely "dotnet depends" tool (go give him a GitHub star now!)  like this:

dotnet tool install -g dotnet-depends

Then I headed over to my Windows Terminal (get it free in the Store) and ran "dotnet depends" on my main website's code and was greeted by this (don't sweat the line spacing, that's a Terminal bug that'll be fixed soon):

dotnet depends in the Windows Terminal

How nice is this! It's a fully featured dependency explorer but it's all in text mode and doesn't require me to use the mouse and take my hands of the keyboard. If I'm already deep into the terminal/text mode, this is a great example of a solid, useful tool.

But how hard was it to make? Surprisingly little as his code is very simple. This is a testament to how he used the API and how Miguel designed it. He's separated the UI and the Business Logic, of course. He does the analysis work and stores it in a graph variable.

Here they're setting up some panes for the (text mode) Windows:


var top = new CustomWindow();

var left = new FrameView("Dependencies")
Width = Dim.Percent(50),
Height = Dim.Fill(1)
var right = new View()
X = Pos.Right(left),
Width = Dim.Fill(),
Height = Dim.Fill(1)

It's split in half at this point, with the left side staying  at 50%.

var orderedDependencyList = graph.Nodes.OrderBy(x => x.Id).ToImmutableList();
var dependenciesView = new ListView(orderedDependencyList)
CanFocus = true,
AllowsMarking = false
var runtimeDependsView = new ListView(Array.Empty<Node>())
CanFocus = true,
AllowsMarking = false
var packageDependsView = new ListView(Array.Empty<Node>())
CanFocus = true,
AllowsMarking = false
var reverseDependsView = new ListView(Array.Empty<Node>())
CanFocus = true,
AllowsMarking = false

right.Add(runtimeDepends, packageDepends, reverseDepends);
top.Add(left, right, helpText);

The right side gets three ListViews added to it and the left side gets the dependencies view. Top it off with some clean data binding to the views and an initial call to UpdateLists. Anytime the dependenciesView gets a SelectedChanged event we'll call UpdateLists again.

top.Dependencies = orderedDependencyList;
top.VisibleDependencies = orderedDependencyList;
top.DependenciesView = dependenciesView;

dependenciesView.SelectedItem = 0;

dependenciesView.SelectedChanged += UpdateLists;


What's in update lists? Filtering code for that graph variable from before.

void UpdateLists()
var selectedNode = top.VisibleDependencies[dependenciesView.SelectedItem];

runtimeDependsView.SetSource(graph.Edges.Where(x => x.Start.Equals(selectedNode) && x.End is AssemblyReferenceNode)
.Select(x => x.End).ToImmutableList());
packageDependsView.SetSource(graph.Edges.Where(x => x.Start.Equals(selectedNode) && x.End is PackageReferenceNode)
.Select(x => $"{x.End}{(string.IsNullOrEmpty(x.Label) ? string.Empty : " (Wanted: " + x.Label + ")")}").ToImmutableList());
reverseDependsView.SetSource(graph.Edges.Where(x => x.End.Equals(selectedNode))
.Select(x => $"{x.Start}{(string.IsNullOrEmpty(x.Label) ? string.Empty : " (Wanted: " + x.Label + ")")}").ToImmutableList());

That's basically it and it's fast as heck. Probably to be expected from the folks that brought you Midnight Commander.

Are you working on any utilities or cool projects and might want to consider - gasp - text mode over a website?

Sponsor: Looking for a tool for performance profiling, unit test coverage, and continuous testing that works cross-platform on Windows, macOS, and Linux? Check out the latest JetBrains Rider!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
August 06, 2019 10:50
This is like Unix curses. There's a JS lib called blessed offering similar functionality. Blessed has an issue on Windows though because they can't get mouse support working. Does the new Windows Terminal (and Gui.cs) have support for mouse input? Would be great to use the mouse wheel to scroll on those panes.
August 06, 2019 16:12
Great post. Gui is a nice project. I used it to create a dotnet tool (lazy) to handle solutions that deals with multiple git repositories.
August 06, 2019 23:54
Nice post Scott! Any chance you can create blog post on how to use this via Powershell for us Windows Sysadmin's in the crowd? :) I would love to make a TUI application in PS, since I am not a C# guy.
August 07, 2019 2:02
Looks like Miguel rediscovered Turbo Vision from ~2000.

August 07, 2019 10:58
Nice. Reminds me of the type of programs I used to make in Turbo Pascal :)
August 07, 2019 13:13
I like consoleframework. It's a Turvo Vision clone with support for XAML and mouse.

<a href=""""></a>

August 07, 2019 14:14
Nice tool, but wow the colors. The text is all but unreadable - light text on a light colored background?

Anyway to change it?
August 07, 2019 20:39
But does it work the same on Mac and/or linux?
August 08, 2019 21:01
I've been tinkering with a Powershell keyboard driven box-menu. It works pretty well so far, other than the tricky math on the scroll thumb for oversized lists.

┌─Select with spacebar─┐
│√first │
│ second │
│√third │
August 08, 2019 21:26
Thank you so much for sharing an information about the text mode development.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.