From fccd3c0fa85bdffc7f484bd9add62c069241e12d Mon Sep 17 00:00:00 2001 From: Ilya Biryukov Date: Wed, 30 May 2018 09:20:37 -0700 Subject: [PATCH] Add TerminalRenderer API --- .../ITerminalRenderer.cs | 56 +++++++++++ .../ITerminalRendererService.cs | 25 +++++ .../BrowserBridge/RendererScriptingObject.cs | 49 ++++++++++ .../BrowserBridge/TerminalScriptingObject.cs | 64 ++---------- .../TerminalScriptingObjectBase.cs | 43 ++++++++ .../BrowserBridge/TerminalTheme.cs | 7 ++ .../BrowserBridge/TerminalThemer.cs | 1 + .../Microsoft.VisualStudio.Terminal.csproj | 21 +++- .../RendererToolWindow.cs | 27 ++++++ .../RendererToolWindowControl.xaml | 15 +++ .../RendererToolWindowControl.xaml.cs | 72 ++++++++++++++ .../TermWindowPackage.cs | 46 ++++++--- .../VsService/EmbeddedTerminal.cs | 97 +------------------ .../VsService/EmbeddedTerminalService.cs | 40 ++++++-- .../VsService/TerminalRenderer.cs | 72 ++++++++++++++ .../VsService/TerminalWindow.cs | 93 ++++++++++++++++++ .../WebView/ts/TermView.ts | 70 ++++++++++++- .../WebView/ts/TerminalFit.d.ts | 11 +++ .../WebView/ts/VsEventManager.ts | 3 +- .../packages.config | 2 +- package-lock.json | 3 + 21 files changed, 635 insertions(+), 182 deletions(-) create mode 100644 Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRenderer.cs create mode 100644 Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRendererService.cs create mode 100644 Microsoft.VisualStudio.Terminal/BrowserBridge/RendererScriptingObject.cs create mode 100644 Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObjectBase.cs create mode 100644 Microsoft.VisualStudio.Terminal/RendererToolWindow.cs create mode 100644 Microsoft.VisualStudio.Terminal/RendererToolWindowControl.xaml create mode 100644 Microsoft.VisualStudio.Terminal/RendererToolWindowControl.xaml.cs create mode 100644 Microsoft.VisualStudio.Terminal/VsService/TerminalRenderer.cs create mode 100644 Microsoft.VisualStudio.Terminal/VsService/TerminalWindow.cs create mode 100644 Microsoft.VisualStudio.Terminal/WebView/ts/TerminalFit.d.ts create mode 100644 package-lock.json diff --git a/Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRenderer.cs b/Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRenderer.cs new file mode 100644 index 0000000..c22ecf0 --- /dev/null +++ b/Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRenderer.cs @@ -0,0 +1,56 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.VisualStudio.Terminal +{ + public delegate void TerminalDataRecievedEventHandler(object sender, string data); + + /// + /// Terminal renderer. + /// The terminal starts in auto-fit mode where terminal size always matches the window size when window resizes. + /// After a first call to ResizeAsyc(), the terminal switches to fixed size mode where the terminal size stays + /// fixed and doesn't change when the window size changes. In this mode the terminal size can only be changed + /// with ResizeAsync(). To show the terminal inside the window, a dotted border will be displayed + /// on the bottom and right sides of it. + /// If the terminal window gets smaller than the terminal, some parts of the terminal may get clipped from view. + /// + [ComImport, Guid("150B7535-03F9-41C0-9515-17ECB8199FFE")] + public interface ITerminalRenderer : ITerminal + { + /// + /// Gets current cols of the terminal window. + /// + int Cols { get; } + + /// + /// Gets current rows of the terminal window. + /// + int Rows { get; } + + /// + /// Changes the size of the terminal. + /// After that the terminal size may not match the terminal window size. + /// Rows and Cols always match the terminal window, and may differ from the terminal size + /// after ResizeAsync is called. + /// CallingResizeAsync doesn't cause TerminalResized event. + /// + Task ResizeAsync(int cols, int rows, CancellationToken cancellationToken); + + /// + /// An event that is fired when the terminal window is resized and either Rows or Cols have changed. + /// + event EventHandler TerminalResized; + + /// + /// An event that is fired when user input is recieved. + /// + event TerminalDataRecievedEventHandler TerminalDataRecieved; + + /// + /// Sends data to the terminal making it render the data. + /// + Task PtyDataAsync(string data, CancellationToken cancellationToken); + } +} diff --git a/Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRendererService.cs b/Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRendererService.cs new file mode 100644 index 0000000..95fb8a3 --- /dev/null +++ b/Microsoft.VisualStudio.Terminal.Embeddable/ITerminalRendererService.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace Microsoft.VisualStudio.Terminal +{ + [ComImport, Guid("250301DA-0BEA-4C4E-B199-C363C7C164B2")] + public interface ITerminalRendererService + { + /// + /// Create a new terminal renderer instance with the given name that fits the window. + /// + /// The name that will be displayed as the tool window title. + /// An instance of ITerminalRenderer + Task CreateTerminalRendererAsync(string name); + + /// + /// Create a new terminal renderer instance with the given name and dimensions. + /// The terminal size won't change when user resizes the window. + /// + /// The name that will be displayed as the tool window title. + /// An instance of ITerminalRenderer + Task CreateTerminalRendererAsync(string name, int cols, int rows); + } +} diff --git a/Microsoft.VisualStudio.Terminal/BrowserBridge/RendererScriptingObject.cs b/Microsoft.VisualStudio.Terminal/BrowserBridge/RendererScriptingObject.cs new file mode 100644 index 0000000..dac1593 --- /dev/null +++ b/Microsoft.VisualStudio.Terminal/BrowserBridge/RendererScriptingObject.cs @@ -0,0 +1,49 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +namespace Microsoft.VisualStudio.Terminal +{ + [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + [ComVisible(true)] + public class RendererScriptingObject : TerminalScriptingObjectBase + { + internal RendererScriptingObject(TermWindowPackage package) : base(package) + { + } + + internal EventHandler TermDataRecieved { get; set; } + + internal EventHandler TermInit { get; set; } + + internal EventHandler TermResized { get; set; } + + + public override void ClosePty() + { + // There is already Closed event that is fired by the TerminalWindow + } + + public override void InitPty(int cols, int rows, string directory) => TermInit?.Invoke(this, EventArgs.Empty); + + public override void ResizePty(int cols, int rows) => TermResized?.Invoke(this, new ResizeEventArgs(cols, rows)); + + public override void TermData(string data) => TermDataRecieved?.Invoke(this, data); + + public override string GetSolutionDir() => null; + } + + [DebuggerStepThrough] + public class ResizeEventArgs : EventArgs + { + public ResizeEventArgs(int cols, int rows) + { + Cols = cols; + Rows = rows; + } + + public int Cols { get; } + public int Rows { get; } + } +} diff --git a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObject.cs b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObject.cs index b106dc2..5b4ee82 100644 --- a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObject.cs +++ b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObject.cs @@ -4,15 +4,13 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Security.Permissions; -using System.Windows; namespace Microsoft.VisualStudio.Terminal { [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] [ComVisible(true)] - public class TerminalScriptingObject : ITerminalScriptingObject + public class TerminalScriptingObject : TerminalScriptingObjectBase { - private readonly TermWindowPackage package; private readonly JsonRpc ptyService; private readonly SolutionUtils solutionUtils; private readonly string workingDirectory; @@ -29,9 +27,8 @@ internal TerminalScriptingObject( bool useSolutionDir, string shellPath, IEnumerable args, - IDictionary env) + IDictionary env) : base(package) { - this.package = package; this.ptyService = ptyService; this.solutionUtils = solutionUtils; this.workingDirectory = workingDirectory; @@ -41,22 +38,7 @@ internal TerminalScriptingObject( this.env = env; } - public string GetTheme() - { - return TerminalThemer.GetTheme(); - } - - public string GetFontFamily() - { - return this.package.OptionFontFamily; - } - - public int GetFontSize() - { - return this.package.OptionFontSize; - } - - public string GetSolutionDir() + public override string GetSolutionDir() { if (!this.useSolutionDir) { @@ -71,32 +53,9 @@ public string GetSolutionDir() return solutionDir; } - public void ClosePty() - { - this.ptyService.InvokeAsync("closeTerm"); - } - - public void CopyStringToClipboard(string stringToCopy) - { - Clipboard.SetText(stringToCopy ?? ""); - } - - public string GetClipboard() - { - return Clipboard.GetText(); - } - - public string GetLinkRegex() - { - return TerminalRegex.LocalLinkRegex.ToString(); - } - - public void HandleLocalLink(string uri) - { - TerminalRegex.HandleLocalLink(uri); - } + public override void ClosePty() => this.ptyService.InvokeAsync("closeTerm"); - public void InitPty(int cols, int rows, string directory) + public override void InitPty(int cols, int rows, string directory) { string configuredShellPath; if (this.package.OptionTerminal == DefaultTerminal.Other) @@ -111,19 +70,10 @@ public void InitPty(int cols, int rows, string directory) this.ptyService.InvokeAsync("initTerm", this.shellPath ?? configuredShellPath, cols, rows, directory, ((object)this.args) ?? this.package.OptionStartupArgument, env).FileAndForget("WhackWhackTerminal/InitPty"); } - public void ResizePty(int cols, int rows) - { + public override void ResizePty(int cols, int rows) => this.ptyService.InvokeAsync("resizeTerm", cols, rows).FileAndForget("WhackWhackTerminal/ResizePty"); - } - public void TermData(string data) - { + public override void TermData(string data) => this.ptyService.InvokeAsync("termData", data).FileAndForget("WhackWhackTerminal/TermData"); - } - - public bool ValidateLocalLink(string link) - { - return TerminalRegex.ValidateLocalLink(link); - } } } diff --git a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObjectBase.cs b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObjectBase.cs new file mode 100644 index 0000000..d616b84 --- /dev/null +++ b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalScriptingObjectBase.cs @@ -0,0 +1,43 @@ +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Windows; + +namespace Microsoft.VisualStudio.Terminal +{ + [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + [ComVisible(true)] + public abstract class TerminalScriptingObjectBase : ITerminalScriptingObject + { + protected readonly TermWindowPackage package; + + internal TerminalScriptingObjectBase(TermWindowPackage package) + { + this.package = package; + } + + public string GetTheme() => TerminalThemer.GetTheme(); + + public string GetFontFamily() => this.package.OptionFontFamily; + + public int GetFontSize() => this.package.OptionFontSize; + + public abstract string GetSolutionDir(); + public abstract void ClosePty(); + + public void CopyStringToClipboard(string stringToCopy) => Clipboard.SetText(stringToCopy ?? ""); + + public string GetClipboard() => Clipboard.GetText(); + + public string GetLinkRegex() => TerminalRegex.LocalLinkRegex.ToString(); + + public void HandleLocalLink(string uri) => TerminalRegex.HandleLocalLink(uri); + + public abstract void InitPty(int cols, int rows, string directory); + + public abstract void ResizePty(int cols, int rows); + + public abstract void TermData(string data); + + public bool ValidateLocalLink(string link) => TerminalRegex.ValidateLocalLink(link); + } +} diff --git a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalTheme.cs b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalTheme.cs index e61a7eb..e39e22f 100644 --- a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalTheme.cs +++ b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalTheme.cs @@ -137,5 +137,12 @@ public string BrightWhite get; set; } + + [DataMember(Name = "border")] + public string Border + { + get; + set; + } } } diff --git a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalThemer.cs b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalThemer.cs index 53fc813..a9f56a9 100644 --- a/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalThemer.cs +++ b/Microsoft.VisualStudio.Terminal/BrowserBridge/TerminalThemer.cs @@ -63,6 +63,7 @@ public static string GetTheme() theme.Background = ColorTranslator.ToHtml(VSColorTheme.GetThemedColor(EnvironmentColors.ToolboxBackgroundColorKey)); theme.Foreground = ColorTranslator.ToHtml(VSColorTheme.GetThemedColor(EnvironmentColors.ToolboxContentTextColorKey)); theme.Cursor = ColorTranslator.ToHtml(VSColorTheme.GetThemedColor(EnvironmentColors.ToolboxContentTextColorKey)); + theme.Border = ColorTranslator.ToHtml(VSColorTheme.GetThemedColor(EnvironmentColors.ToolboxDisabledContentTextColorKey)); return JsonConvert.SerializeObject(theme); } } diff --git a/Microsoft.VisualStudio.Terminal/Microsoft.VisualStudio.Terminal.csproj b/Microsoft.VisualStudio.Terminal/Microsoft.VisualStudio.Terminal.csproj index 8ef1c21..2f438ff 100644 --- a/Microsoft.VisualStudio.Terminal/Microsoft.VisualStudio.Terminal.csproj +++ b/Microsoft.VisualStudio.Terminal/Microsoft.VisualStudio.Terminal.csproj @@ -1,7 +1,7 @@  + - 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) @@ -86,13 +86,20 @@ + + + + + RendererToolWindowControl.xaml + ServiceToolWindowControl.xaml + @@ -111,6 +118,7 @@ + @@ -153,6 +161,10 @@ + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -349,6 +361,7 @@ + @@ -370,12 +383,11 @@ - - + + - @@ -405,6 +417,7 @@ +