diff --git a/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs b/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs index b447821..beb6526 100644 --- a/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs +++ b/FluentTerminal.App.Services/Implementation/DefaultValueProvider.cs @@ -415,6 +415,7 @@ namespace FluentTerminal.App.Services.Implementation PreInstalled = true, WorkingDirectory = string.Empty, UseConPty = ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8), // Windows 10 1903+ + UseBuffer = false, EnvironmentVariables = new Dictionary { ["TERM"] = "xterm-256color" @@ -442,6 +443,7 @@ namespace FluentTerminal.App.Services.Implementation PreInstalled = true, WorkingDirectory = string.Empty, UseConPty = ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7), // Windows 10 1809+ + UseBuffer = true, EnvironmentVariables = new Dictionary { ["TERM"] = "xterm-256color" @@ -469,6 +471,7 @@ namespace FluentTerminal.App.Services.Implementation PreInstalled = true, WorkingDirectory = string.Empty, UseConPty = ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7), // Windows 10 1809+ + UseBuffer = true, //TODO: Set to false if the buffer causes issues with WSL. EnvironmentVariables = new Dictionary { ["TERM"] = "xterm-256color" diff --git a/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs b/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs index 39ba027..921a2b4 100644 --- a/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs +++ b/FluentTerminal.App.ViewModels/Profiles/ProfileProviderViewModelBase.cs @@ -154,6 +154,14 @@ namespace FluentTerminal.App.ViewModels.Profiles set => Set(ref _useConPty, value); } + private bool _useBuffer; + + public bool UseBuffer + { + get => _useBuffer; + set => Set(ref _useBuffer, value); + } + #endregion Properties #region Constructor @@ -215,6 +223,7 @@ namespace FluentTerminal.App.ViewModels.Profiles private void Initialize(ShellProfile profile) { UseConPty = profile.UseConPty; + UseBuffer = profile.UseBuffer; TerminalThemeId = profile.TerminalThemeId; TabThemeId = profile.TabThemeId; } @@ -227,6 +236,7 @@ namespace FluentTerminal.App.ViewModels.Profiles protected virtual Task CopyToProfileAsync(ShellProfile profile) { profile.UseConPty = _useConPty; + profile.UseBuffer = _useBuffer; profile.TerminalThemeId = _terminalThemeId; profile.TabThemeId = _tabThemeId; return Task.CompletedTask; @@ -244,6 +254,7 @@ namespace FluentTerminal.App.ViewModels.Profiles public virtual bool HasChanges() { return Model.UseConPty != _useConPty || + Model.UseBuffer != _useBuffer || !Model.TerminalThemeId.Equals(_terminalThemeId) || Model.TabThemeId != _tabThemeId; } @@ -279,6 +290,7 @@ namespace FluentTerminal.App.ViewModels.Profiles #region Links/shortcuts related private const string UseConPtyQueryStringName = "conpty"; + private const string UseBufferQueryStringName = "buffer"; private const string TerminalThemeIdQueryStringName = "theme"; private const string TabThemeIdQueryStringName = "tab"; @@ -318,8 +330,7 @@ URL={0} public string GetBaseQueryString() { - var queryString = - $"{UseConPtyQueryStringName}={_useConPty}"; + var queryString = $"{UseConPtyQueryStringName}={_useConPty}&{UseBufferQueryStringName}={_useBuffer}"; if (_tabThemeId != TabThemes.First().Id) { @@ -349,6 +360,14 @@ URL={0} UseConPty = useConPty; } + keyValue = queryStringParams.FirstOrDefault(t => + UseBufferQueryStringName.Equals(t.Item1, StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrEmpty(keyValue?.Item2) && bool.TryParse(keyValue.Item2?.ToLower(), out bool useBuffer)) + { + UseConPty = useBuffer; + } + keyValue = queryStringParams.FirstOrDefault(t => TabThemeIdQueryStringName.Equals(t.Item1, StringComparison.OrdinalIgnoreCase)); diff --git a/FluentTerminal.App/App.xaml.cs b/FluentTerminal.App/App.xaml.cs index 42ae024..8a5a54f 100755 --- a/FluentTerminal.App/App.xaml.cs +++ b/FluentTerminal.App/App.xaml.cs @@ -424,6 +424,11 @@ namespace FluentTerminal.App WorkingDirectory = runVerb.Directory }; + if (!string.IsNullOrEmpty(runVerb.Buffer) && bool.TryParse(runVerb.Buffer, out var useBuffer)) + { + profile.UseBuffer = useBuffer; + } + if (!string.IsNullOrWhiteSpace(runVerb.Theme)) { var theme = _settingsService.GetThemes().FirstOrDefault(x => x.Name.Equals(runVerb.Theme, StringComparison.CurrentCultureIgnoreCase)); diff --git a/FluentTerminal.App/CommandLineArguments/RunVerb.cs b/FluentTerminal.App/CommandLineArguments/RunVerb.cs index eab3c8a..3c13f84 100644 --- a/FluentTerminal.App/CommandLineArguments/RunVerb.cs +++ b/FluentTerminal.App/CommandLineArguments/RunVerb.cs @@ -14,6 +14,9 @@ namespace FluentTerminal.App.CommandLineArguments [Option("theme")] public string Theme { get; set; } + [Option("buffer")] + public string Buffer { get; set; } + [Option("target")] public Target Target { get; set; } } diff --git a/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml b/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml index c885361..312aea0 100644 --- a/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml +++ b/FluentTerminal.App/Dialogs/CustomCommandDialog.xaml @@ -79,6 +79,7 @@ + @@ -124,6 +125,15 @@ Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseConPty}" IsChecked="{x:Bind ViewModel.UseConPty, Mode=TwoWay}" /> + + + diff --git a/FluentTerminal.App/Dialogs/SshInfoDialog.xaml b/FluentTerminal.App/Dialogs/SshInfoDialog.xaml index 0bac224..a427e21 100644 --- a/FluentTerminal.App/Dialogs/SshInfoDialog.xaml +++ b/FluentTerminal.App/Dialogs/SshInfoDialog.xaml @@ -129,6 +129,7 @@ + @@ -209,6 +210,15 @@ Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseConPty}" IsChecked="{x:Bind ViewModel.UseConPty, Mode=TwoWay}" /> + + + diff --git a/FluentTerminal.App/Strings/en/Resources.resw b/FluentTerminal.App/Strings/en/Resources.resw index dd4e6a1..f02f77c 100644 --- a/FluentTerminal.App/Strings/en/Resources.resw +++ b/FluentTerminal.App/Strings/en/Resources.resw @@ -1108,4 +1108,7 @@ Fuzzy Copy selection or paste + + Use buffer + \ No newline at end of file diff --git a/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml b/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml index 4a04977..2b5a7a7 100644 --- a/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml +++ b/FluentTerminal.App/Views/SettingsPages/ShellProfileSettings.xaml @@ -249,6 +249,13 @@ IsEnabled="{x:Bind InEditMode, Mode=OneWay}" IsOn="{x:Bind ProfileVm.UseConPty, Mode=TwoWay}" /> + + + + + + + + + + + + new KeyBinding(x)).ToList(); } @@ -42,6 +43,7 @@ namespace FluentTerminal.Models public int TabThemeId { get; set; } public Dictionary EnvironmentVariables { get; set; } = new Dictionary(); public bool UseConPty { get; set; } + public bool UseBuffer { get; set; } = true; public int MigrationVersion { get; set; } = CurrentMigrationVersion; @@ -75,6 +77,7 @@ namespace FluentTerminal.Models && other.TabThemeId.Equals(TabThemeId) && other.TerminalThemeId.Equals(TerminalThemeId) && other.UseConPty == UseConPty + && other.UseBuffer == UseBuffer && other.KeyBindings.SequenceEqual(KeyBindings); } diff --git a/FluentTerminal.SystemTray/BufferedReader.cs b/FluentTerminal.SystemTray/BufferedReader.cs index 8be896a..1116a9b 100644 --- a/FluentTerminal.SystemTray/BufferedReader.cs +++ b/FluentTerminal.SystemTray/BufferedReader.cs @@ -16,6 +16,7 @@ namespace FluentTerminal.SystemTray private readonly Stream _stream; private readonly Action _callback; + private readonly bool _enableBuffer; private bool _disposed; private bool _paused; @@ -28,10 +29,11 @@ namespace FluentTerminal.SystemTray private int _nearReadingsCount; private Task _sendingTask; - internal BufferedReader(Stream stream, Action callback) + internal BufferedReader(Stream stream, Action callback, bool enableBuffer) { _stream = stream; _callback = callback; + _enableBuffer = enableBuffer; // ReSharper disable once AssignmentIsFullyDiscarded _ = Task.Factory.StartNew(ReadingLoop, TaskCreationOptions.LongRunning); @@ -89,6 +91,18 @@ namespace FluentTerminal.SystemTray continue; } + if (!_enableBuffer) + { + // Buffering disabled. Just send. + + _buffer = currentBuffer; + _bufferIndex = read; + + SendBuffer(); + + continue; + } + var now = DateTime.UtcNow; lock (_lock) diff --git a/FluentTerminal.SystemTray/Services/ConPty/ConPtySession.cs b/FluentTerminal.SystemTray/Services/ConPty/ConPtySession.cs index 51a3937..d467195 100644 --- a/FluentTerminal.SystemTray/Services/ConPty/ConPtySession.cs +++ b/FluentTerminal.SystemTray/Services/ConPty/ConPtySession.cs @@ -12,6 +12,7 @@ namespace FluentTerminal.SystemTray.Services.ConPty private Terminal _terminal; private BufferedReader _reader; + private bool _enableBuffer; public byte Id { get; private set; } @@ -33,6 +34,11 @@ namespace FluentTerminal.SystemTray.Services.ConPty public void Start(CreateTerminalRequest request, TerminalsManager terminalsManager) { + _enableBuffer = request.Profile.UseBuffer; + + _reader?.Dispose(); + _reader = null; + Id = request.Id; _terminalsManager = terminalsManager; @@ -71,7 +77,7 @@ namespace FluentTerminal.SystemTray.Services.ConPty if (_reader == null) { _reader = new BufferedReader(_terminal.ConsoleOutStream, - bytes => _terminalsManager.DisplayTerminalOutput(Id, bytes)); + bytes => _terminalsManager.DisplayTerminalOutput(Id, bytes), _enableBuffer); } } diff --git a/FluentTerminal.SystemTray/Services/WinPty/WinPtySession.cs b/FluentTerminal.SystemTray/Services/WinPty/WinPtySession.cs index fcb47d5..6c154eb 100644 --- a/FluentTerminal.SystemTray/Services/WinPty/WinPtySession.cs +++ b/FluentTerminal.SystemTray/Services/WinPty/WinPtySession.cs @@ -18,9 +18,12 @@ namespace FluentTerminal.SystemTray.Services.WinPty private TerminalsManager _terminalsManager; private Process _shellProcess; private BufferedReader _reader; + private bool _enableBuffer; public void Start(CreateTerminalRequest request, TerminalsManager terminalsManager) { + _enableBuffer = request.Profile.UseBuffer; + Id = request.Id; _terminalsManager = terminalsManager; @@ -82,7 +85,8 @@ namespace FluentTerminal.SystemTray.Services.WinPty winpty_error_free(errorHandle); } - _reader = new BufferedReader(_stdout, bytes => _terminalsManager.DisplayTerminalOutput(Id, bytes)); + _reader = new BufferedReader(_stdout, bytes => _terminalsManager.DisplayTerminalOutput(Id, bytes), + _enableBuffer); } private void _shellProcess_Exited(object sender, EventArgs e)