Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implement previewing, with the new TSF #17386

Merged
merged 9 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/cascadia/TerminalApp/ActionPreviewHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace winrt::TerminalApp::implementation
{
case ShortcutAction::SetColorScheme:
case ShortcutAction::AdjustOpacity:
case ShortcutAction::SendInput:
{
_RunRestorePreviews();
break;
Expand Down Expand Up @@ -140,6 +141,24 @@ namespace winrt::TerminalApp::implementation
});
}

void TerminalPage::_PreviewSendInput(const Settings::Model::SendInputArgs& args)
{
const auto backup = _restorePreviewFuncs.empty();

_ApplyToActiveControls([&](const auto& control) {
const auto& str{ args.Input() };
control.PreviewInput(str);

if (backup)
{
_restorePreviewFuncs.emplace_back([=]() {
// On dismiss:
control.PreviewInput(L"");
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
});
}
});
}

void TerminalPage::_PreviewAction(const Settings::Model::ActionAndArgs& args)
{
switch (args.Action())
Expand All @@ -150,6 +169,9 @@ namespace winrt::TerminalApp::implementation
case ShortcutAction::AdjustOpacity:
_PreviewAdjustOpacity(args.Args().try_as<AdjustOpacityArgs>());
break;
case ShortcutAction::SendInput:
_PreviewSendInput(args.Args().try_as<SendInputArgs>());
break;
}

// GH#9818 Other ideas for actions that could be preview-able:
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ namespace winrt::TerminalApp::implementation
void _RunRestorePreviews();
void _PreviewColorScheme(const Microsoft::Terminal::Settings::Model::SetColorSchemeArgs& args);
void _PreviewAdjustOpacity(const Microsoft::Terminal::Settings::Model::AdjustOpacityArgs& args);
void _PreviewSendInput(const Microsoft::Terminal::Settings::Model::SendInputArgs& args);

winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs _lastPreviewedAction{ nullptr };
std::vector<std::function<void()>> _restorePreviewFuncs{};
Expand Down
6 changes: 6 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2893,4 +2893,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _clickedOnMark(_contextMenuBufferPosition,
[](const ::MarkExtents& m) -> bool { return !m.HasOutput(); });
}

void ControlCore::PreviewInput(std::wstring_view input)
{
_terminal->PreviewText(input);
}

}
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool ShouldShowSelectCommand();
bool ShouldShowSelectOutput();

void PreviewInput(std::wstring_view input);

RUNTIME_SETTING(float, Opacity, _settings->Opacity());
RUNTIME_SETTING(float, FocusedOpacity, FocusedAppearance().Opacity());
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void TermControl::SendInput(const winrt::hstring& wstr)
{
// Dismiss any previewed input.
PreviewInput(L"");
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved

// only broadcast if there's an actual listener. Saves the overhead of some object creation.
if (StringSent)
{
Expand Down Expand Up @@ -3664,6 +3667,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.OwningHwnd();
}

void TermControl::PreviewInput(const winrt::hstring& text)
{
get_self<ControlCore>(_core)->PreviewInput(text);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
}

void TermControl::AddMark(const Control::ScrollMark& mark)
{
_core.AddMark(mark);
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::Foundation::Size CharacterDimensions() const;
Windows::Foundation::Size MinimumSize();
float SnapDimensionToGrid(const bool widthOrHeight, const float dimension);
void PreviewInput(const winrt::hstring& text);

Windows::Foundation::Point CursorPositionInDips();

Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ namespace Microsoft.Terminal.Control
CommandHistoryContext CommandHistory();

void AdjustOpacity(Single Opacity, Boolean relative);
void PreviewInput(String text);

// You'd think this should just be "Opacity", but UIElement already
// defines an "Opacity", which we're actually not setting at all. We're
Expand Down
51 changes: 51 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,57 @@ til::point Terminal::GetViewportRelativeCursorPosition() const noexcept
return absoluteCursorPosition - viewport.Origin();
}

void Terminal::PreviewText(std::wstring_view input)
{
// Our suggestion text is default-on-default, in italics.
static constexpr TextAttribute previewAttrs{ CharacterAttributes::Italics, TextColor{}, TextColor{}, 0u, TextColor{} };

auto lock = LockForWriting();
if (input.empty())
{
snippetPreview.text = L"";
snippetPreview.attributes.clear();
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
_activeBuffer().NotifyPaintFrame();
return;
}

// When we're previewing suggestions, they might be preceded with DEL
// characters to backspace off the old command.
//
// But also, in the case of something like pwsh, there might be MORE "ghost"
// text in the buffer _after_ the commandline.
//
// We need to trim off the leading DELs, then pad out the rest of the line
// to cover any other ghost text.
std::wstring_view view{ input };
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
// Where do the DELs end?
const auto strBegin = view.find_first_not_of(L"\x7f");
if (strBegin != std::wstring::npos)
{
// Trim them off.
view = view.substr(strBegin);
}
// How many spaces do we need, so that the preview exactly covers the entire
// prompt, all the way to the end of the viewport?
const auto bufferWidth = _GetMutableViewport().Width();
const auto cursorX = _activeBuffer().GetCursor().GetPosition().x;
const auto expectedLenTillEnd = strBegin + (bufferWidth - cursorX);
std::wstring preview{ view };
const auto originalSize{ preview.size() };
if (expectedLenTillEnd > originalSize)
{
// pad it out
preview.insert(originalSize, expectedLenTillEnd - originalSize, L' ');
}
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
snippetPreview.text = til::visualize_nonspace_control_codes(preview);
// Build our composition data
const auto len = snippetPreview.text.size();
snippetPreview.attributes.clear();
snippetPreview.attributes.emplace_back(len, previewAttrs);
snippetPreview.cursorPos = len;
_activeBuffer().NotifyPaintFrame();
}

// These functions are used by TerminalInput, which must build in conhost
// against OneCore compatible signatures. See the definitions in
// VtApiRedirection.hpp (which we cannot include cross-project.)
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ class Microsoft::Terminal::Core::Terminal final :
const size_t GetTaskbarProgress() const noexcept;

void ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode);
void PreviewText(std::wstring_view input);

#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
Expand Down
12 changes: 6 additions & 6 deletions src/renderer/base/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,14 +772,14 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
scratch.CopyFrom(r);
rowBackup = &scratch;

std::wstring_view text{ _pData->activeComposition.text };
std::wstring_view text{ _pData->GetActiveComposition().text };
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
RowWriteState state{
.columnLimit = r.GetReadableColumnCount(),
.columnEnd = _compositionCache->absoluteOrigin.x,
};

size_t off = 0;
for (const auto& range : _pData->activeComposition.attributes)
for (const auto& range : _pData->GetActiveComposition().attributes)
{
const auto len = range.len;
auto attr = range.attr;
Expand Down Expand Up @@ -1225,7 +1225,7 @@ void Renderer::_invalidateOldComposition() const
// so that _PaintBufferOutput() actually gets a chance to draw it.
void Renderer::_prepareNewComposition()
{
if (_pData->activeComposition.text.empty())
if (_pData->GetActiveComposition().text.empty())
{
return;
}
Expand All @@ -1246,16 +1246,16 @@ void Renderer::_prepareNewComposition()
auto& buffer = _pData->GetTextBuffer();
auto& scratch = buffer.GetScratchpadRow();

std::wstring_view text{ _pData->activeComposition.text };
std::wstring_view text{ _pData->GetActiveComposition().text };
RowWriteState state{
.columnLimit = buffer.GetRowByOffset(line.top).GetReadableColumnCount(),
};

state.text = text.substr(0, _pData->activeComposition.cursorPos);
state.text = text.substr(0, _pData->GetActiveComposition().cursorPos);
scratch.ReplaceText(state);
const auto cursorOffset = state.columnEnd;

state.text = text.substr(_pData->activeComposition.cursorPos);
state.text = text.substr(_pData->GetActiveComposition().cursorPos);
state.columnBegin = state.columnEnd;
scratch.ReplaceText(state);

Expand Down
8 changes: 7 additions & 1 deletion src/renderer/inc/IRenderData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ namespace Microsoft::Console::Render
// Ideally this would not be stored on an interface, however ideally IRenderData should not be an interface in the first place.
// This is because we should have only 1 way how to represent render data across the codebase anyway, and it should
// be by-value in a struct so that we can snapshot it and release the terminal lock as quickly as possible.
Composition activeComposition;
const Composition& GetActiveComposition() const noexcept
{
return !snippetPreview.text.empty() ? snippetPreview : tsfPreview;
}

Composition tsfPreview;
Composition snippetPreview;
};
}
6 changes: 3 additions & 3 deletions src/tsf/Implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ void Implementation::Unfocus(IDataProvider* provider)
renderData->UnlockConsole();
});

if (!renderData->activeComposition.text.empty())
if (!renderData->tsfPreview.text.empty())
{
auto& comp = renderData->activeComposition;
auto& comp = renderData->tsfPreview;
comp.text.clear();
comp.attributes.clear();
renderer->NotifyPaintFrame();
Expand Down Expand Up @@ -570,7 +570,7 @@ void Implementation::_doCompositionUpdate(TfEditCookie ec)
renderData->UnlockConsole();
});

auto& comp = renderData->activeComposition;
auto& comp = renderData->tsfPreview;
comp.text = std::move(activeComposition);
comp.attributes = std::move(activeCompositionRanges);
// The code block above that calculates the `cursorPos` will clamp it to a positive number.
Expand Down
Loading