mirror of
https://github.com/microsoft/terminal.git
synced 2026-02-04 05:35:20 +00:00
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
This commit is contained in:
2
.github/actions/spelling/allow/allow.txt
vendored
2
.github/actions/spelling/allow/allow.txt
vendored
@@ -5,6 +5,7 @@ breadcrumbs
|
||||
ccmp
|
||||
ccon
|
||||
clickable
|
||||
cmark
|
||||
CMMI
|
||||
colorbrewer
|
||||
consvc
|
||||
@@ -22,6 +23,7 @@ Emacspeak
|
||||
Fitt
|
||||
FTCS
|
||||
gantt
|
||||
gfm
|
||||
ghe
|
||||
gje
|
||||
godbolt
|
||||
|
||||
5
.github/actions/spelling/allow/apis.txt
vendored
5
.github/actions/spelling/allow/apis.txt
vendored
@@ -43,6 +43,7 @@ DONTADDTORECENT
|
||||
DWMSBT
|
||||
DWMWA
|
||||
DWORDLONG
|
||||
EMPH
|
||||
endfor
|
||||
ENDSESSION
|
||||
enumset
|
||||
@@ -62,6 +63,7 @@ GETDESKWALLPAPER
|
||||
GETHIGHCONTRAST
|
||||
GETMOUSEHOVERTIME
|
||||
GETTEXTLENGTH
|
||||
HARDBREAKS
|
||||
Hashtable
|
||||
HIGHCONTRASTON
|
||||
HIGHCONTRASTW
|
||||
@@ -115,6 +117,7 @@ IUri
|
||||
IVirtual
|
||||
KEYSELECT
|
||||
LCID
|
||||
LINEBREAK
|
||||
llabs
|
||||
llu
|
||||
localtime
|
||||
@@ -148,6 +151,7 @@ NIF
|
||||
NIN
|
||||
NOAGGREGATION
|
||||
NOASYNC
|
||||
NOBREAKS
|
||||
NOCHANGEDIR
|
||||
NOPROGRESS
|
||||
NOREDIRECTIONBITMAP
|
||||
@@ -204,6 +208,7 @@ SINGLEUSE
|
||||
SIZENS
|
||||
smoothstep
|
||||
snprintf
|
||||
SOFTBREAK
|
||||
spsc
|
||||
sregex
|
||||
SRWLOC
|
||||
|
||||
1
.github/actions/spelling/excludes.txt
vendored
1
.github/actions/spelling/excludes.txt
vendored
@@ -104,6 +104,7 @@
|
||||
^doc/reference/UTF8-torture-test\.txt$
|
||||
^doc/reference/windows-terminal-logo\.ans$
|
||||
^oss/
|
||||
^NOTICE.md
|
||||
^samples/PixelShaders/Screenshots/
|
||||
^src/interactivity/onecore/BgfxEngine\.
|
||||
^src/renderer/atlas/
|
||||
|
||||
175
NOTICE.md
175
NOTICE.md
@@ -281,6 +281,181 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
```
|
||||
|
||||
## cmark
|
||||
**Source**: [https://github.com/commonmark/cmark](https://github.com/commonmark/cmark)
|
||||
|
||||
### License
|
||||
Copyright (c) 2014, John MacFarlane
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-----
|
||||
|
||||
houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c
|
||||
|
||||
derive from https://github.com/vmg/houdini (with some modifications)
|
||||
|
||||
Copyright (C) 2012 Vicent Martí
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
buffer.h, buffer.c, chunk.h
|
||||
|
||||
are derived from code (C) 2012 Github, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
utf8.c and utf8.c
|
||||
|
||||
are derived from utf8proc
|
||||
(<http://www.public-software-group.org/utf8proc>),
|
||||
(C) 2009 Public Software Group e. V., Berlin, Germany.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
The normalization code in normalize.py was derived from the
|
||||
markdowntest project, Copyright 2013 Karl Dubost:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Karl Dubost
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
The CommonMark spec (test/spec.txt) is
|
||||
|
||||
Copyright (C) 2014-15 John MacFarlane
|
||||
|
||||
Released under the Creative Commons CC-BY-SA 4.0 license:
|
||||
<http://creativecommons.org/licenses/by-sa/4.0/>.
|
||||
|
||||
-----
|
||||
|
||||
The test software in test/ is
|
||||
|
||||
Copyright (c) 2014, John MacFarlane
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Microsoft Open Source
|
||||
|
||||
This product also incorporates source code from other Microsoft open source projects, all licensed under the MIT license.
|
||||
|
||||
@@ -405,6 +405,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenderingTests", "src\tools
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "src\cascadia\UIHelpers\UIHelpers.vcxproj", "{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI.Markdown", "src\cascadia\UIMarkdown\UIMarkdown.vcxproj", "{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchcat", "src\tools\benchcat\benchcat.vcxproj", "{2C836962-9543-4CE5-B834-D28E1F124B66}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleMonitor", "src\tools\ConsoleMonitor\ConsoleMonitor.vcxproj", "{328729E9-6723-416E-9C98-951F1473BBE1}"
|
||||
@@ -2302,6 +2304,28 @@ Global
|
||||
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x64.Build.0 = Release|x64
|
||||
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32
|
||||
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.Build.0 = Release|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|Any CPU.ActiveCfg = Debug|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x64.Build.0 = Debug|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x86.Build.0 = Debug|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x64.ActiveCfg = Release|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x64.Build.0 = Release|x64
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x86.Build.0 = Release|Win32
|
||||
{2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
@@ -2455,6 +2479,7 @@ Global
|
||||
{613CCB57-5FA9-48EF-80D0-6B1E319E20C4} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{37C995E0-2349-4154-8E77-4A52C0C7F46D} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C}
|
||||
{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C}
|
||||
{2C836962-9543-4CE5-B834-D28E1F124B66} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{328729E9-6723-416E-9C98-951F1473BBE1} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
{BE92101C-04F8-48DA-99F0-E1F4F1D2DC48} = {A10C4720-DCA4-4640-9749-67F4314F527C}
|
||||
|
||||
202
src/cascadia/TerminalApp/MarkdownPaneContent.cpp
Normal file
202
src/cascadia/TerminalApp/MarkdownPaneContent.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "MarkdownPaneContent.h"
|
||||
#include <LibraryResources.h>
|
||||
#include "MarkdownPaneContent.g.cpp"
|
||||
#include <til/io.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
|
||||
MarkdownPaneContent::MarkdownPaneContent() :
|
||||
MarkdownPaneContent(L"") {}
|
||||
|
||||
MarkdownPaneContent::MarkdownPaneContent(const winrt::hstring& initialPath)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
FilePathInput().Text(initialPath);
|
||||
_filePath = FilePathInput().Text();
|
||||
_loadFile();
|
||||
}
|
||||
|
||||
INewContentArgs MarkdownPaneContent::GetNewTerminalArgs(BuildStartupKind /*kind*/) const
|
||||
{
|
||||
return BaseContentArgs(L"x-markdown");
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::_clearOldNotebook()
|
||||
{
|
||||
RenderedMarkdown().Children().Clear();
|
||||
}
|
||||
void MarkdownPaneContent::_loadFile()
|
||||
{
|
||||
if (_filePath.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Our title is the path of our MD file
|
||||
TitleChanged.raise(*this, nullptr);
|
||||
|
||||
const std::filesystem::path filePath{ std::wstring_view{ _filePath } };
|
||||
const auto markdownContents{ til::io::read_file_as_utf8_string_if_exists(filePath) };
|
||||
|
||||
Editing(false);
|
||||
PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"Editing" });
|
||||
FileContents(winrt::to_hstring(markdownContents));
|
||||
PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"FileContents" });
|
||||
|
||||
_renderFileContents();
|
||||
}
|
||||
void MarkdownPaneContent::_renderFileContents()
|
||||
{
|
||||
// Was the file a .md file?
|
||||
if (_filePath.ends_with(L".md"))
|
||||
{
|
||||
_loadMarkdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
_loadText();
|
||||
}
|
||||
}
|
||||
void MarkdownPaneContent::_loadText()
|
||||
{
|
||||
auto block = WUX::Controls::TextBlock();
|
||||
block.IsTextSelectionEnabled(true);
|
||||
block.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" });
|
||||
block.Text(FileContents());
|
||||
|
||||
RenderedMarkdown().Children().Append(block);
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::_loadMarkdown()
|
||||
{
|
||||
auto rootTextBlock{ Microsoft::Terminal::UI::Markdown::Builder::Convert(FileContents(), _filePath) };
|
||||
|
||||
// By default, the markdown pane doesn't have play buttons next to the
|
||||
// blocks. But to demonstrate how that's possible:
|
||||
for (const auto& b : rootTextBlock.Blocks())
|
||||
{
|
||||
if (const auto& p{ b.try_as<WUX::Documents::Paragraph>() })
|
||||
{
|
||||
for (const auto& line : p.Inlines())
|
||||
{
|
||||
if (const auto& otherContent{ line.try_as<WUX::Documents::InlineUIContainer>() })
|
||||
{
|
||||
if (const auto& codeBlock{ otherContent.Child().try_as<Microsoft::Terminal::UI::Markdown::CodeBlock>() })
|
||||
{
|
||||
codeBlock.PlayButtonVisibility(WUX::Visibility::Visible);
|
||||
codeBlock.RequestRunCommands({ this, &MarkdownPaneContent::_handleRunCommandRequest });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderedMarkdown().Children().Append(rootTextBlock);
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::_loadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
|
||||
{
|
||||
_filePath = FilePathInput().Text();
|
||||
// Does the file exist? if not, bail
|
||||
const wil::unique_handle file{ CreateFileW(_filePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
|
||||
if (!file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// It does. Clear the old one
|
||||
_clearOldNotebook();
|
||||
_loadFile();
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::_editTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
|
||||
{
|
||||
if (Editing())
|
||||
{
|
||||
_clearOldNotebook();
|
||||
_renderFileContents();
|
||||
|
||||
EditIcon().Glyph(L"\xe932"); // Label
|
||||
|
||||
_scrollViewer().Visibility(WUX::Visibility::Visible);
|
||||
_editor().Visibility(WUX::Visibility::Collapsed);
|
||||
|
||||
Editing(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditIcon().Glyph(L"\xe890"); // View
|
||||
|
||||
_scrollViewer().Visibility(WUX::Visibility::Collapsed);
|
||||
_editor().Visibility(WUX::Visibility::Visible);
|
||||
|
||||
Editing(true);
|
||||
}
|
||||
PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"Editing" });
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::_closeTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
|
||||
{
|
||||
CloseRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::_handleRunCommandRequest(const Microsoft::Terminal::UI::Markdown::CodeBlock& /*sender*/,
|
||||
const Microsoft::Terminal::UI::Markdown::RequestRunCommandsArgs& request)
|
||||
{
|
||||
auto text = request.Commandlines();
|
||||
|
||||
if (const auto& strongControl{ _control.get() })
|
||||
{
|
||||
Model::ActionAndArgs actionAndArgs{ ShortcutAction::SendInput, Model::SendInputArgs{ text } };
|
||||
|
||||
// By using the last active control as the sender here, the
|
||||
// action dispatch will send this to the active control,
|
||||
// thinking that it is the control that requested this event.
|
||||
DispatchActionRequested.raise(strongControl, actionAndArgs);
|
||||
strongControl.Focus(winrt::WUX::FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region IPaneContent
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement MarkdownPaneContent::GetRoot()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MarkdownPaneContent::Close()
|
||||
{
|
||||
CloseRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
winrt::hstring MarkdownPaneContent::Icon() const
|
||||
{
|
||||
static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote
|
||||
return winrt::hstring{ glyph };
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void MarkdownPaneContent::SetLastActiveControl(const Microsoft::Terminal::Control::TermControl& control)
|
||||
{
|
||||
_control = control;
|
||||
}
|
||||
}
|
||||
74
src/cascadia/TerminalApp/MarkdownPaneContent.h
Normal file
74
src/cascadia/TerminalApp/MarkdownPaneContent.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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);
|
||||
}
|
||||
24
src/cascadia/TerminalApp/MarkdownPaneContent.idl
Normal file
24
src/cascadia/TerminalApp/MarkdownPaneContent.idl
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "IPaneContent.idl";
|
||||
import "FilteredCommand.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass MarkdownPaneContent : Windows.UI.Xaml.Controls.UserControl,
|
||||
IPaneContent,
|
||||
Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
MarkdownPaneContent();
|
||||
MarkdownPaneContent(String originalPath);
|
||||
void SetLastActiveControl(Microsoft.Terminal.Control.TermControl control);
|
||||
|
||||
Boolean Editing;
|
||||
String FileContents;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.ActionAndArgs> DispatchActionRequested;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
129
src/cascadia/TerminalApp/MarkdownPaneContent.xaml
Normal file
129
src/cascadia/TerminalApp/MarkdownPaneContent.xaml
Normal file
@@ -0,0 +1,129 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="TerminalApp.MarkdownPaneContent"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<!-- same as in MainPage, this is SolidBackgroundFillColorTertiary -->
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="PageBackground">#282828</Color>
|
||||
<Color x:Key="PlayButtonHoveredColor">#90ef90</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#8888</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="PageBackground">#F9F9F9</Color>
|
||||
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#88222222</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<!-- Define resources for HighContrast mode here -->
|
||||
<StaticResource x:Key="PageBackground"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="Root"
|
||||
Background="{ThemeResource PageBackground}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="FilePathInput"
|
||||
Grid.Column="0"
|
||||
Margin="4"
|
||||
PlaceholderText="Enter a path to a markdown file..."
|
||||
Text="Z:\dev\simple-test.md" />
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<Button Margin="4"
|
||||
Tapped="_loadTapped">
|
||||
<FontIcon FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<!-- OpenFile -->
|
||||
</Button>
|
||||
<Button Margin="4"
|
||||
Tapped="_editTapped">
|
||||
<FontIcon x:Name="EditIcon"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<!-- Label -->
|
||||
</Button>
|
||||
<Button Margin="4"
|
||||
Tapped="_closeTapped">
|
||||
<FontIcon FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<!-- ChromeClose -->
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="TabContent"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid x:Name="InProcContent"
|
||||
Grid.Column="0"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#ff0000" />
|
||||
|
||||
<TextBox x:Name="_editor"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AcceptsReturn="True"
|
||||
FontFamily="Cascadia Code"
|
||||
IsSpellCheckEnabled="False"
|
||||
Text="{x:Bind FileContents, Mode=TwoWay}"
|
||||
Visibility="{x:Bind Editing}" />
|
||||
|
||||
<ScrollViewer x:Name="_scrollViewer"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
BringIntoViewOnFocusChange="True"
|
||||
IsVerticalScrollChainingEnabled="True">
|
||||
<StackPanel x:Name="RenderedMarkdown"
|
||||
Grid.Column="1"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
Orientation="Vertical" />
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -206,6 +206,10 @@
|
||||
<!-- Define resources for HighContrast mode here -->
|
||||
<StaticResource x:Key="PageBackground"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="PlayButtonHoveredColor"
|
||||
ResourceKey="SystemColorHighlightColor" />
|
||||
<StaticResource x:Key="PlayButtonNormalColor"
|
||||
ResourceKey="SystemColorHighlightColor" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
<Page Include="SnippetsPaneContent.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="MarkdownPaneContent.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -178,6 +181,9 @@
|
||||
<ClInclude Include="SuggestionsControl.h">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MarkdownPaneContent.h">
|
||||
<DependentUpon>MarkdownPaneContent.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowsPackageManagerFactory.h" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
@@ -296,6 +302,11 @@
|
||||
<ClCompile Include="SuggestionsControl.cpp">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MarkdownPaneContent.cpp">
|
||||
<DependentUpon>MarkdownPaneContent.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -368,6 +379,10 @@
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="TerminalSettingsCache.idl" />
|
||||
<Midl Include="MarkdownPaneContent.idl">
|
||||
<DependentUpon>MarkdownPaneContent.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -416,6 +431,11 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\UIHelpers\UIHelpers.vcxproj">
|
||||
<Project>{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\UIMarkdown\UIMarkdown.vcxproj">
|
||||
<Project>{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}</Project>
|
||||
<Private>true</Private>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
@@ -459,6 +479,12 @@
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.UI.Markdown">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)Microsoft.Terminal.UI.Markdown\Microsoft.Terminal.UI.Markdown.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="$(WindowsSDK_MetadataPathVersioned)\Windows.UI.Xaml.Hosting.HostingContract\*\*.winmd">
|
||||
<WinMDFile>true</WinMDFile>
|
||||
<CopyLocal>false</CopyLocal>
|
||||
@@ -504,4 +530,4 @@
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "SettingsPaneContent.h"
|
||||
#include "ScratchpadContent.h"
|
||||
#include "SnippetsPaneContent.h"
|
||||
#include "MarkdownPaneContent.h"
|
||||
#include "TabRowControl.h"
|
||||
|
||||
#include "TerminalPage.g.cpp"
|
||||
@@ -3438,6 +3439,30 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
content = *tasksContent;
|
||||
}
|
||||
else if (paneType == L"x-markdown")
|
||||
{
|
||||
if (Feature_MarkdownPane::IsEnabled())
|
||||
{
|
||||
const auto& markdownContent{ winrt::make_self<MarkdownPaneContent>(L"") };
|
||||
markdownContent->UpdateSettings(_settings);
|
||||
markdownContent->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler });
|
||||
|
||||
// This one doesn't use DispatchCommand, because we don't create
|
||||
// Command's freely at runtime like we do with just plain old actions.
|
||||
markdownContent->DispatchActionRequested([weak = get_weak()](const auto& sender, const auto& actionAndArgs) {
|
||||
if (const auto& page{ weak.get() })
|
||||
{
|
||||
page->_actionDispatch->DoAction(sender, actionAndArgs);
|
||||
}
|
||||
});
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
markdownContent->SetLastActiveControl(termControl);
|
||||
}
|
||||
|
||||
content = *markdownContent;
|
||||
}
|
||||
}
|
||||
|
||||
assert(content);
|
||||
|
||||
|
||||
@@ -1235,6 +1235,10 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
taskPane.SetLastActiveControl(termControl);
|
||||
}
|
||||
else if (const auto& taskPane{ p->GetContent().try_as<MarkdownPaneContent>() })
|
||||
{
|
||||
taskPane.SetLastActiveControl(termControl);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\dll\TerminalControl.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsModel\dll\Microsoft.Terminal.Settings.Model.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\UIMarkdown\UIMarkdown.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\UIHelpers\UIHelpers.vcxproj">
|
||||
<Project>{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
#include <winrt/Microsoft.Terminal.Settings.Editor.h>
|
||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
||||
#include <winrt/Microsoft.Terminal.UI.h>
|
||||
#include <winrt/Microsoft.Terminal.UI.Markdown.h>
|
||||
|
||||
#include <winrt/Windows.Services.Store.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.Storage.Provider.h>
|
||||
|
||||
15
src/cascadia/UIMarkdown/Builder.cpp
Normal file
15
src/cascadia/UIMarkdown/Builder.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "pch.h"
|
||||
#include "Builder.h"
|
||||
#include "Builder.g.cpp"
|
||||
|
||||
#include "MarkdownToXaml.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::Markdown::implementation
|
||||
{
|
||||
winrt::Windows::UI::Xaml::Controls::RichTextBlock Builder::Convert(const winrt::hstring& text,
|
||||
const winrt::hstring& baseUrl)
|
||||
{
|
||||
const auto u8String{ til::u16u8(text) };
|
||||
return MarkdownToXaml::Convert(u8String, baseUrl);
|
||||
}
|
||||
}
|
||||
19
src/cascadia/UIMarkdown/Builder.h
Normal file
19
src/cascadia/UIMarkdown/Builder.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Builder.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::Markdown::implementation
|
||||
{
|
||||
struct Builder
|
||||
{
|
||||
static winrt::Windows::UI::Xaml::Controls::RichTextBlock Convert(const winrt::hstring& text, const winrt::hstring& baseUrl);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::Markdown::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(Builder);
|
||||
}
|
||||
11
src/cascadia/UIMarkdown/Builder.idl
Normal file
11
src/cascadia/UIMarkdown/Builder.idl
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.UI.Markdown
|
||||
{
|
||||
static runtimeclass Builder
|
||||
{
|
||||
static Windows.UI.Xaml.Controls.RichTextBlock Convert(String text, String baseUrl);
|
||||
};
|
||||
|
||||
}
|
||||
31
src/cascadia/UIMarkdown/CodeBlock.cpp
Normal file
31
src/cascadia/UIMarkdown/CodeBlock.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "CodeBlock.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "CodeBlock.g.cpp"
|
||||
#include "RequestRunCommandsArgs.g.cpp"
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::Markdown::implementation
|
||||
{
|
||||
CodeBlock::CodeBlock(const winrt::hstring& initialCommandlines) :
|
||||
Commandlines(initialCommandlines)
|
||||
{
|
||||
}
|
||||
void CodeBlock::_playPressed(const Windows::Foundation::IInspectable&,
|
||||
const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e)
|
||||
{
|
||||
auto args = winrt::make_self<RequestRunCommandsArgs>(Commandlines());
|
||||
RequestRunCommands.raise(*this, *args);
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
43
src/cascadia/UIMarkdown/CodeBlock.h
Normal file
43
src/cascadia/UIMarkdown/CodeBlock.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CodeBlock.g.h"
|
||||
#include "RequestRunCommandsArgs.g.h"
|
||||
#include "../../../src/cascadia/inc/cppwinrt_utils.h"
|
||||
#include <til/hash.h>
|
||||
#include <til/winrt.h>
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::Markdown::implementation
|
||||
{
|
||||
struct CodeBlock : CodeBlockT<CodeBlock>
|
||||
{
|
||||
CodeBlock(const winrt::hstring& initialCommandlines);
|
||||
|
||||
til::property<winrt::hstring> Commandlines;
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
til::typed_event<Microsoft::Terminal::UI::Markdown::CodeBlock, RequestRunCommandsArgs> RequestRunCommands;
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Visibility, PlayButtonVisibility, PropertyChanged.raise, Windows::UI::Xaml::Visibility::Collapsed);
|
||||
|
||||
private:
|
||||
friend struct CodeBlockT<CodeBlock>; // for Xaml to bind events
|
||||
|
||||
void _playPressed(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
|
||||
};
|
||||
|
||||
struct RequestRunCommandsArgs : RequestRunCommandsArgsT<RequestRunCommandsArgs>
|
||||
{
|
||||
RequestRunCommandsArgs(const winrt::hstring& commandlines) :
|
||||
Commandlines{ commandlines } {};
|
||||
|
||||
til::property<winrt::hstring> Commandlines;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::Markdown::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(CodeBlock);
|
||||
}
|
||||
22
src/cascadia/UIMarkdown/CodeBlock.idl
Normal file
22
src/cascadia/UIMarkdown/CodeBlock.idl
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.UI.Markdown
|
||||
{
|
||||
runtimeclass RequestRunCommandsArgs
|
||||
{
|
||||
String Commandlines { get;};
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass CodeBlock : Windows.UI.Xaml.Controls.UserControl,
|
||||
Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
CodeBlock(String initialCommandlines);
|
||||
|
||||
String Commandlines { get; set; };
|
||||
Windows.UI.Xaml.Visibility PlayButtonVisibility { get; set; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<CodeBlock, RequestRunCommandsArgs> RequestRunCommands;
|
||||
};
|
||||
|
||||
}
|
||||
210
src/cascadia/UIMarkdown/CodeBlock.xaml
Normal file
210
src/cascadia/UIMarkdown/CodeBlock.xaml
Normal file
@@ -0,0 +1,210 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="Microsoft.Terminal.UI.Markdown.CodeBlock"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.Terminal.UI.Markdown"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="256"
|
||||
d:DesignWidth="1024"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="BlockBackgroundColor">#1e1e1e</Color>
|
||||
<Color x:Key="BlockBorderColor">#30363d</Color>
|
||||
<Color x:Key="PlayButtonHoveredColor">#90ef90</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#88888888</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="BlockBackgroundColor">#f6f8fa</Color>
|
||||
<Color x:Key="BlockBorderColor">#d3d3d3</Color>
|
||||
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#88222222</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="BlockBackgroundColor"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="BlockBorderColor"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="PlayButtonHoveredColor"
|
||||
ResourceKey="SystemColorHighlightColor" />
|
||||
<StaticResource x:Key="PlayButtonNormalColor"
|
||||
ResourceKey="SystemColorHighlightColor" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
|
||||
<Style x:Key="PlayButtonTemplate"
|
||||
TargetType="Button">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="4" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="ButtonBaseElement"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Viewbox Width="20"
|
||||
Height="20">
|
||||
<Grid>
|
||||
<FontIcon x:Name="ButtonBackgroundIcon"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Foreground="{ThemeResource PlayButtonHoveredColor}"
|
||||
Glyph=""
|
||||
Visibility="Collapsed" />
|
||||
<FontIcon x:Name="ButtonOutlineIcon"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Foreground="{ThemeResource PlayButtonNormalColor}"
|
||||
Glyph="" />
|
||||
<muxc:ProgressRing x:Name="StatusProgress"
|
||||
IsActive="False" />
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
|
||||
<VisualState x:Name="Normal">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
|
||||
<VisualState x:Name="Disabled" />
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="PlayButtonStates">
|
||||
<VisualState x:Name="Ready">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<Setter Target="StatusProgress.IsActive" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Running">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value=" " />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value=" " />
|
||||
<Setter Target="StatusProgress.IsActive" Value="True" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="AlreadyRan">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<Setter Target="StatusProgress.IsActive" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
</Style>
|
||||
<Style x:Key="CodeBlockLineTemplate"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Cascadia Mono, Consolas" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button x:Name="RunButton"
|
||||
Grid.Column="0"
|
||||
Margin="0,9,0,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Top"
|
||||
Style="{StaticResource PlayButtonTemplate}"
|
||||
Tapped="_playPressed"
|
||||
Visibility="{x:Bind PlayButtonVisibility, Mode=OneWay}">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="{ThemeResource SystemColorButtonFaceColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
<Border Grid.Column="1"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{ThemeResource BlockBackgroundColor}"
|
||||
BorderBrush="{ThemeResource BlockBorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<ScrollViewer HorizontalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
HorizontalScrollMode="Auto">
|
||||
<Grid x:Name="CommandsAndOutput"
|
||||
Margin="14"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<TextBlock FontFamily="Cascadia Mono, Consolas"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind Commandlines}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
469
src/cascadia/UIMarkdown/MarkdownToXaml.cpp
Normal file
469
src/cascadia/UIMarkdown/MarkdownToXaml.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "CodeBlock.h"
|
||||
#include "MarkdownToXaml.h"
|
||||
|
||||
#include <cmark.h>
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
}
|
||||
using namespace winrt;
|
||||
|
||||
// Bullet points used for unordered lists.
|
||||
static constexpr std::wstring_view bullets[]{
|
||||
L"• ",
|
||||
L"◦ ",
|
||||
L"▪ " // After this level, we'll keep using this one.
|
||||
};
|
||||
static constexpr int WidthOfBulletPoint{ 9 };
|
||||
static constexpr int IndentWidth{ 3 * WidthOfBulletPoint };
|
||||
static constexpr int H1FontSize{ 36 };
|
||||
static constexpr int HeaderMinFontSize{ 16 };
|
||||
|
||||
static constexpr std::wstring_view CodeFontFamily{ L"Cascadia Mono, Consolas" };
|
||||
|
||||
template<typename T>
|
||||
static std::string_view textFromCmarkString(const T& s) noexcept
|
||||
{
|
||||
return std::string_view{ (char*)s.data, (size_t)s.len };
|
||||
}
|
||||
static std::string_view textFromLiteral(cmark_node* node) noexcept
|
||||
{
|
||||
return cmark_node_get_literal(node);
|
||||
}
|
||||
static std::string_view textFromUrl(cmark_node* node) noexcept
|
||||
{
|
||||
return cmark_node_get_url(node);
|
||||
}
|
||||
|
||||
typedef wil::unique_any<cmark_node*, decltype(&cmark_node_free), cmark_node_free> unique_node;
|
||||
typedef wil::unique_any<cmark_iter*, decltype(&cmark_iter_free), cmark_iter_free> unique_iter;
|
||||
|
||||
// Function Description:
|
||||
// - Entrypoint to convert a string of markdown into a XAML RichTextBlock.
|
||||
// Arguments:
|
||||
// - markdownText: the markdown content to render
|
||||
// - baseUrl: the current URI of the content. This will allow for relative links
|
||||
// to be appropriately resolved.
|
||||
// Return Value:
|
||||
// - a RichTextBlock with the rendered markdown in it.
|
||||
WUX::Controls::RichTextBlock MarkdownToXaml::Convert(std::string_view markdownText, const winrt::hstring& baseUrl)
|
||||
{
|
||||
MarkdownToXaml data{ baseUrl };
|
||||
|
||||
unique_node doc{ cmark_parse_document(markdownText.data(), markdownText.size(), CMARK_OPT_DEFAULT) };
|
||||
unique_iter iter{ cmark_iter_new(doc.get()) };
|
||||
cmark_event_type ev_type;
|
||||
|
||||
while ((ev_type = cmark_iter_next(iter.get())) != CMARK_EVENT_DONE)
|
||||
{
|
||||
data._RenderNode(cmark_iter_get_node(iter.get()), ev_type);
|
||||
}
|
||||
|
||||
return data._root;
|
||||
}
|
||||
|
||||
MarkdownToXaml::MarkdownToXaml(const winrt::hstring& baseUrl) :
|
||||
_baseUri{ baseUrl }
|
||||
{
|
||||
_root.IsTextSelectionEnabled(true);
|
||||
_root.TextWrapping(WUX::TextWrapping::WrapWholeWords);
|
||||
}
|
||||
|
||||
WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
|
||||
{
|
||||
if (_lastParagraph == nullptr)
|
||||
{
|
||||
_lastParagraph = WUX::Documents::Paragraph{};
|
||||
if (_indent > 0)
|
||||
{
|
||||
// If we're in a list, we will start this paragraph with a bullet
|
||||
// point. That bullet point will be added as part of the actual text
|
||||
// of the paragraph, but we want the real text of the paragraph all
|
||||
// aligned. So we will _de-indent_ the first line, to give us space
|
||||
// for the bullet.
|
||||
if (_indent - _blockQuoteDepth > 0)
|
||||
{
|
||||
_lastParagraph.TextIndent(-WidthOfBulletPoint);
|
||||
}
|
||||
_lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(IndentWidth * _indent, 0, 0, 0));
|
||||
}
|
||||
_root.Blocks().Append(_lastParagraph);
|
||||
}
|
||||
return _lastParagraph;
|
||||
}
|
||||
WUX::Documents::Run MarkdownToXaml::_CurrentRun()
|
||||
{
|
||||
if (_lastRun == nullptr)
|
||||
{
|
||||
_lastRun = WUX::Documents::Run{};
|
||||
_CurrentSpan().Inlines().Append(_lastRun);
|
||||
}
|
||||
return _lastRun;
|
||||
}
|
||||
WUX::Documents::Span MarkdownToXaml::_CurrentSpan()
|
||||
{
|
||||
if (_lastSpan == nullptr)
|
||||
{
|
||||
_lastSpan = WUX::Documents::Span{};
|
||||
_CurrentParagraph().Inlines().Append(_lastSpan);
|
||||
}
|
||||
return _lastSpan;
|
||||
}
|
||||
WUX::Documents::Run MarkdownToXaml::_NewRun()
|
||||
{
|
||||
if (_lastRun == nullptr)
|
||||
{
|
||||
return _CurrentRun();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto old{ _lastRun };
|
||||
|
||||
WUX::Documents::Run newRun{};
|
||||
|
||||
newRun.FontFamily(old.FontFamily());
|
||||
newRun.FontWeight(old.FontWeight());
|
||||
newRun.FontStyle(old.FontStyle());
|
||||
|
||||
_lastRun = newRun;
|
||||
_CurrentSpan().Inlines().Append(_lastRun);
|
||||
}
|
||||
return _lastRun;
|
||||
}
|
||||
void MarkdownToXaml::_EndRun()
|
||||
{
|
||||
_lastRun = nullptr;
|
||||
}
|
||||
void MarkdownToXaml::_EndSpan()
|
||||
{
|
||||
_EndRun();
|
||||
_lastSpan = nullptr;
|
||||
}
|
||||
void MarkdownToXaml::_EndParagraph()
|
||||
{
|
||||
_EndSpan();
|
||||
_lastParagraph = nullptr;
|
||||
}
|
||||
|
||||
WUX::Controls::TextBlock MarkdownToXaml::_makeDefaultTextBlock()
|
||||
{
|
||||
WUX::Controls::TextBlock b{};
|
||||
b.IsTextSelectionEnabled(true);
|
||||
b.TextWrapping(WUX::TextWrapping::WrapWholeWords);
|
||||
return b;
|
||||
}
|
||||
|
||||
void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
|
||||
{
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
|
||||
switch (cmark_node_get_type(node))
|
||||
{
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
|
||||
// It's non-trivial to deal with the right-side vertical lines that
|
||||
// we're accustomed to seeing for block quotes in markdown content.
|
||||
// RichTextBlock doesn't have a good way of adding a border to a
|
||||
// paragraph, it would seem.
|
||||
//
|
||||
// We could add a InlineUIContainer, with a Border in there, then
|
||||
// put a new RichTextBlock in there, but I believe text selection
|
||||
// wouldn't transit across the border.
|
||||
|
||||
// Instead, we're just going to add a new layer of indenting.
|
||||
|
||||
if (entering)
|
||||
{
|
||||
_EndParagraph();
|
||||
_indent++;
|
||||
_blockQuoteDepth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_EndParagraph();
|
||||
_indent = std::max(0, _indent - 1);
|
||||
_blockQuoteDepth = std::max(0, _blockQuoteDepth - 1);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LIST:
|
||||
{
|
||||
// when `node->as.list.list_type == CMARK_BULLET_LIST`, we're an unordered list.
|
||||
// Otherwise, we're an ordered one (and we might not start at 0).
|
||||
//
|
||||
// However, we don't support numbered lists for now.
|
||||
if (entering)
|
||||
{
|
||||
_EndParagraph();
|
||||
_indent++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_EndParagraph();
|
||||
_indent = std::max(0, _indent - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMARK_NODE_ITEM:
|
||||
// A list item, either for a ordered list or an unordered one.
|
||||
if (entering)
|
||||
{
|
||||
_EndParagraph();
|
||||
_NewRun().Text(bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)]);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HEADING:
|
||||
{
|
||||
_EndParagraph();
|
||||
|
||||
// At the start of a header, change the font size to match the new
|
||||
// level of header we're at. The text will come later, in a
|
||||
// CMARK_NODE_TEXT
|
||||
if (entering)
|
||||
{
|
||||
// Insert a blank line, just to help break up the walls of text.
|
||||
// This better reflects the way MD is rendered to HTML
|
||||
_root.Blocks().Append(WUX::Documents::Paragraph{});
|
||||
|
||||
const auto level = cmark_node_get_heading_level(node);
|
||||
_CurrentParagraph().FontSize(std::max(HeaderMinFontSize, H1FontSize - level * 6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
{
|
||||
_EndParagraph();
|
||||
|
||||
const auto codeHstring{ winrt::to_hstring(cmark_node_get_literal(node)) };
|
||||
// The literal for a code node always includes the trailing newline.
|
||||
// Trim that off.
|
||||
std::wstring_view codeView{ codeHstring.c_str(), codeHstring.size() - 1 };
|
||||
|
||||
auto codeBlock = winrt::make<winrt::Microsoft::Terminal::UI::Markdown::implementation::CodeBlock>(winrt::hstring{ codeView });
|
||||
WUX::Documents::InlineUIContainer codeContainer{};
|
||||
codeContainer.Child(codeBlock);
|
||||
_CurrentParagraph().Inlines().Append(codeContainer);
|
||||
|
||||
_EndParagraph();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML_BLOCK:
|
||||
// Raw HTML comes to us in the literal
|
||||
// node->as.literal.data, node->as.literal.len
|
||||
// But we don't support raw HTML, so we'll do nothing.
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CUSTOM_BLOCK:
|
||||
// Not even entirely sure what this is.
|
||||
break;
|
||||
|
||||
case CMARK_NODE_THEMATIC_BREAK:
|
||||
// A <hr>. Not currently supported.
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
{
|
||||
bool tight;
|
||||
cmark_node* parent = cmark_node_parent(node);
|
||||
cmark_node* grandparent = cmark_node_parent(parent);
|
||||
|
||||
if (grandparent != NULL && cmark_node_get_type(grandparent))
|
||||
{
|
||||
tight = cmark_node_get_list_tight(grandparent);
|
||||
}
|
||||
else
|
||||
{
|
||||
tight = false;
|
||||
}
|
||||
|
||||
// If we aren't in a list, then end the current paragraph and
|
||||
// start a new one.
|
||||
if (!tight)
|
||||
{
|
||||
_EndParagraph();
|
||||
}
|
||||
|
||||
// Start a new paragraph if we don't have one
|
||||
break;
|
||||
}
|
||||
case CMARK_NODE_TEXT:
|
||||
{
|
||||
const auto text{ winrt::to_hstring(textFromLiteral(node)) };
|
||||
|
||||
if (_lastImage)
|
||||
{
|
||||
// The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here.
|
||||
WUX::Controls::ToolTipService::SetToolTip(_lastImage, box_value(text));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, just add the text to the current paragraph
|
||||
_NewRun().Text(text);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
_EndSpan();
|
||||
_CurrentParagraph().Inlines().Append(WUX::Documents::LineBreak());
|
||||
break;
|
||||
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
// I'm fairly confident this is what happens when you've just got
|
||||
// two lines only separated by a single \r\n in a MD doc. E.g. when
|
||||
// you want a paragraph to wrap at 80 columns in code, but wrap in
|
||||
// the rendered document.
|
||||
//
|
||||
// In the HTML implementation, what happens here depends on the options:
|
||||
// * CMARK_OPT_HARDBREAKS: add a full line break
|
||||
// * CMARK_OPT_NOBREAKS: Just add a space
|
||||
// * otherwise, just add a '\n'
|
||||
//
|
||||
// We're not really messing with options here, so lets just add a
|
||||
// space. That seems to keep the current line going, but allow for
|
||||
// word breaking.
|
||||
|
||||
_NewRun().Text(L" ");
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE:
|
||||
{
|
||||
const auto text{ winrt::to_hstring(textFromLiteral(node)) };
|
||||
const auto& codeRun{ _NewRun() };
|
||||
|
||||
codeRun.FontFamily(WUX::Media::FontFamily{ CodeFontFamily });
|
||||
// A Span can't have a border or a background, so we can't give
|
||||
// it the whole treatment that a <code> span gets in HTML.
|
||||
codeRun.Text(text);
|
||||
|
||||
_NewRun().FontFamily(_root.FontFamily());
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML_INLINE:
|
||||
// Same as above - no raw HTML support here.
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CUSTOM_INLINE:
|
||||
// Same as above - not even entirely sure what this is.
|
||||
break;
|
||||
|
||||
case CMARK_NODE_STRONG:
|
||||
_NewRun().FontWeight(entering ?
|
||||
winrt::Windows::UI::Text::FontWeights::Bold() :
|
||||
winrt::Windows::UI::Text::FontWeights::Normal());
|
||||
break;
|
||||
|
||||
case CMARK_NODE_EMPH:
|
||||
_NewRun().FontStyle(entering ?
|
||||
winrt::Windows::UI::Text::FontStyle::Italic :
|
||||
winrt::Windows::UI::Text::FontStyle::Normal);
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINK:
|
||||
|
||||
if (entering)
|
||||
{
|
||||
const auto urlHstring{ to_hstring(textFromUrl(node)) };
|
||||
WUX::Documents::Hyperlink a{};
|
||||
|
||||
// Set the tooltip to display the URL
|
||||
try
|
||||
{
|
||||
// This block is from TermControl.cpp, where we sanitize the
|
||||
// tooltips for URLs. That has a much more comprehensive
|
||||
// comment.
|
||||
|
||||
const winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring };
|
||||
|
||||
a.NavigateUri(uri);
|
||||
|
||||
auto tooltipText = urlHstring;
|
||||
const auto unicode = uri.AbsoluteUri();
|
||||
const auto punycode = uri.AbsoluteCanonicalUri();
|
||||
if (punycode != unicode)
|
||||
{
|
||||
tooltipText = winrt::hstring{ punycode + L"\n" + unicode };
|
||||
}
|
||||
WUX::Controls::ToolTipService::SetToolTip(a, box_value(tooltipText));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
_CurrentParagraph().Inlines().Append(a);
|
||||
_lastSpan = a;
|
||||
|
||||
// Similar to the header element, the actual text of the link
|
||||
// will later come through as a CMARK_NODE_TEXT
|
||||
}
|
||||
else
|
||||
{
|
||||
_EndSpan();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_IMAGE:
|
||||
if (entering)
|
||||
{
|
||||
const auto urlHstring{ to_hstring(textFromUrl(node)) };
|
||||
|
||||
try
|
||||
{
|
||||
winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring };
|
||||
|
||||
WUX::Media::Imaging::BitmapImage bitmapImage;
|
||||
bitmapImage.UriSource(uri);
|
||||
|
||||
WUX::Controls::Image img{};
|
||||
img.Source(bitmapImage);
|
||||
|
||||
WUX::Documents::InlineUIContainer imageBlock{};
|
||||
imageBlock.Child(img);
|
||||
|
||||
_CurrentParagraph().Inlines().Append(imageBlock);
|
||||
_lastImage = img;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_EndSpan();
|
||||
_lastImage = nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
// These elements are in cmark-gfm, which we'd love to move to in the
|
||||
// future, but isn't yet available in vcpkg.
|
||||
|
||||
// case CMARK_NODE_FOOTNOTE_DEFINITION:
|
||||
// // Not supported currently
|
||||
// break;
|
||||
//
|
||||
// case CMARK_NODE_FOOTNOTE_REFERENCE:
|
||||
// // Not supported currently
|
||||
// break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
37
src/cascadia/UIMarkdown/MarkdownToXaml.h
Normal file
37
src/cascadia/UIMarkdown/MarkdownToXaml.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include <cmark.h>
|
||||
|
||||
struct MarkdownToXaml
|
||||
{
|
||||
public:
|
||||
static winrt::Windows::UI::Xaml::Controls::RichTextBlock Convert(std::string_view markdownText, const winrt::hstring& baseUrl);
|
||||
|
||||
private:
|
||||
MarkdownToXaml(const winrt::hstring& baseUrl);
|
||||
|
||||
winrt::hstring _baseUri{ L"" };
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{};
|
||||
winrt::Windows::UI::Xaml::Documents::Run _lastRun{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Documents::Span _lastSpan{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Documents::Paragraph _lastParagraph{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Controls::Image _lastImage{ nullptr };
|
||||
|
||||
int _indent = 0;
|
||||
int _blockQuoteDepth = 0;
|
||||
|
||||
winrt::Windows::UI::Xaml::Documents::Paragraph _CurrentParagraph();
|
||||
winrt::Windows::UI::Xaml::Documents::Run _CurrentRun();
|
||||
winrt::Windows::UI::Xaml::Documents::Span _CurrentSpan();
|
||||
winrt::Windows::UI::Xaml::Documents::Run _NewRun();
|
||||
void _EndRun();
|
||||
void _EndSpan();
|
||||
void _EndParagraph();
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::TextBlock _makeDefaultTextBlock();
|
||||
|
||||
void _RenderNode(cmark_node* node, cmark_event_type ev_type);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
87
src/cascadia/UIMarkdown/UIMarkdown.vcxproj
Normal file
87
src/cascadia/UIMarkdown/UIMarkdown.vcxproj
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}</ProjectGuid>
|
||||
<ProjectName>Microsoft.Terminal.UI.Markdown</ProjectName>
|
||||
<RootNamespace>Microsoft.Terminal.UI.Markdown</RootNamespace>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
|
||||
<!-- C++/WinRT sets the depth to 1 if there is a XAML file in the project
|
||||
Unfortunately for us, we need it to be 4. When the namespace merging
|
||||
depth is 1, Microsoft.Terminal.UI.Markdown becomes "Microsoft",
|
||||
and our WinMD file becomes "Microsoft". Because WinRT is very
|
||||
namespace-driven, this winmd is considered to contain the entire
|
||||
Microsoft namespace. This is, obviously, not great. None of our other
|
||||
projects compile properly when they depend on this "Microsoft.winmd."
|
||||
-->
|
||||
<CppWinRTNamespaceMergeDepth>4</CppWinRTNamespaceMergeDepth>
|
||||
<XamlComponentResourceLocation>nested</XamlComponentResourceLocation>
|
||||
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Builder.h">
|
||||
<DependentUpon>Builder.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MarkdownToXaml.h" />
|
||||
<ClInclude Include="CodeBlock.h">
|
||||
<DependentUpon>CodeBlock.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="init.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Builder.cpp">
|
||||
<DependentUpon>Builder.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CodeBlock.cpp">
|
||||
<DependentUpon>CodeBlock.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MarkdownToXaml.cpp" />
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="Builder.idl" />
|
||||
<Midl Include="CodeBlock.idl">
|
||||
<DependentUpon>CodeBlock.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="CodeBlock.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<!--
|
||||
the packaging project won't recurse through our dependencies, you have to
|
||||
make sure that if you add a cppwinrt dependency to any of these projects,
|
||||
you also update all the consumers
|
||||
-->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj">
|
||||
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
|
||||
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
</Project>
|
||||
38
src/cascadia/UIMarkdown/UIMarkdown.vcxproj.filters
Normal file
38
src/cascadia/UIMarkdown/UIMarkdown.vcxproj.filters
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resources\en-US">
|
||||
<UniqueIdentifier>{ee3ff32f-d013-49cb-8eb9-1ec084585086}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Module">
|
||||
<UniqueIdentifier>{091e7617-c506-4742-82fc-75e7ca32e2fe}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="init.cpp">
|
||||
<Filter>Module</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp">
|
||||
<Filter>Module</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Module</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="Builder.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
21
src/cascadia/UIMarkdown/init.cpp
Normal file
21
src/cascadia/UIMarkdown/init.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#pragma warning(suppress : 26440) // Not interested in changing the specification of DllMain to make it noexcept given it's an interface to the OS.
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID /*reserved*/)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstDll);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
4
src/cascadia/UIMarkdown/pch.cpp
Normal file
4
src/cascadia/UIMarkdown/pch.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
47
src/cascadia/UIMarkdown/pch.h
Normal file
47
src/cascadia/UIMarkdown/pch.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// pch.h
|
||||
// Header for platform projection include files
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#define BLOCK_TIL
|
||||
#include <LibraryIncludes.h>
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
// SDK definition of this function, so the only fix is to undef it.
|
||||
// from WinBase.h
|
||||
// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <wil/cppwinrt.h>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
#include <winrt/Windows.UI.Text.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Markup.h>
|
||||
#include <winrt/Windows.UI.Xaml.Media.h>
|
||||
#include <winrt/Windows.UI.Xaml.Media.Imaging.h>
|
||||
#include <winrt/Windows.UI.Xaml.Documents.h>
|
||||
#include <winrt/Windows.UI.Xaml.Input.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
|
||||
#include <cppwinrt_utils.h>
|
||||
#include <wil/cppwinrt_helpers.h> // must go after the CoreDispatcher type is defined
|
||||
@@ -91,6 +91,7 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalApp\dll\TerminalApp.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\Remoting\dll\Microsoft.Terminal.Remoting.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\UIMarkdown\UIMarkdown.vcxproj" />
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
|
||||
|
||||
@@ -145,6 +145,17 @@
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_MarkdownPane</name>
|
||||
<description>Allow the user to create markdown panes. Experimental, to validate markdown parsing.</description>
|
||||
<id>16495</id>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
<brandingToken>Canary</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_KeypadModeEnabled</name>
|
||||
<description>Enables the DECKPAM, DECKPNM sequences to work as intended </description>
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"description": "Components required for Windows Terminal; separated out to make the Windows conhost build work",
|
||||
"dependencies": [
|
||||
"jsoncpp",
|
||||
"cli11"
|
||||
"cli11",
|
||||
"cmark"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -29,6 +30,10 @@
|
||||
{
|
||||
"name": "cli11",
|
||||
"version": "2.4.2"
|
||||
},
|
||||
{
|
||||
"name": "cmark",
|
||||
"version": "0.30.3"
|
||||
}
|
||||
],
|
||||
"builtin-baseline": "fe1cde61e971d53c9687cf9a46308f8f55da19fa"
|
||||
|
||||
Reference in New Issue
Block a user