Files
terminal/src/cascadia/TerminalApp/MarkdownPaneContent.h
Mike Griese 772f546ac4 Add support for markdown -> XAML parsing (#17585)
This adds support to the Terminal for parsing Markdown to XAML. We're
using https://github.com/github/cmark-gfm as our parser, so that we can
support the fullness of github-flavored markdown.

The parser parses the markdown to produce a `RichTextBlock`, which
covers just about all the scenarios we need. Since we're initially just
targeting using this for "Release notes", I didn't implement
_everything_ in markdown[^1]. But headers, bold & italic, unordered
lists, images, links, code spans & blocks - all that works. We can work
on additional elements as we need them. The parser is encapsulated into
`Microsoft.Terminal.UI.Markdown.dll`, so that we won't load it on
startup, only when the pane is actually made the first time.

To test this out, I've added a `MarkdownPaneContent` pane type on
`x-markdown` (the `x-` is "experimental"). Go ahead and add that with:

```json
{ "command": { "action": "splitPane", "type": "x-markdown" } }
```

That's got the ability to load arbitrary MD files and render them. I
wouldn't call that experience finished though[^2][^3](and it probably
won't be in 1.22 timeframe). However, it is an excellent testbed for
validating what we do and do not support.

We'll use the markdown parser Soon<sup>TM</sup> for the What's New
panes.

* Done in pursuit of displaying release notes in the Terminal.
* Doesn't quite close out #16495 
* Should make #8647 possible
* may help with #16484

[^1]: the most notable gap being "block quotes" with `>`. I don't think
I can draw a vertical line in a rich text block easily. Footnotes are
also missing, as well as tables.
[^2]: I say it's not finished because the aforementioned MD gaps. Also
the UX there is not polished at all.
[^3]: I don't believe we'll have time to polish out the pure markdown
pane for 1.22, but what the parser covers now is more than enough for
the release notes pane in time for 1.22
2024-11-12 10:18:11 -08:00

75 lines
3.1 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "MarkdownPaneContent.g.h"
#include "BasicPaneEvents.h"
namespace winrt::TerminalApp::implementation
{
struct MarkdownPaneContent : MarkdownPaneContentT<MarkdownPaneContent>, BasicPaneEvents
{
public:
MarkdownPaneContent();
MarkdownPaneContent(const winrt::hstring& filePath);
til::property<bool> Editing{ false };
til::property<winrt::hstring> FileContents{ L"" };
void SetLastActiveControl(const Microsoft::Terminal::Control::TermControl& control);
// TODO! this should just be til::property_changed_event but I don't have that commit here
til::event<winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> PropertyChanged;
#pragma region IPaneContent
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings&){};
winrt::Windows::Foundation::Size MinimumSize() { return { 1, 1 }; };
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic) { reason; };
void Close();
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
winrt::hstring Title() { return _filePath; }
uint64_t TaskbarState() { return 0; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept { return nullptr; }
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush() { return Background(); }
// See BasicPaneEvents for most generic event definitions
#pragma endregion
til::typed_event<winrt::Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::ActionAndArgs> DispatchActionRequested;
void _handleRunCommandRequest(const Microsoft::Terminal::UI::Markdown::CodeBlock& sender,
const Microsoft::Terminal::UI::Markdown::RequestRunCommandsArgs& control);
private:
friend struct MarkdownPaneContentT<MarkdownPaneContent>; // for Xaml to bind events
winrt::hstring _filePath{};
winrt::weak_ref<Microsoft::Terminal::Control::TermControl> _control{ nullptr };
void _clearOldNotebook();
void _loadFile();
void _renderFileContents();
void _loadText();
void _loadMarkdown();
void _loadTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
void _editTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
void _closeTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(MarkdownPaneContent);
}