Skip to main content

Migrating to 4.0

One break and one behavior change. The break is namespaces, which the compiler points at and a using fixes; the behavior change is quiet and worth two minutes of reading. Everything else 4.0 added — the localization generator, layouts, dialogs of your own, PaintRow, Notifications.Recent — is new surface an existing application gets without asking.

What changedWhat to do
Four namespaces split into sub-namespacesAdd the sub-namespace to the using the compiler names
A disabled ViewCommand no longer swallows its keyNothing, unless a view relied on the key disappearing
Alt+Esc now arrives as one key rather than two EscapesNothing, unless a view counted on the two

Namespaces follow their folders

Nothing was renamed and nothing was removed. Four namespaces had grown past the point where a name could be found in them by looking, so each was split by what its files are for:

WasNowHolding
Arlecchino.ModalsArlecchino.Modals.AskingTextModal, TextAreaModal, NumberModal, NumericModal, the text interfaces
Arlecchino.Modals.ChoosingChoiceModal, MultiChoiceModal, OptionListModal, CommandModal
Arlecchino.Modals.SettingSliderModal, ToggleModal, ColorModal, DateModal, TimeModal, SegmentedModal
Arlecchino.Modals.TellingMessageModal, NotificationModal
Arlecchino.WidgetsArlecchino.Widgets.ListsListBox<T>, Table<T>, Tree<T>, Tabs, ScrollPane, ScrollBar, ScrollWindow
Arlecchino.Widgets.PicturesPicture
Arlecchino.Widgets.ReadoutsSparkline, BarChart<T>, AreaChart, Gauge, ProgressBar, Spinner, StatusBar, TextView
Arlecchino.RenderingArlecchino.Rendering.ColorsTheme, ThemePalette, TermColor, RgbTermColor, Rgb, TerminalColor, ColorSupport, IArlecchinoColor, TextStyle
Arlecchino.Rendering.TextTextWidth, Joinery, Glyphs, GraphSymbols
Arlecchino.Rendering.TerminalsTerminalProbe, TerminalCapabilities, ImageProtocol
Arlecchino.AtomsArlecchino.Atoms.LocalLocalAtom<T> and the local collections
Arlecchino.Atoms.TrackedTrackedAtom<T> and the tracked collections
Arlecchino.Atoms.CollectionsAtomsList<T>, AtomsMap<K,V>, AtomsSet<T>, AtomsQueue<T>, AtomsStack<T>

A file that draws a list and a chart now imports two namespaces where it imported one:

using Arlecchino.Widgets.Lists;
using Arlecchino.Widgets.Readouts;

What stayed where it was is the vocabulary every file reaches for anyway — Modal and ModalFrame in Arlecchino.Modals, Surface, SurfaceRegion, Margin and Align in Arlecchino.Rendering, Atom and the store interfaces in Arlecchino.Atoms. A using for the parent namespace keeps working for those, which is why most files need one line added rather than one line changed.

tip

There is nothing to think about here. Build, and add the namespace each CS0246 names — the type it cannot find is in the sub-namespace with the matching job. An IDE's "add using" fixes the whole file at once.

A disabled command lets its key through

ViewCommand.IsEnabled used to mean two things at once: grayed out on the key screen, and a key that silently does nothing. The second meaning left a view unable to give the key another job for exactly the times its command is off.

new ViewCommand
{
Binding = new(ConsoleKey.Escape),
Label = () => "stop what is running",
IsEnabled = () => operations.IsBusy,
Run = () => { operations.Cancel(); return ViewRoute.None; },
}

With nothing running, Esc used to disappear. It now reaches the commands available everywhere and then the view's own Handle — to leave a search, to clear a filter, to go back — as if nothing had claimed it.

This is the only change in 4.0 that a compiler cannot point at, so it is worth grepping for IsEnabled and asking of each one whether the key had a second job. An application that wanted the key eaten should bind it and do nothing rather than disable it:

new ViewCommand
{
Binding = new(ConsoleKey.Escape),
Label = () => "stop what is running",
Run = () => { if (operations.IsBusy) { operations.Cancel(); } return ViewRoute.None; },
}

What arrives without being asked for

Nothing here needs an edit; all of it is worth knowing about.

Text can have a name. Drop a TOML file in Localization/, add it to AdditionalFiles, and the generator emits a LocString for every entry and a Loc that resolves it. Existing literals go on working — this is something to move to, a screen at a time. See Localization.

A dialog can be your own. Modal is abstract over Draw(ModalFrame) and Handle(ModalFrame, ConsoleKeyInfo), so a dialog an application writes is a subclass like every dialog the framework brings. Assigning state.Modal = new TextModal { … } is unchanged. See Modals.

A list row can be painted. ListBox<T>.PaintRow draws a row in as many styles as it needs, instead of one string in one style. Render and ItemStyle still work and are still what most lists want. See Lists.

Notifications can be shown as a stack. Notifications.Recent is everything running plus everything that ended recently, newest first, for an application that shows its work as cards rather than one line. See Diagnostics.

Every view can share one frame. UseLayout<T>() draws a band, a bar, or both around every screen, and Surface.Content hands each view the room the layout left it — so an application moves its header out of the views without editing one of them. See Views and navigation.

A key can be named from the localization. The generator writes Bind beside LocString, so Bind.To(new(ConsoleKey.F5), LocString.Copy, files.Copy) replaces the lambda. Existing ViewCommand.For(binding, () => "copy", …) keeps working. See Localization.