Compare commits

..
1 Commits
51 changed files with 3324 additions and 8066 deletions

No files matched your search

+1 -1
View File
@@ -20,4 +20,4 @@ jobs:
uses: warrenbuckley/Setup-MSBuild@v1
- name: MSBuild
run: msbuild FluentTerminal.sln -t:build -p:Configuration=Debug -p:Platform=x64 -m -restore
run: msbuild FluentTerminal.sln -t:build -p:Configuration=Debug -p:Platform=x64 -p:AppxPackage=false -m -restore
@@ -1,23 +0,0 @@
using System;
namespace FluentTerminal.App.Services.Exceptions
{
public class ReadTextFileException : Exception
{
public ReadTextFileException() : base()
{
}
public ReadTextFileException(string message) : base(message)
{
}
public ReadTextFileException(string message, Exception innerException) : base(message, innerException)
{
}
protected ReadTextFileException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
{
}
}
}
@@ -0,0 +1,12 @@
using FluentTerminal.Models.Enums;
namespace FluentTerminal.App.Services
{
// This validator is needed because accelerator key has to be member of VirtualKey enum.
public interface IAcceleratorKeyValidator
{
bool Valid(int key);
bool Valid(ExtendedVirtualKey key);
}
}
@@ -35,8 +35,6 @@ namespace FluentTerminal.App.Services
Task SaveTextFileAsync(string path, string content);
Task<string> ReadTextFileAsync(string path);
Task<string> GetSshConfigDirAsync();
Task<string[]> GetFilesFromSshConfigDirAsync();
@@ -1,4 +1,5 @@
using FluentTerminal.Models;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
@@ -230,7 +231,8 @@ namespace FluentTerminal.App.Services.Implementation
Command = nameof(Command.ShowSettings),
Ctrl = true,
Shift = true,
Key = (int)ExtendedVirtualKey.Comma
// I've had to replace ExtendedVirtualKey.Comma because it isn't a member of VirtualKey enum, thus cannot be shown in menu.
Key = (int)ExtendedVirtualKey.S
}
};
@@ -340,7 +342,7 @@ namespace FluentTerminal.App.Services.Implementation
new TabTheme
{
Id = 0,
Name = "TabTheme.None",
Name = I18N.Translate("TabTheme.None"),
BackgroundOpacity = double.NaN,
BackgroundPointerOverOpacity = double.NaN,
BackgroundPressedOpacity = double.NaN,
@@ -351,37 +353,37 @@ namespace FluentTerminal.App.Services.Implementation
new TabTheme
{
Id = 1,
Name = "TabTheme.Red",
Name = I18N.Translate("TabTheme.Red"),
Color = "#E81123"
},
new TabTheme
{
Id = 2,
Name = "TabTheme.Green",
Name = I18N.Translate("TabTheme.Green"),
Color = "#10893E"
},
new TabTheme
{
Id = 3,
Name = "TabTheme.Blue",
Name = I18N.Translate("TabTheme.Blue"),
Color = "#0078D7"
},
new TabTheme
{
Id = 4,
Name = "TabTheme.Purple",
Name = I18N.Translate("TabTheme.Purple"),
Color = "#881798"
},
new TabTheme
{
Id = 5,
Name = "TabTheme.Orange",
Name = I18N.Translate("TabTheme.Orange"),
Color = "#FF8C00"
},
new TabTheme
{
Id = 6,
Name = "TabTheme.Teal",
Name = I18N.Translate("TabTheme.Teal"),
Color = "#00B7C3"
}
};
@@ -71,7 +71,7 @@ namespace FluentTerminal.App.Services.Implementation
config.Themes.Add(theme);
}
foreach (var profile in GetShellProfiles())
foreach (var profile in GetShellProfiles().Where(x => !x.PreInstalled))
{
config.Profiles.Add(profile);
}
@@ -117,18 +117,21 @@ namespace FluentTerminal.App.Services.Implementation
SaveTheme(theme, existingTheme != null);
}
foreach (var profile in config.Profiles)
// Can't create pre-installed profiles
foreach (var profile in config.Profiles.Where(x => !x.PreInstalled))
{
var existingProfile = GetShellProfile(profile.Id);
var isNew = existingProfile == default;
var isNew = existingProfile.EqualTo(default);
// You can only edit certain parts of preinstalled profiles
if (!isNew && existingProfile.PreInstalled)
{
// those cannot be edited
profile.Name = existingProfile.Name;
profile.Location = existingProfile.Location;
SaveShellProfile(profile, false);
existingProfile.WorkingDirectory = profile.WorkingDirectory;
existingProfile.Arguments = profile.Arguments;
existingProfile.TabThemeId = profile.TabThemeId;
existingProfile.TerminalThemeId = profile.TerminalThemeId;
existingProfile.KeyBindings = profile.KeyBindings;
SaveShellProfile(profile, isNew);
continue;
}
SaveShellProfile(profile, isNew);
@@ -137,7 +140,7 @@ namespace FluentTerminal.App.Services.Implementation
foreach (var profile in config.SshProfiles)
{
var existingProfile = GetSshProfile(profile.Id);
var isNew = existingProfile == default;
var isNew = existingProfile.EqualTo(default(SshProfile));
SaveSshProfile(profile, isNew);
}
@@ -84,18 +84,6 @@ namespace FluentTerminal.App.Services.Implementation
}
}
public async Task<string> ReadTextFileAsync(string path)
{
var response = await GetResponseAsync<StringValueResponse>(new ReadTextFileRequest { Path = path }).ConfigureAwait(false);
if (!response.Success)
{
throw new ReadTextFileException(string.IsNullOrWhiteSpace(response.Error) ? "Failed to read the file." : response.Error);
}
return response.Value;
}
public async Task<string> GetSshConfigDirAsync()
{
if (!string.IsNullOrEmpty(_sshConfigDir))
-4
View File
@@ -77,8 +77,6 @@ namespace FluentTerminal.App.Services
public byte Id { get; }
public ShellProfile Profile { get; private set; }
/// <summary>
/// To be called by either view or viewmodel
/// </summary>
@@ -145,8 +143,6 @@ namespace FluentTerminal.App.Services
/// </summary>
public async Task<TerminalResponse> StartShellProcessAsync(ShellProfile shellProfile, TerminalSize size, SessionType sessionType, string termState)
{
Profile = shellProfile;
if (!_requireShellProcessStart && !string.IsNullOrEmpty(termState))
{
OutputReceived?.Invoke(this, Encoding.UTF8.GetBytes(termState));
+18 -5
View File
@@ -28,6 +28,7 @@ namespace FluentTerminal.App.ViewModels
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private readonly ICommandHistoryService _commandHistoryService;
private readonly IAcceleratorKeyValidator _acceleratorKeyValidator;
private ApplicationSettings _applicationSettings;
private bool _useAcrylicBackground;
private double _backgroundOpacity;
@@ -37,7 +38,7 @@ namespace FluentTerminal.App.ViewModels
private IDictionary<string, ICollection<KeyBinding>> _keyBindings;
public MainViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, IKeyboardCommandService keyboardCommandService,
IApplicationView applicationView, IClipboardService clipboardService, ICommandHistoryService commandHistoryService)
IApplicationView applicationView, IClipboardService clipboardService, ICommandHistoryService commandHistoryService, IAcceleratorKeyValidator acceleratorKeyValidator)
{
MessengerInstance.Register<ApplicationSettingsChangedMessage>(this, OnApplicationSettingsChanged);
MessengerInstance.Register<ShellProfileAddedMessage>(this, OnShellProfileAdded);
@@ -56,6 +57,7 @@ namespace FluentTerminal.App.ViewModels
_clipboardService = clipboardService;
_keyboardCommandService = keyboardCommandService;
_commandHistoryService = commandHistoryService;
_acceleratorKeyValidator = acceleratorKeyValidator;
_keyboardCommandService.RegisterCommandHandler(nameof(Command.NewTab), async () => await AddDefaultProfileAsync(NewTerminalLocation.Tab));
_keyboardCommandService.RegisterCommandHandler(nameof(Command.NewWindow), async () => await AddDefaultProfileAsync(NewTerminalLocation.Window));
@@ -675,7 +677,8 @@ namespace FluentTerminal.App.ViewModels
icon: Mdl2Icon.Settings());
if (_keyBindings.TryGetValue(nameof(Command.ShowSettings), out var keyBindings) &&
keyBindings.FirstOrDefault() is KeyBinding settingsKeyBinding)
keyBindings.FirstOrDefault() is KeyBinding settingsKeyBinding &&
_acceleratorKeyValidator.Valid(settingsKeyBinding.Key))
{
LoadKeyBindingsFromModel(settingsItem, settingsKeyBinding);
}
@@ -717,7 +720,8 @@ namespace FluentTerminal.App.ViewModels
var defaultProfileCommand = tab ? nameof(Command.NewTab) : nameof(Command.NewWindow);
if (_keyBindings.TryGetValue(defaultProfileCommand, out var kbs) &&
kbs.FirstOrDefault() is KeyBinding tabKeyBindings)
kbs.FirstOrDefault() is KeyBinding tabKeyBindings &&
_acceleratorKeyValidator.Valid(tabKeyBindings.Key))
{
LoadKeyBindingsFromModel(defaultProfileItem, tabKeyBindings);
}
@@ -739,7 +743,8 @@ namespace FluentTerminal.App.ViewModels
var command = tab ? nameof(Command.NewSshTab) : nameof(Command.NewSshWindow);
if (_keyBindings.TryGetValue(command, out var keyBindings) &&
keyBindings.FirstOrDefault() is KeyBinding remoteTabKeyBinding)
keyBindings.FirstOrDefault() is KeyBinding remoteTabKeyBinding &&
_acceleratorKeyValidator.Valid(remoteTabKeyBinding.Key))
{
LoadKeyBindingsFromModel(remoteConnectItem, remoteTabKeyBinding);
}
@@ -760,7 +765,8 @@ namespace FluentTerminal.App.ViewModels
command = tab ? nameof(Command.NewCustomCommandTab) : nameof(Command.NewCustomCommandWindow);
if (_keyBindings.TryGetValue(command, out keyBindings) &&
keyBindings.FirstOrDefault() is KeyBinding quickTabKeyBinding)
keyBindings.FirstOrDefault() is KeyBinding quickTabKeyBinding &&
_acceleratorKeyValidator.Valid(quickTabKeyBinding.Key))
{
LoadKeyBindingsFromModel(quickLaunchItem, quickTabKeyBinding);
}
@@ -789,6 +795,13 @@ namespace FluentTerminal.App.ViewModels
private void LoadKeyBindingsFromModel(MenuItemViewModel menuItemViewModel, KeyBinding keyBinding)
{
if (!_acceleratorKeyValidator.Valid(keyBinding.Key))
{
menuItemViewModel.KeyBinding = null;
return;
}
if (menuItemViewModel.KeyBinding == null)
{
menuItemViewModel.KeyBinding = new MenuItemKeyBindingViewModel(keyBinding);
@@ -1,15 +1,12 @@
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using Windows.System;
namespace FluentTerminal.App.ViewModels.Menu
{
public class MenuItemKeyBindingViewModel : ViewModelBase
{
#region Properties
private int _key;
public int Key
@@ -83,21 +80,9 @@ namespace FluentTerminal.App.ViewModels.Menu
}
}
public bool IsExtendedVirtualKey => !Enum.IsDefined(typeof(VirtualKey), Key);
#endregion Properties
public string GetOverrideText()
{
var segments = new List<string>();
if (Ctrl) segments.Add("Ctrl");
if (Alt) segments.Add("Alt");
if (Windows) segments.Add("Windows");
if (Shift) segments.Add("Shift");
segments.Add(EnumHelper.GetEnumDescription((ExtendedVirtualKey)Key));
return string.Join("+", segments);
}
#region Constructors
public MenuItemKeyBindingViewModel(int key = 0, bool ctrl = false, bool alt = false, bool shift = false,
bool windows = false)
@@ -116,7 +101,9 @@ namespace FluentTerminal.App.ViewModels.Menu
{
}
#endregion Constructors
#region Methods
private void SetKeyModifiers()
{
@@ -155,5 +142,6 @@ namespace FluentTerminal.App.ViewModels.Menu
return _key == other._key && _keyModifiers == other._keyModifiers;
}
#endregion Methods
}
}
@@ -116,7 +116,6 @@ namespace FluentTerminal.App.ViewModels
private string _hoveredUri;
private MenuViewModel _contextMenu;
private MenuViewModel _tabContextMenu;
private readonly TabThemeViewModel _transparentTabThemeViewModel;
public TerminalViewModel(ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService,
IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, ShellProfile shellProfile,
@@ -168,8 +167,6 @@ namespace FluentTerminal.App.ViewModels
defaultTabTheme.IsSelected = true;
}
_transparentTabThemeViewModel = TabThemes.FirstOrDefault(t => t.Theme.Id == 0);
Terminal = new Terminal(TrayProcessCommunicationService, _terminalId);
Terminal.KeyboardCommandReceived += Terminal_KeyboardCommandReceived;
Terminal.OutputReceived += Terminal_OutputReceived;
@@ -221,13 +218,13 @@ namespace FluentTerminal.App.ViewModels
public IApplicationView ApplicationView { get; }
public TabThemeViewModel BackgroundTabTheme
public TabTheme BackgroundTabTheme
{
// The effective background theme depends on whether it is selected (use the theme), or if it is inactive
// (if we're set to underline inactive tabs, use the null theme).
get => IsSelected || (!IsSelected && ApplicationSettings.InactiveTabColorMode == InactiveTabColorMode.Background) ?
TabTheme :
_transparentTabThemeViewModel;
_tabTheme?.Theme :
SettingsService.GetTabThemes().FirstOrDefault(t => t.Color == null);
}
public IClipboardService ClipboardService { get; }
@@ -692,7 +689,6 @@ namespace FluentTerminal.App.ViewModels
private void Terminal_TitleChanged(object sender, string e)
{
if (e == Terminal.Profile.Location) return;
ApplicationView.ExecuteOnUiThreadAsync(() => ShellTitle = e);
}
@@ -781,7 +777,7 @@ namespace FluentTerminal.App.ViewModels
{
//todo localise name
var icon = tabTheme.Theme.Id == 0 ? Mdl2Icon.PaginationDotOutline10() : Mdl2Icon.PaginationDotSolid10(tabTheme.Theme.Color);
return new RadioMenuItemViewModel(I18N.Translate($"{tabTheme.Theme.Name}"), $"{Terminal.Id}_tabTheme", tabTheme, bindingPath: nameof(TabThemeViewModel.IsSelected) , icon: icon);
return new RadioMenuItemViewModel(I18N.Translate($"TabTheme.{tabTheme.Theme.Name}"), $"{Terminal.Id}_tabTheme", tabTheme, bindingPath: nameof(TabThemeViewModel.IsSelected) , icon: icon);
}
var tabColor = new ExpandableMenuItemViewModel(I18N.Translate("Color.Text"));
+149 -193
View File
@@ -47,7 +47,6 @@ namespace FluentTerminal.App
private readonly ISettingsService _settingsService;
private readonly ITrayProcessCommunicationService _trayProcessCommunicationService;
private readonly IDialogService _dialogService;
private readonly INotificationService _notificationService;
private bool _alreadyLaunched;
private bool _isLaunching;
private ApplicationSettings _applicationSettings;
@@ -111,13 +110,13 @@ namespace FluentTerminal.App
builder.RegisterType<StartupTaskService>().As<IStartupTaskService>().SingleInstance();
builder.RegisterType<ApplicationLanguageService>().As<IApplicationLanguageService>().SingleInstance();
builder.RegisterType<ShellProfileMigrationService>().As<IShellProfileMigrationService>().SingleInstance();
builder.RegisterType<AcceleratorKeyValidator>().As<IAcceleratorKeyValidator>().SingleInstance();
_container = builder.Build();
Messenger.Default.Register<ApplicationSettingsChangedMessage>(this, OnApplicationSettingsChanged);
_settingsService = _container.Resolve<ISettingsService>();
_notificationService = _container.Resolve<INotificationService>();
var shellProfileMigrationService = _container.Resolve<IShellProfileMigrationService>();
foreach (var profile in _settingsService.GetShellProfiles())
@@ -187,189 +186,7 @@ namespace FluentTerminal.App
protected override async void OnActivated(IActivatedEventArgs args)
{
await OnLaunchOrActivate(args);
base.OnActivated(args);
}
private async Task ParseCommandLineArgumentsAsync(object verb, CommandLineActivatedEventArgs commandLineActivated)
{
using var deferral = commandLineActivated.Operation.GetDeferral();
if (verb is SettingsVerb settingsVerb)
{
if (string.IsNullOrWhiteSpace(settingsVerb.Import) && !settingsVerb.Export)
{
await ShowSettingsAsync();
}
else if (settingsVerb.Export)
{
var settings = _settingsService.ExportSettings();
var path = Path.Combine(commandLineActivated.Operation.CurrentDirectoryPath, "config.json");
try
{
await StartSystemTray().ConfigureAwait(false);
await _trayProcessCommunicationService.SaveTextFileAsync(path, settings).ConfigureAwait(false);
_notificationService.ShowNotification("Export settings", $"Settings were exported to {path}.");
}
catch (Exception e)
{
_notificationService.ShowNotification("Export settings", $"Failed with error: {e.Message}");
commandLineActivated.Operation.ExitCode = 1;
}
if (!_isLaunching && !_alreadyLaunched)
{
Exit();
}
}
else if (!string.IsNullOrWhiteSpace(settingsVerb.Import))
{
var path = Path.Combine(commandLineActivated.Operation.CurrentDirectoryPath, settingsVerb.Import.Replace(".\\", string.Empty));
try
{
await StartSystemTray().ConfigureAwait(false);
var content = await _trayProcessCommunicationService.ReadTextFileAsync(path).ConfigureAwait(false);
_settingsService.ImportSettings(content);
_notificationService.ShowNotification("Import settings", $"Successfully imported settings from {path}.");
}
catch (Exception e)
{
_notificationService.ShowNotification("Import settings", $"Failed with error: {e.Message}");
commandLineActivated.Operation.ExitCode = 1;
}
if (!_isLaunching && !_alreadyLaunched)
{
Exit();
}
}
}
else if (verb is NewVerb newVerb)
{
var profile = default(ShellProfile);
if (!string.IsNullOrWhiteSpace(newVerb.Profile))
{
profile = _settingsService.GetShellProfiles().FirstOrDefault(x => x.Name.Equals(newVerb.Profile, StringComparison.CurrentCultureIgnoreCase));
}
if (profile == null)
{
profile = _settingsService.GetDefaultShellProfile();
}
if (!string.IsNullOrWhiteSpace(newVerb.Directory) && newVerb.Directory != ".")
{
profile.WorkingDirectory = newVerb.Directory;
}
else
{
profile.WorkingDirectory = commandLineActivated.Operation.CurrentDirectoryPath;
}
var location = newVerb.Target == Target.Default ? _applicationSettings.NewTerminalLocation
: newVerb.Target == Target.Tab ? NewTerminalLocation.Tab
: NewTerminalLocation.Window;
await CreateTerminalAsync(profile, location);
}
else if (verb is RunVerb runVerb)
{
var profile = new ShellProfile
{
Id = Guid.Empty,
Location = null,
Arguments = runVerb.Command,
WorkingDirectory = runVerb.Directory
};
if (runVerb.SmartBuffer.HasValue)
{
profile.UseBuffer = runVerb.SmartBuffer.Value;
}
if (!string.IsNullOrWhiteSpace(runVerb.Theme))
{
var theme = _settingsService.GetThemes().FirstOrDefault(x => x.Name.Equals(runVerb.Theme, StringComparison.CurrentCultureIgnoreCase));
if (theme != null)
{
profile.TerminalThemeId = theme.Id;
}
}
if (string.IsNullOrWhiteSpace(profile.WorkingDirectory))
{
profile.WorkingDirectory = commandLineActivated.Operation.CurrentDirectoryPath;
}
var location = runVerb.Target == Target.Default ? _applicationSettings.NewTerminalLocation
: runVerb.Target == Target.Tab ? NewTerminalLocation.Tab
: NewTerminalLocation.Window;
await CreateTerminalAsync(profile, location);
}
}
private Task ShowOrCreateWindowAsync(ActivationViewSwitcher viewSwitcher)
{
var viewModel = _mainViewModels.Find(o => o.ApplicationView.Id == _activeWindowId) ??
_mainViewModels.LastOrDefault();
return viewModel == null
? CreateTerminalAsync(_settingsService.GetDefaultShellProfile(), NewTerminalLocation.Tab, viewSwitcher)
: ShowAsStandaloneAsync(viewModel, viewSwitcher);
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
await OnLaunchOrActivate(args);
}
public async Task OnLaunchOrActivate(IActivatedEventArgs args)
{
if (args is LaunchActivatedEventArgs launchActivated)
{
if (_isLaunching)
{
return;
}
_isLaunching = true;
if (!_alreadyLaunched)
{
await InitializeLoggerAsync();
// ReSharper disable once AssignmentIsFullyDiscarded
_ = JumpListHelper.UpdateAsync(_settingsService);
var viewModel = _container.Resolve<MainViewModel>();
if (launchActivated.Arguments.StartsWith(JumpListHelper.ShellProfileFlag))
{
await viewModel.AddProfileByGuidAsync(Guid.Parse(launchActivated.Arguments.Replace(JumpListHelper.ShellProfileFlag, string.Empty)));
}
else
{
await viewModel.AddDefaultProfileAsync(NewTerminalLocation.Tab);
}
await CreateMainViewAsync(typeof(MainPage), viewModel, true);
Window.Current.Activate();
}
else if (launchActivated.Arguments.StartsWith(JumpListHelper.ShellProfileFlag))
{
var location = _applicationSettings.NewTerminalLocation;
var profile = _settingsService.GetShellProfile(Guid.Parse(launchActivated.Arguments.Replace(JumpListHelper.ShellProfileFlag, string.Empty)));
await CreateTerminalAsync(profile, location, launchActivated.ViewSwitcher);
}
else
{
var viewModel = await CreateNewTerminalWindowAsync();
await viewModel.AddDefaultProfileAsync(NewTerminalLocation.Tab);
await ShowAsStandaloneAsync(viewModel, launchActivated.ViewSwitcher);
}
_isLaunching = false;
}
else if (args is ProtocolActivatedEventArgs protocolActivated)
if (args is ProtocolActivatedEventArgs protocolActivated)
{
if (protocolActivated.Uri == new Uri("ftcmd://fluent.terminal?focus"))
{
@@ -445,7 +262,7 @@ namespace FluentTerminal.App
var error = await vm.AcceptChangesAsync(true);
var profile = (SshProfile)vm.Model;
var profile = (SshProfile) vm.Model;
if (!string.IsNullOrEmpty(error))
{
@@ -530,7 +347,8 @@ namespace FluentTerminal.App
return;
}
else if (args is CommandLineActivatedEventArgs commandLineActivated)
if (args is CommandLineActivatedEventArgs commandLineActivated)
{
var arguments = commandLineActivated.Operation.Arguments;
if (string.IsNullOrWhiteSpace(arguments))
@@ -540,10 +358,153 @@ namespace FluentTerminal.App
_commandLineParser
.ParseArguments(SplitArguments(arguments), typeof(NewVerb), typeof(RunVerb), typeof(SettingsVerb))
.WithParsed(async verb => await ParseCommandLineArgumentsAsync(verb, commandLineActivated));
.WithParsed(async verb => await CliRunAsync(verb, commandLineActivated));
}
}
private async Task CliRunAsync(object verb, CommandLineActivatedEventArgs commandLineActivated)
{
if (verb is SettingsVerb settingsVerb)
{
if (!settingsVerb.Import && !settingsVerb.Export)
{
await ShowSettingsAsync();
}
else if (settingsVerb.Export)
{
var exportFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("config.json", CreationCollisionOption.OpenIfExists);
var settings = _settingsService.ExportSettings();
await FileIO.WriteTextAsync(exportFile, settings);
await new MessageDialog($"{I18N.Translate("SettingsExported")} {exportFile.Path}").ShowAsync();
}
else if (settingsVerb.Import)
{
var file = await ApplicationData.Current.LocalFolder.GetFileAsync("config.json");
var content = await FileIO.ReadTextAsync(file);
_settingsService.ImportSettings(content);
await new MessageDialog($"{I18N.Translate("SettingsImported")} {file.Path}").ShowAsync();
}
}
else if (verb is NewVerb newVerb)
{
var profile = default(ShellProfile);
if (!string.IsNullOrWhiteSpace(newVerb.Profile))
{
profile = _settingsService.GetShellProfiles().FirstOrDefault(x => x.Name.Equals(newVerb.Profile, StringComparison.CurrentCultureIgnoreCase));
}
if (profile == null)
{
profile = _settingsService.GetDefaultShellProfile();
}
if (!string.IsNullOrWhiteSpace(newVerb.Directory) && newVerb.Directory != ".")
{
profile.WorkingDirectory = newVerb.Directory;
}
else
{
profile.WorkingDirectory = commandLineActivated.Operation.CurrentDirectoryPath;
}
var location = newVerb.Target == Target.Default ? _applicationSettings.NewTerminalLocation
: newVerb.Target == Target.Tab ? NewTerminalLocation.Tab
: NewTerminalLocation.Window;
await CreateTerminalAsync(profile, location);
}
else if (verb is RunVerb runVerb)
{
var profile = new ShellProfile
{
Id = Guid.Empty,
Location = null,
Arguments = runVerb.Command,
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));
if (theme != null)
{
profile.TerminalThemeId = theme.Id;
}
}
if (string.IsNullOrWhiteSpace(profile.WorkingDirectory))
{
profile.WorkingDirectory = commandLineActivated.Operation.CurrentDirectoryPath;
}
var location = runVerb.Target == Target.Default ? _applicationSettings.NewTerminalLocation
: runVerb.Target == Target.Tab ? NewTerminalLocation.Tab
: NewTerminalLocation.Window;
await CreateTerminalAsync(profile, location);
}
}
private Task ShowOrCreateWindowAsync(ActivationViewSwitcher viewSwitcher)
{
var viewModel = _mainViewModels.Find(o => o.ApplicationView.Id == _activeWindowId) ??
_mainViewModels.LastOrDefault();
return viewModel == null
? CreateTerminalAsync(_settingsService.GetDefaultShellProfile(), NewTerminalLocation.Tab, viewSwitcher)
: ShowAsStandaloneAsync(viewModel, viewSwitcher);
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (_isLaunching)
{
return;
}
_isLaunching = true;
if (!_alreadyLaunched)
{
await InitializeLoggerAsync();
// ReSharper disable once AssignmentIsFullyDiscarded
_ = JumpListHelper.UpdateAsync(_settingsService);
var viewModel = _container.Resolve<MainViewModel>();
if (args.Arguments.StartsWith(JumpListHelper.ShellProfileFlag))
{
await viewModel.AddProfileByGuidAsync(Guid.Parse(args.Arguments.Replace(JumpListHelper.ShellProfileFlag, string.Empty)));
}
else
{
await viewModel.AddDefaultProfileAsync(NewTerminalLocation.Tab);
}
await CreateMainViewAsync(typeof(MainPage), viewModel, true);
Window.Current.Activate();
}
else if (args.Arguments.StartsWith(JumpListHelper.ShellProfileFlag))
{
var location = _applicationSettings.NewTerminalLocation;
var profile = _settingsService.GetShellProfile(Guid.Parse(args.Arguments.Replace(JumpListHelper.ShellProfileFlag, string.Empty)));
await CreateTerminalAsync(profile, location, args.ViewSwitcher);
}
else
{
var viewModel = await CreateNewTerminalWindowAsync();
await viewModel.AddDefaultProfileAsync(NewTerminalLocation.Tab);
await ShowAsStandaloneAsync(viewModel, args.ViewSwitcher);
}
_isLaunching = false;
}
private static async Task InitializeLoggerAsync()
{
var logDirectory = await ApplicationData.Current.LocalCacheFolder.CreateFolderAsync("Logs", CreationCollisionOption.OpenIfExists);
@@ -798,11 +759,6 @@ namespace FluentTerminal.App
private Task StartSystemTray()
{
if (_trayReady.Task.IsCompleted)
{
return Task.CompletedTask;
}
var launch = FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("AppLaunchedParameterGroup").AsTask();
return Task.WhenAll(launch, _trayReady.Task).ContinueWith(
@@ -14,8 +14,8 @@ namespace FluentTerminal.App.CommandLineArguments
[Option("theme")]
public string Theme { get; set; }
[Option("smart-buffer")]
public bool? SmartBuffer { get; set; }
[Option("buffer")]
public string Buffer { get; set; }
[Option("target")]
public Target Target { get; set; }
@@ -6,8 +6,8 @@ namespace FluentTerminal.App.CommandLineArguments
public class SettingsVerb
{
[Option('i', "import",
HelpText = "Import settings from specified file.")]
public string Import { get; set; }
HelpText = "Import settings.")]
public bool Import { get; set; }
[Option('e', "export",
HelpText = "Export settings.")]
@@ -20,10 +20,6 @@ namespace FluentTerminal.App.Converters
{
return Translate($"{enumType}.{enumValue}");
}
else if (value is string stringValue)
{
return Translate(stringValue);
}
else if (parameter is string resource)
{
return Translate(resource);
@@ -7,7 +7,6 @@ using Windows.UI.Xaml.Input;
using FluentTerminal.App.ViewModels.Menu;
using FluentTerminal.App.Views;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation.Metadata;
// ReSharper disable LocalizableElement
@@ -91,22 +90,12 @@ namespace FluentTerminal.App.Converters
if (viewModel.KeyBinding != null)
{
if (viewModel.KeyBinding.IsExtendedVirtualKey)
item.KeyboardAccelerators?.Add(new KeyboardAccelerator
{
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 6))
{
item.KeyboardAcceleratorTextOverride = viewModel.KeyBinding.GetOverrideText();
}
}
else
{
item.KeyboardAccelerators?.Add(new KeyboardAccelerator
{
Key = (VirtualKey)viewModel.KeyBinding.Key,
Modifiers = (VirtualKeyModifiers)viewModel.KeyBinding.KeyModifiers,
IsEnabled = true
});
}
Key = (VirtualKey) viewModel.KeyBinding.Key,
Modifiers = (VirtualKeyModifiers) viewModel.KeyBinding.KeyModifiers,
IsEnabled = true
});
}
return item;
@@ -16,6 +16,8 @@ namespace FluentTerminal.App.Dialogs
// ReSharper disable once RedundantExtendsListEntry
public sealed partial class CreateKeyBindingDialog : ContentDialog, ICreateKeyBindingDialog, INotifyPropertyChanged
{
private readonly IAcceleratorKeyValidator _acceleratorKeyValidator;
private bool _ctrl;
private bool _shift;
private bool _alt;
@@ -51,12 +53,17 @@ namespace FluentTerminal.App.Dialogs
get => _key;
set
{
Set(ref _key, value);
// We're ignoring invalid keys.
if (_acceleratorKeyValidator.Valid(value))
{
Set(ref _key, value);
}
}
}
public CreateKeyBindingDialog()
public CreateKeyBindingDialog(IAcceleratorKeyValidator acceleratorKeyValidator)
{
_acceleratorKeyValidator = acceleratorKeyValidator;
InitializeComponent();
ResetCommand = new RelayCommand(Reset);
PreviewKeyDown += RegisterKeyBindingDialog_PreviewKeyDown;
+1 -9
View File
@@ -133,6 +133,7 @@
<Compile Include="Dialogs\AboutDialog.xaml.cs">
<DependentUpon>AboutDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Services\AcceleratorKeyValidator.cs" />
<Compile Include="Services\CommandHistoryService.cs" />
<Compile Include="Utilities\DelayedAction.cs" />
<Compile Include="Utilities\DispatcherExtensions.cs" />
@@ -436,15 +437,6 @@
<ItemGroup>
<PRIResource Include="Strings\zh-Hans\Resources.resw" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\fa\Resources.resw" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\hu\Resources.resw" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\tr\Resources.resw" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
@@ -0,0 +1,13 @@
using System;
using Windows.System;
using FluentTerminal.Models.Enums;
namespace FluentTerminal.App.Services
{
public class AcceleratorKeyValidator : IAcceleratorKeyValidator
{
public bool Valid(int key) => Enum.IsDefined(typeof(VirtualKey), key);
public bool Valid(ExtendedVirtualKey key) => Valid((int) key);
}
}
@@ -16,11 +16,9 @@ namespace FluentTerminal.App.Services
["de"] = "Deutsch",
["en"] = "English",
["es"] = "Español",
["fa"] = "فارسی",
["fr"] = "Français",
["he"] = "עברית",
["hi"] = "हिन्दुस्तानी",
["hu"] = "magyar",
["id"] = "Bahasa Indonesia",
["it"] = "Italiano",
["ja"] = "日本語",
@@ -30,10 +28,9 @@ namespace FluentTerminal.App.Services
["pt-BR"] = "Português-Brasil",
["ro"] = "Română",
["ru"] = "Pусский",
["tr"] = "Türkçe",
["uk"] = "Українська",
["zh-Hans"] = "简体中文",
["zh-Hant"] = "繁體中文"
["zh-Hans"] = "繁體中文",
["zh-Hant"] = "简体中文"
};
public IEnumerable<string> Languages => _languages.Values;
File diff suppressed because it is too large. Load diff
+5 -5
View File
@@ -1058,7 +1058,7 @@ Fuzzy</comment>
<value>Lancer une session dans une nouvelle fenêtre.</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Type de menu d&apos;application</value>
<value>Application menu type</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Plat, honorant le paramètre &quot;Ouvrir de nouveaux terminaux comme&quot;</value>
@@ -1106,12 +1106,12 @@ Fuzzy</comment>
<value>Copier la sélection ou coller</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Utiliser un tampon rapide</value>
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Redémarrer</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -1059,9 +1059,9 @@ Fuzzy</comment>
<value>Usa smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Riavvia</value>
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Sessione terminata.</value>
<value>Session disconnected.</value>
</data>
</root>
+12 -12
View File
@@ -1014,42 +1014,42 @@
<value>Activat de politică.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Imagine de fundal</value>
<value>Background image</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Folosiți fundal acrilic</value>
<value>Use acrylic background</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Sigur doriți să ștergeți această imagine de fundal?</value>
<value>Are you sure you want to delete this background image?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Culori</value>
<value>Colors</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Culori deschise</value>
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copiere link</value>
<value>Copy link</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>Regex</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>Întregul cuvânt</value>
<value>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Potrivire litere</value>
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copiați selecția sau lipiți</value>
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Folosiți tampon inteligent</value>
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Repornire</value>
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Sesiunea a fost deconectată.</value>
<value>Session disconnected.</value>
</data>
</root>
File diff suppressed because it is too large. Load diff
@@ -971,13 +971,13 @@ Fuzzy</comment>
<value>最近</value>
</data>
<data name="NewTab_Description" xml:space="preserve">
<value>在新标签打开默认配置。</value>
<value>Opens default profile in a new tab.</value>
</data>
<data name="NewSshTab_Description" xml:space="preserve">
<value>从新标签页打开SSH或Mosh会话</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>打开“快速启动”对话框并在新标签中开启会话。</value>
<value>Opens &quot;Quick Launch&quot; dialog and starts session in a new tab.</value>
</data>
<data name="Settings_Description" xml:space="preserve">
<value>打开设置页面</value>
@@ -989,19 +989,19 @@ Fuzzy</comment>
<value>最近打开的会话</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>基于默认配置开启新的终端会话。</value>
<value>Starts new terminal session based on the default profile.</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>远程连接</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>打开对话框开启新的 SSH 或 Mosh 终端会话。</value>
<value>Opens a dialog for launching a new SSH or Mosh terminal session.</value>
</data>
<data name="MenuItem_QuickLaunch_Text" xml:space="preserve">
<value>快捷启动</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>打开“快速启动”对话框并开启终端会话。</value>
<value>Opens a &quot;Quick Launch&quot; dialog for starting a new terminal session.</value>
</data>
<data name="MenuItem_NewWindow_Text" xml:space="preserve">
<value>新建窗口</value>
@@ -1016,13 +1016,13 @@ Fuzzy</comment>
<value>从新窗口启动会话</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>应用菜单类型</value>
<value>Application menu type</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>扁平,荣耀的“打开新的终端”设置</value>
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>“新标签”/“新窗口”级联菜单</value>
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>退出</value>
@@ -1031,16 +1031,16 @@ Fuzzy</comment>
<value>退出关于</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>根据策略启用。</value>
<value>Enabled by policy.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>背景图片</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>使用亚克力背景</value>
<value>Use acrylic background</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>你确定你想要删除这个背景图片吗?</value>
<value>Are you sure you want to delete this background image?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>颜色</value>
@@ -1055,13 +1055,13 @@ Fuzzy</comment>
<value>正则表达式</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>全字匹配</value>
<value>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>大小写敏感</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>复制或者粘贴选中的文本</value>
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
File diff suppressed because it is too large. Load diff
+15 -15
View File
@@ -1,19 +1,19 @@
<ResourceDictionary
x:Class="FluentTerminal.App.Views.TemplateSelectors"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="using:FluentTerminal.App.Views"
xmlns:models="using:FluentTerminal.Models"
xmlns:settings="using:FluentTerminal.App.ViewModels.Settings"
xmlns:views="using:FluentTerminal.App.Views">
xmlns:settings="using:FluentTerminal.App.ViewModels.Settings">
<views:TabThemeTemplateSelector x:Key="TabThemeTemplateSelector">
<views:TabThemeTemplateSelector.DefaultTemplate>
<DataTemplate x:DataType="models:TabTheme">
<StackPanel Orientation="Horizontal">
<FontIcon
Margin="0,0,6,0"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xF126;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay, Converter={StaticResource I18NConverter}}" />
Margin="0,0,6,0"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xF126;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</views:TabThemeTemplateSelector.DefaultTemplate>
@@ -21,11 +21,11 @@
<DataTemplate x:DataType="models:TabTheme">
<StackPanel Orientation="Horizontal">
<FontIcon
Margin="0,0,6,0"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Foreground="{x:Bind Color}"
Glyph="&#xF127;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay, Converter={StaticResource I18NConverter}}" />
Margin="0,0,6,0"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Foreground="{x:Bind Color}"
Glyph="&#xF127;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</views:TabThemeTemplateSelector.ColoredTemplate>
@@ -51,9 +51,9 @@
<views:TerminalKeybindTemplateSelector.KeyBindingsTemplate>
<DataTemplate x:DataType="settings:KeyBindingsViewModel">
<views:KeyBindingsView
Margin="0,6,0,0"
ShowCommandName="False"
ViewModel="{x:Bind}" />
Margin="0,6,0,0"
ShowCommandName="False"
ViewModel="{x:Bind}" />
</DataTemplate>
</views:TerminalKeybindTemplateSelector.KeyBindingsTemplate>
</views:TerminalKeybindTemplateSelector>
+1 -1
View File
@@ -35,7 +35,7 @@
Width="16"
Height="16"
Margin="6,0,0,0">
<SymbolIcon Symbol="Find" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xF78B;" />
</Viewbox>
<TextBox
Name="SearchTextBox"
File diff suppressed because it is too large. Load diff
+9 -9
View File
@@ -5,22 +5,22 @@
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "xcopy /y /s node_modules\\xterm\\css\\xterm.css dist\\ && xcopy /y /s src\\style.css dist\\ && xcopy /y /s src\\index.html dist\\ && npx webpack --config webpack.config.js"
"build": "xcopy /y /s node_modules\\xterm\\css\\xterm.css dist\\ && xcopy /y /s src\\style.css dist\\ && xcopy /y /s src\\index.html dist\\ && cd node_modules/xterm && yarn && yarn package && cd ../.. && npx webpack --config webpack.config.js"
},
"author": "FS Apps",
"license": "GPL-3.0",
"devDependencies": {
"ts-loader": "^6.2.2",
"typescript": "^3.8.3",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
"ts-loader": "^6.0.2",
"typescript": "^3.5.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3"
},
"dependencies": {
"xterm": "^4.5.0",
"xterm": "felixse/xterm.js#fix-edge-selection-color",
"xterm-addon-fit": "^0.3.0",
"xterm-addon-search": "^0.6.0",
"xterm-addon-serialize": "^0.2.0",
"xterm-addon-search": "^0.5.0",
"xterm-addon-serialize": "^0.1.2",
"xterm-addon-unicode11": "^0.1.1",
"xterm-addon-web-links": "^0.3.0"
"xterm-addon-web-links": "^0.2.1"
}
}
+1 -9
View File
@@ -29,7 +29,6 @@ let searchAddon: SearchAddon;
let serializeAddon: SerializeAddon;
let webLinksAddon: WebLinksAddon;
let unicode11Addon: Unicode11Addon;
let altGrPressed = false;
const terminalContainer = document.getElementById('terminal-container');
@@ -166,16 +165,9 @@ window.createTerminal = (options, theme, keyBindings) => {
});
term.attachCustomKeyEventHandler(function (e) {
if (e.altKey && e.type === "keydown" && e.location === 2) {
altGrPressed = true;
} else if (e.altKey && e.type === "keyup" && e.key === "Control") {
altGrPressed = false
}
if (e.type != "keydown" || altGrPressed) {
if (e.type != "keydown") {
return true;
}
for (var i = 0; i < window.keyBindings.length; i++) {
var keyBinding = window.keyBindings[i];
if (keyBinding.ctrl == e.ctrlKey
File diff suppressed because it is too large. Load diff
+1 -2
View File
@@ -20,7 +20,6 @@
GetCommandPathRequest = 15,
PauseTerminalOutputRequest = 16,
PauseTerminalOutputResponse = 17,
QuitApplicationRequest = 18,
ReadTextFileRequest = 19
QuitApplicationRequest = 18
}
}
@@ -1,9 +0,0 @@
namespace FluentTerminal.Models.Requests
{
public class ReadTextFileRequest : IMessage
{
public byte Identifier => (byte)MessageIdentifiers.ReadTextFileRequest;
public string Path { get; set; }
}
}
@@ -1,7 +1,11 @@
namespace FluentTerminal.Models.Responses
{
public class CommonResponse : TerminalResponse
public class CommonResponse : IMessage
{
public override byte Identifier => (byte) MessageIdentifiers.CommonResponse;
public virtual byte Identifier => (byte) MessageIdentifiers.CommonResponse;
public bool Success { get; set; }
public string Error { get; set; }
}
}
@@ -1,8 +1,8 @@
namespace FluentTerminal.Models.Responses
{
public class CreateTerminalResponse : TerminalResponse
public class CreateTerminalResponse : TerminalResponse, IMessage
{
public override byte Identifier => (byte) MessageIdentifiers.CreateTerminalResponse;
public byte Identifier => (byte) MessageIdentifiers.CreateTerminalResponse;
public string Name { get; set; }
}
@@ -1,7 +1,7 @@
namespace FluentTerminal.Models.Responses
{
public class PauseTerminalOutputResponse : TerminalResponse
public class PauseTerminalOutputResponse : TerminalResponse, IMessage
{
public override byte Identifier => (byte) MessageIdentifiers.PauseTerminalOutputResponse;
public byte Identifier => (byte) MessageIdentifiers.PauseTerminalOutputResponse;
}
}
@@ -1,8 +1,11 @@
namespace FluentTerminal.Models.Responses
using System;
using System.Collections.Generic;
using System.Text;
namespace FluentTerminal.Models.Responses
{
public abstract class TerminalResponse : IMessage
public class TerminalResponse
{
public abstract byte Identifier { get; }
public bool Success { get; set; }
public string Error { get; set; }
}
@@ -59,7 +59,6 @@
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateKeyFile>FluentTerminal.App_StoreKey.pfx</PackageCertificateKeyFile>
<EntryPointProjectUniqueName>$(SolutionDir)FluentTerminal.App\FluentTerminal.App.csproj</EntryPointProjectUniqueName>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
@@ -67,7 +66,8 @@
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<PackageCertificateThumbprint>8A5DE5B20B663BD6A99B44C5BA278289521F419F</PackageCertificateThumbprint>
<PackageCertificateThumbprint>9E39FAC27F1AEA1BAC9BCF60FF29B32B354E0E93</PackageCertificateThumbprint>
<AppxPackageSigningTimestampServerUrl>http://timestamp.comodoca.com</AppxPackageSigningTimestampServerUrl>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<AppxBundle>Always</AppxBundle>
+1 -1
View File
@@ -8,7 +8,7 @@
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="uap rescap desktop">
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=BDC72197-B634-438A-B863-16DCB7D90C85" Version="0.7.0.0" />
<Identity Name="53621FSApps.FluentTerminal" Publisher="CN=Felix Seidl, O=Felix Seidl, STREET=Kapellenstr. 4, L=Nürnberg, S=Bayern, PostalCode=90478, C=DE" Version="0.7.0.0" />
<Properties>
<DisplayName>Fluent Terminal</DisplayName>
+1 -1
View File
@@ -1,3 +1,3 @@
<default>
<qualifier name="Language" value="ar;ar-IQ;az;de;en;es;fa;fr;he;hi;hu;id;it;ja;ko;nl;pl;pt-BR;ro;ru;tr;uk;zh-Hans;zh-Hant" />
<qualifier name="Language" value="ar;ar-IQ;az;de;en;es;fr;he;hi;id;it;ja;ko;nl;pl;pt-BR;ro;ru;uk;zh-Hans;zh-Hant" />
</default>
@@ -53,9 +53,6 @@ namespace FluentTerminal.SystemTray
{
while (true)
{
// Allow CPU to jump between TerminalSessions' ReadingLoop Tasks
await Task.Delay(1).ConfigureAwait(false);
bool paused;
lock (_lock)
@@ -134,9 +134,6 @@ namespace FluentTerminal.SystemTray.Services
case MessageIdentifiers.QuitApplicationRequest:
HandleQuitApplicationRequest();
return;
case MessageIdentifiers.ReadTextFileRequest:
await HandleReadTextFileRequestAsync(args).ConfigureAwait(false);
return;
default:
Logger.Instance.Error("Received unknown message type: {messageType}", messageType);
return;
@@ -217,31 +214,6 @@ namespace FluentTerminal.SystemTray.Services
deferral.Complete();
}
private async Task HandleReadTextFileRequestAsync(AppServiceRequestReceivedEventArgs args)
{
var deferreal = args.GetDeferral();
var deferral = args.GetDeferral();
var messageContent = (string)args.Request.Message[MessageKeys.Content];
var request = JsonConvert.DeserializeObject<ReadTextFileRequest>(messageContent);
var response = new StringValueResponse();
try
{
var content = Utilities.ReadFile(request.Path);
response.Success = true;
response.Value = content;
}
catch (Exception e)
{
response.Success = false;
response.Error = e.Message;
}
await args.Request.SendResponseAsync(CreateMessage(response));
deferral.Complete();
}
private async Task HandleGetSshConfigFolderRequestAsync(AppServiceRequestReceivedEventArgs args)
{
var deferral = args.GetDeferral();
@@ -91,11 +91,6 @@ namespace FluentTerminal.SystemTray.Services.ConPty
_reader?.SetPaused(value);
}
~ConPtySession()
{
Dispose(false);
}
#region IDisposable Support
private bool _disposed;
@@ -118,7 +113,6 @@ namespace FluentTerminal.SystemTray.Services.ConPty
public void Dispose()
{
_terminal.Exited -= _terminal_Exited;
_terminal.OutputReady -= _terminal_OutputReady;
Dispose(true);
}
@@ -42,19 +42,10 @@ namespace FluentTerminal.SystemTray.Services.ConPty
ResizePseudoConsole(Handle, new COORD { X = (short)width, Y = (short)height });
}
private bool alreadyDisposed = false;
public void Dispose()
{
if (alreadyDisposed)
{
return;
}
ClosePseudoConsole(Handle);
GC.SuppressFinalize(this);
alreadyDisposed = true;
}
}
}
@@ -175,12 +175,9 @@ namespace FluentTerminal.SystemTray.Services.ConPty
if (disposeManaged)
{
ConsoleOutStream.Dispose();
// Dispose pseudo console before _consoleInputWriter to avoid
// hanging on call of ClosePseudoConsole
_pseudoConsole?.Dispose();
_consoleInputWriter?.Dispose();
_process?.Dispose();
_pseudoConsole?.Dispose();
_outputPipe?.Dispose();
_inputPipe?.Dispose();
}
-5
View File
@@ -536,11 +536,6 @@ namespace FluentTerminal.SystemTray
}
}
internal static string ReadFile(string path)
{
return File.ReadAllText(path);
}
private static bool? MuteProcess(int id, bool mute, bool force = false)
{
bool? isAudioSessionMuted = VolumeControl.GetAudioSessionMute(id);
+2
View File
@@ -68,6 +68,8 @@ Sign up to [POEditor](https://poeditor.com/join/project/TfKNIt826z) to help with
- From an elevated/admin shell, execute `choco install fluent-terminal`
### Scoop package manager installation
- [Enable sideloading apps](https://www.windowscentral.com/how-enable-windows-10-sideload-apps-outside-store)
- Alternatively, [enable developer mode](https://docs.microsoft.com/en-US/windows/uwp/get-started/enable-your-device-for-development) if you plan to do UWP app development. **For most users that do not intend to do UWP app development, developer mode will not be necessary.**
- Install Scoop
- Install 7zip and git (to add buckets): `scoop install 7zip git`
- From an elevated/admin shell, execute
+2 -5
View File
@@ -24,8 +24,7 @@ function DownloadLanguageFile($language, $directory)
}
DownloadLanguageFile "en"
DownloadLanguageFile "zh-TW" "zh-Hant"
DownloadLanguageFile "zh-Hans"
DownloadLanguageFile "zh-CN" "zh-Hant"
DownloadLanguageFile "de"
DownloadLanguageFile "es"
DownloadLanguageFile "fr"
@@ -44,6 +43,4 @@ DownloadLanguageFile "ko"
DownloadLanguageFile "az"
DownloadLanguageFile "ar"
DownloadLanguageFile "id"
DownloadLanguageFile "fa"
DownloadLanguageFile "tr"
DownloadLanguageFile "hu"
DownloadLanguageFile "zh-Hans"