-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite how marks are stored & add reflow (#16937)
This is pretty much a huge refactoring of how marks are stored in the buffer. Gone is the list of `ScrollMark`s in the buffer that store regions of text as points marking the ends. Those would be nigh impossible to reflow nicely. Instead, we're going to use `TextAttribute`s to store the kind of output we've got - `Prompt`, `Command`, `Output`, or, the default, `None`. Those already reflow nicely! But we also need to store things like, the exit code for the command. That's why we've now added `ScrollbarData` to `ROW`s. There's really only going to be one prompt->output on a single row. So, we only need to store one ScrollbarData per-row. When a command ends, we can just go update the mark on the row that started that command. But iterating over the whole buffer to find the next/previous prompt/command/output region sounds complicated. So, to avoid everyone needing to do some variant of that, we've added `MarkExtents` (which is literally just the same mark structure as before). TextBuffer can figure out where all the mark regions are, and hand that back to callers. This allows ControlCore to be basically unchanged. _But collecting up all the regions for all the marks sounds expensive! We need to update the scrollbar frequently, we can't just collect those up every time!_ No we can't! But we also don't need to. The scrollbar doesn't need to know where all the marks start and end and if they have commands and this and that - no. We only need to know the rows that have marks on them. So, we've now also got `ScrollMark` to represent just a mark on a scrollbar at a specific row on the buffer. We can get those quickly. * [x] I added a bunch of tests for this. * [x] I played with it and it feels good, even after a reflow (finally) * See: * #11000 * #15057 (I'm not marking this as closed. The stacked PR will close this, when I move marks to Stable)
- Loading branch information
1 parent
dc4026d
commit c3f44f7
Showing
28 changed files
with
1,628 additions
and
496 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/*++ | ||
Copyright (c) Microsoft Corporation | ||
Licensed under the MIT license. | ||
Module Name: | ||
- marks.hpp | ||
Abstract: | ||
- Definitions for types that are used for "scroll marks" and shell integration | ||
in the buffer. | ||
- Scroll marks are identified by the existence of "ScrollbarData" on a ROW in the buffer. | ||
- Shell integration will then also markup the buffer with special | ||
TextAttributes, to identify regions of text as the Prompt, the Command, the | ||
Output, etc. | ||
- MarkExtents are used to abstract away those regions of text, so a caller | ||
doesn't need to iterate over the buffer themselves. | ||
--*/ | ||
|
||
#pragma once | ||
|
||
enum class MarkCategory : uint8_t | ||
{ | ||
Default = 0, | ||
Error = 1, | ||
Warning = 2, | ||
Success = 3, | ||
Prompt = 4 | ||
}; | ||
|
||
// This is the data that's stored on each ROW, to suggest that there's something | ||
// interesting on this row to show in the scrollbar. Also used in conjunction | ||
// with shell integration - when a prompt is added through shell integration, | ||
// we'll also add a scrollbar mark as a quick "bookmark" to the start of that | ||
// command. | ||
struct ScrollbarData | ||
{ | ||
MarkCategory category{ MarkCategory::Default }; | ||
|
||
// Scrollbar marks may have been given a color, or not. | ||
std::optional<til::color> color; | ||
|
||
// Prompts without an exit code haven't had a matching FTCS CommandEnd | ||
// called yet. Any value other than 0 is an error. | ||
std::optional<uint32_t> exitCode; | ||
// Future consideration: stick the literal command as a string on here, if | ||
// we were given it with the 633;E sequence. | ||
}; | ||
|
||
// Helper struct for describing the bounds of a command and it's output, | ||
// * The Prompt is between the start & end | ||
// * The Command is between the end & commandEnd | ||
// * The Output is between the commandEnd & outputEnd | ||
// | ||
// These are not actually stored in the buffer. The buffer can produce them for | ||
// callers, to make reasoning about regions of the buffer easier. | ||
struct MarkExtents | ||
{ | ||
// Data from the row | ||
ScrollbarData data; | ||
|
||
til::point start; | ||
til::point end; // exclusive | ||
std::optional<til::point> commandEnd; | ||
std::optional<til::point> outputEnd; | ||
|
||
// MarkCategory category{ MarkCategory::Info }; | ||
// Other things we may want to think about in the future are listed in | ||
// GH#11000 | ||
|
||
bool HasCommand() const noexcept | ||
{ | ||
return commandEnd.has_value() && *commandEnd != end; | ||
} | ||
bool HasOutput() const noexcept | ||
{ | ||
return outputEnd.has_value() && *outputEnd != *commandEnd; | ||
} | ||
std::pair<til::point, til::point> GetExtent() const | ||
{ | ||
til::point realEnd{ til::coalesce_value(outputEnd, commandEnd, end) }; | ||
return std::make_pair(start, realEnd); | ||
} | ||
}; | ||
|
||
// Another helper, for when callers would like to know just about the data of | ||
// the scrollbar, but don't actually need all the extents of prompts. | ||
struct ScrollMark | ||
{ | ||
til::CoordType row{ 0 }; | ||
ScrollbarData data; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.