Skip to content

Conversation

@DHowett
Copy link
Member

@DHowett DHowett commented Jul 14, 2025

This has been on my list for a while.

HighlightedTextControl is a XAML user control that contains a text
block and takes vector of HighlightedText. HighlightedText uses
tuples (string, boolean). Allocating an entire object to store a
string and an integer felt like a waste, especially when we were doing
it thousands of times for the command palette and just to pass them
into another object that stores a string and a few more integers
(Run).

The new HighlightedTextControl is a standard templated control, and
supports styling of both the inner text block and of the highlighted
runs.

It no longer takes a HighlightedText, but rather a standard string and
a set of runs (tuple (int start, int end)); these can be stored more
efficiently, and this change moves the construction of text and runs
directly into HighlightedTextControl itself as an implementation
detail rather than an API contract.

XAML Properties

  • Text: the string to highlight
  • HighlightedRuns: a vector of (start, end) pairs, indicating which
    regions are intended to be highlighted. Can be empty (which indicates
    there is no highlight and that the entire string is styled normally.)
  • TextBlockStyle: the Style applied to the inner text block;
    optional; allows consumers to change how both normal and highlighted
    text looks.
  • HighlightedRunStyle: a Style applied only to the highlighted runs;
    optional; allows consumers to change how highlighted text looks. If
    left NULL, highlighted runs will be bold.

HighlightedRunStyle is a little bodgy. It only applies to Run
objects (which is fine, and XAML somewhat supports), but since Run is
not a FrameworkElement, it doesn't actually have a Style member.
We need to crack open the style and apply it manually, entry by entry.
FontWeight is special because XAML is a special little flower.

@DHowett DHowett changed the title WIP: Convert HighlightedTextControl to a templated control and do a bunch of other stuff too Rewrite HighlightedTextControl, remove HighlightedText Jul 14, 2025
@DHowett DHowett changed the title Rewrite HighlightedTextControl, remove HighlightedText Rewrite HighlightedTextControl and remove HighlightedText Jul 14, 2025
@DHowett
Copy link
Member Author

DHowett commented Jul 14, 2025

The new TextBlockStyle lets you do this (the subtitle is a second HighlightedTextControl):

image

... and the new HighlightedRunStyle lets you do that (the runs are styled using a style; we actually don't want ugly underlined red, but it proves it works):

image image

/cc @e82eric since he's been working in this space

Copy link
Member Author

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments inline

Documents::Run run;
run.Text(matchSeg);

if (runStyle)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could [[unlikely]] this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry about likely/unlikely too much. It's only a super subtle hint to the optimizer after all.

if (lastPos < text.size())
{
// checking lastPos here prevents a needless deep copy of the whole text in the no-match case
hstring tail{ lastPos == 0 ? text : hstring{ til::safe_slice_abs(text, lastPos, SIZE_T_MAX) } };
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: in general in this file, I should document WHY WE HAVE TEMPORARY HSTRINGS. i had to rediscover it for myself.

HighlightedText Text;
Windows.UI.Xaml.Controls.TextBlock TextView { get; };

IVector<HighlightedRun> HighlightedRuns;
Copy link
Member Author

@DHowett DHowett Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these feel so much better than object pointers, and have much better locality. also no AddRef and Release a jillion times.

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Style TargetType="local:HighlightedTextControl">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we had a good way to roll up XAML resources, this could go down to microsoft.terminal.ui and be used everywhere


<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
HighlightedRuns="{x:Bind FilteredCommand.NameHighlights, Mode=OneWay}"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ergonomically: I don't love that it's two properties, but man it makes the code so much simpler

return winrt::unbox_value<type>(temp); \
} \
\
if constexpr (std::is_same_v<type, winrt::hstring>) \
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is actually necessary because you can't unbox IInspectable nullptr as a hstring without exploding. And we do want the property to be nullable.

This is a strictly better version of the one that lives in TerminalSettingsEditor, and supersedes it, so it can live here.

@github-actions

This comment has been minimized.

Copy link
Member

@carlos-zamora carlos-zamora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big fan of moving the dependency property macro to a shared spot. Happy that we'll be able to use that everywhere now.

Love that we can pass in special styling in the new control. Using the ranges makes sense too! Nice work :)

@DHowett DHowett enabled auto-merge (squash) July 14, 2025 20:24
@DHowett DHowett merged commit 0cbb6b1 into main Jul 14, 2025
17 of 19 checks passed
@DHowett DHowett deleted the dev/duhowett/better-high-text-control branch July 14, 2025 20:40
DHowett added a commit that referenced this pull request Jul 28, 2025
The bulk of this work is changing `Command::Name` (and its descendants
like `GenerateName`) to support looking up names in English and in the
local language.

When matching a "palette item" with a "subtitle" (a new field introduced
to store the English command name when the current language is not
English), the weight of the subtitle is used only if it is greater than
the weight of the name. This ensures that we do not penalize or
over-promote results that contain similar Latin letters in both fields.

Refs #19130, #19131, #19132, #19165
Closes #7039
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants