Compare commits

..
233 changed files with 3689 additions and 9935 deletions

No files matched your search

+2 -2
View File
@@ -13,8 +13,8 @@ jobs:
- name: Build client
working-directory: ./FluentTerminal.Client
run: |
yarn
yarn build
npm install
npm run build
- name: Setup MSBuild.exe
uses: warrenbuckley/Setup-MSBuild@v1
@@ -23,7 +23,7 @@ namespace FluentTerminal.App.Services.Test
public void ShowCreateKeyBindingDialog_Default_UsesCreateKeyBindingDialog()
{
var createKeyBindingDialog = new Mock<ICreateKeyBindingDialog>();
var dialogService = new DialogService(Mock.Of<IMessageDialog>, () => createKeyBindingDialog.Object, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, () => createKeyBindingDialog.Object, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
dialogService.ShowCreateKeyBindingDialog();
@@ -36,7 +36,7 @@ namespace FluentTerminal.App.Services.Test
var title = string.Empty;
var content = _fixture.Create<string>();
var buttons = _fixture.CreateMany<DialogButton>(2);
var dialogService = new DialogService(Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
Func<Task<DialogButton>> showMessageDialogAsnyc = () => dialogService.ShowMessageDialogAsync(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
@@ -49,7 +49,7 @@ namespace FluentTerminal.App.Services.Test
var title = _fixture.Create<string>();
var content = string.Empty;
var buttons = _fixture.CreateMany<DialogButton>(2);
var dialogService = new DialogService(Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
Func<Task<DialogButton>> showMessageDialogAsnyc = () => dialogService.ShowMessageDialogAsync(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
@@ -61,7 +61,7 @@ namespace FluentTerminal.App.Services.Test
{
var title = _fixture.Create<string>();
var content = _fixture.Create<string>();
var dialogService = new DialogService(Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
Func<Task<DialogButton>> showMessageDialogAsnyc = () => dialogService.ShowMessageDialogAsync(title, content);
@@ -75,19 +75,30 @@ namespace FluentTerminal.App.Services.Test
var content = _fixture.Create<string>();
var buttons = _fixture.CreateMany<DialogButton>(2);
var messageDialog = new Mock<IMessageDialog>();
var dialogService = new DialogService(() => messageDialog.Object, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, () => messageDialog.Object, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
dialogService.ShowMessageDialogAsync(title, content, buttons.ElementAt(0), buttons.ElementAt(1));
messageDialog.Verify(x => x.ShowAsync(), Times.Once);
}
[Fact]
public void ShowProfileSelectionDialogAsync_Default_UsesShellProfileSelectionDialog()
{
var shellProfileSelectionDialog = new Mock<IShellProfileSelectionDialog>();
var dialogService = new DialogService(() => shellProfileSelectionDialog.Object, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
dialogService.ShowProfileSelectionDialogAsync();
shellProfileSelectionDialog.Verify(x => x.SelectProfileAsync(), Times.Once);
}
[Fact]
public void ShowInputDialogAsync_UsesIInputDialogSetTitle()
{
var title = "title";
var inputDialog = new Mock<IInputDialog>();
var dialogService = new DialogService(Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, () => inputDialog.Object, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, () => inputDialog.Object, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
dialogService.ShowInputDialogAsync(title);
@@ -0,0 +1,12 @@
using FluentTerminal.Models;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Dialogs
{
public interface IShellProfileSelectionDialog
{
ShellProfile SelectedProfile { get; }
Task<ShellProfile> SelectProfileAsync();
}
}
@@ -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);
}
}
@@ -14,8 +14,9 @@ namespace FluentTerminal.App.Services
{
Task<DialogButton> ShowMessageDialogAsync(string title, string content, params DialogButton[] buttons);
Task<KeyBinding> ShowCreateKeyBindingDialog();
Task<ShellProfile> ShowProfileSelectionDialogAsync();
Task<KeyBinding> ShowCreateKeyBindingDialog();
Task<string> ShowInputDialogAsync(string title);
Task<SshProfile> ShowSshConnectionInfoDialogAsync(SshProfile input = null);
@@ -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;
@@ -41,8 +42,7 @@ namespace FluentTerminal.App.Services.Implementation
EnableLogging = false,
PrintableOutputOnly = true,
LogDirectoryPath = logDirectoryPath,
UseConPty = true,
ShowTextCopied = false
UseConPty = true
};
}
@@ -114,18 +114,6 @@ namespace FluentTerminal.App.Services.Implementation
}
};
case Command.ReconnectTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = nameof(Command.ReconnectTab),
Ctrl = true,
Alt = true,
Key = (int)ExtendedVirtualKey.R
}
};
case Command.NewTab:
return new List<KeyBinding>
{
@@ -138,6 +126,18 @@ namespace FluentTerminal.App.Services.Implementation
}
};
case Command.ConfigurableNewTab:
return new List<KeyBinding>
{
new KeyBinding
{
Command = nameof(Command.ConfigurableNewTab),
Ctrl = true,
Alt = true,
Key = (int)ExtendedVirtualKey.T
}
};
case Command.NewSshTab:
return new List<KeyBinding>
{
@@ -169,8 +169,8 @@ namespace FluentTerminal.App.Services.Implementation
{
Command = nameof(Command.NewCustomCommandTab),
Ctrl = true,
Alt = true,
Key = (int)ExtendedVirtualKey.T
Shift = true,
Key = (int)ExtendedVirtualKey.Q
}
};
@@ -182,7 +182,7 @@ namespace FluentTerminal.App.Services.Implementation
Command = nameof(Command.NewCustomCommandWindow),
Ctrl = true,
Alt = true,
Key = (int)ExtendedVirtualKey.N
Key = (int)ExtendedVirtualKey.Q
}
};
@@ -222,6 +222,18 @@ namespace FluentTerminal.App.Services.Implementation
}
};
case Command.ConfigurableNewWindow:
return new List<KeyBinding>
{
new KeyBinding
{
Command = nameof(Command.ConfigurableNewWindow),
Ctrl = true,
Alt = true,
Key = (int)ExtendedVirtualKey.N
}
};
case Command.ShowSettings:
return new List<KeyBinding>
{
@@ -230,7 +242,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 +353,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 +364,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"
}
};
@@ -424,8 +437,8 @@ namespace FluentTerminal.App.Services.Implementation
Location = @"C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe",
PreInstalled = true,
WorkingDirectory = string.Empty,
LineEndingTranslation = LineEndingStyle.DoNotModify,
UseConPty = ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8), // Windows 10 1903+
UseBuffer = false,
EnvironmentVariables = new Dictionary<string, string>
{
["TERM"] = "xterm-256color"
@@ -452,8 +465,8 @@ namespace FluentTerminal.App.Services.Implementation
Location = @"C:\Windows\System32\cmd.exe",
PreInstalled = true,
WorkingDirectory = string.Empty,
LineEndingTranslation = LineEndingStyle.DoNotModify,
UseConPty = ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7), // Windows 10 1809+
UseBuffer = true,
EnvironmentVariables = new Dictionary<string, string>
{
["TERM"] = "xterm-256color"
@@ -480,8 +493,8 @@ namespace FluentTerminal.App.Services.Implementation
Location = @"C:\windows\system32\wsl.exe",
PreInstalled = true,
WorkingDirectory = string.Empty,
LineEndingTranslation = LineEndingStyle.ToLF,
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<string, string>
{
["TERM"] = "xterm-256color"
@@ -7,6 +7,7 @@ namespace FluentTerminal.App.Services.Implementation
{
public class DialogService : IDialogService
{
private readonly Func<IShellProfileSelectionDialog> _shellProfileSelectionDialogFactory;
private readonly Func<IMessageDialog> _messageDialogFactory;
private readonly Func<ICreateKeyBindingDialog> _createKeyBindingDialogFactory;
private readonly Func<IInputDialog> _inputDialogFactory;
@@ -14,11 +15,13 @@ namespace FluentTerminal.App.Services.Implementation
private readonly Func<ICustomCommandDialog> _customCommandDialogFactory;
private readonly Func<IAboutDialog> _aboutDialogFactory;
public DialogService(Func<IMessageDialog> messageDialogFactory, Func<ICreateKeyBindingDialog> createKeyBindingDialogFactory,
public DialogService(Func<IShellProfileSelectionDialog> shellProfileSelectionDialogFactory,
Func<IMessageDialog> messageDialogFactory, Func<ICreateKeyBindingDialog> createKeyBindingDialogFactory,
Func<IInputDialog> inputDialogFactory, Func<ISshConnectionInfoDialog> sshConnectionInfoDialogFactory,
Func<ICustomCommandDialog> customCommandDialogFactory,
Func<IAboutDialog> aboutDialogFactory)
{
_shellProfileSelectionDialogFactory = shellProfileSelectionDialogFactory;
_messageDialogFactory = messageDialogFactory;
_createKeyBindingDialogFactory = createKeyBindingDialogFactory;
_inputDialogFactory = inputDialogFactory;
@@ -71,6 +74,13 @@ namespace FluentTerminal.App.Services.Implementation
return dialog.GetInput();
}
public Task<ShellProfile> ShowProfileSelectionDialogAsync()
{
var dialog = _shellProfileSelectionDialogFactory();
return dialog.SelectProfileAsync();
}
public Task<SshProfile> ShowSshConnectionInfoDialogAsync(SshProfile input = null) =>
_sshConnectionInfoDialogFactory().GetSshConnectionInfoAsync(input);
@@ -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,22 @@ 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.LineEndingTranslation = profile.LineEndingTranslation;
existingProfile.KeyBindings = profile.KeyBindings;
SaveShellProfile(profile, isNew);
continue;
}
SaveShellProfile(profile, isNew);
@@ -137,7 +141,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))
+1 -11
View File
@@ -24,12 +24,6 @@ namespace FluentTerminal.App.Services
_requireShellProcessStart = !terminalId.HasValue;
}
public void Reconnect()
{
_exited = false;
_trayProcessCommunicationService.TerminalExited += OnTerminalExited;
}
private void OnTerminalExited(object sender, TerminalExitStatus status)
{
if (status.TerminalId != Id)
@@ -77,8 +71,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 +137,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));
@@ -161,7 +151,7 @@ namespace FluentTerminal.App.Services
if (response.Success)
{
_fallbackTitle = response.Name;
_fallbackTitle = response.ShellExecutableName;
SetTitle(_fallbackTitle);
}
return response;
@@ -10,12 +10,11 @@ namespace FluentTerminal.App.ViewModels
Task ChangeKeyBindingsAsync();
Task ChangeOptionsAsync(TerminalOptions options);
Task InitializeAsync(TerminalViewModel viewModel);
Task ReconnectAsync();
void DisposalPrepare();
Task FindNextAsync(SearchRequest request);
Task FindPreviousAsync(SearchRequest request);
Task FindNextAsync(string searchText);
Task FindPreviousAsync(string searchText);
Task FocusTerminalAsync();
Task<string> SerializeXtermStateAsync();
void Paste(string text);
Task PasteAsync(string text);
}
}
File diff suppressed because it is too large. Load diff
@@ -5,11 +5,11 @@ using GalaSoft.MvvmLight;
namespace FluentTerminal.App.ViewModels.Menu
{
public class MenuViewModel : ViewModelBase
public class AppMenuViewModel : ViewModelBase
{
public ObservableCollection<MenuItemViewModelBase> Items { get; }
public MenuViewModel(IEnumerable<MenuItemViewModelBase> items = null)
public AppMenuViewModel(IEnumerable<MenuItemViewModelBase> items = null)
{
if (items == null)
{
@@ -25,7 +25,7 @@ namespace FluentTerminal.App.ViewModels.Menu
}
}
public bool EquivalentTo(MenuViewModel other)
public bool EquivalentTo(AppMenuViewModel other)
{
if (ReferenceEquals(this, other)) return true;
@@ -9,7 +9,7 @@ namespace FluentTerminal.App.ViewModels.Menu
public ObservableCollection<MenuItemViewModelBase> SubItems { get; }
public ExpandableMenuItemViewModel(string text, IEnumerable<MenuItemViewModelBase> subItems = null,
string description = null, Mdl2Icon icon = null) : base(text, description, icon)
string description = null, object icon = null) : base(text, description, icon)
{
if (subItems == null)
{
@@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FluentTerminal.App.ViewModels.Menu
{
public sealed class Mdl2Icon
{
public string Color { get; }
public string Glyph { get; }
private Mdl2Icon(string glyph, string color = null)
{
Glyph = glyph;
Color = color;
}
public static Mdl2Icon Link(string color = null) => new Mdl2Icon("\uE71B", color);
public static Mdl2Icon Copy(string color = null) => new Mdl2Icon("\uE8C8", color);
public static Mdl2Icon Paste(string color = null) => new Mdl2Icon("\uE77F", color);
public static Mdl2Icon Edit(string color = null) => new Mdl2Icon("\uE70F", color);
public static Mdl2Icon Search(string color = null) => new Mdl2Icon("\uE721", color);
public static Mdl2Icon Add(string color = null) => new Mdl2Icon("\uE710", color);
public static Mdl2Icon Cancel(string color = null) => new Mdl2Icon("\uE711", color);
public static Mdl2Icon PaginationDotOutline10(string color = null) => new Mdl2Icon("\uF126", color);
public static Mdl2Icon PaginationDotSolid10(string color = null) => new Mdl2Icon("\uF127", color);
public static Mdl2Icon NewWindow(string color = null) => new Mdl2Icon("\uE78B", color);
public static Mdl2Icon History(string color = null) => new Mdl2Icon("\uE81C", color);
public static Mdl2Icon Settings(string color = null) => new Mdl2Icon("\uE713", color);
public static Mdl2Icon Info(string color = null) => new Mdl2Icon("\uE946", color);
public static Mdl2Icon FavoriteStar(string color = null) => new Mdl2Icon("\uE734", color);
public static Mdl2Icon Globe(string color = null) => new Mdl2Icon("\uE774", color);
public static Mdl2Icon Play(string color = null) => new Mdl2Icon("\uE768", color);
}
}
@@ -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
}
}
@@ -21,7 +21,7 @@ namespace FluentTerminal.App.ViewModels.Menu
#region Constructors
public MenuItemViewModel(string text, ICommand command, string description = null, Mdl2Icon icon = null,
public MenuItemViewModel(string text, ICommand command, string description = null, object icon = null,
MenuItemKeyBindingViewModel keyBinding = null) : base(text, description, icon)
{
_keyBinding = keyBinding;
@@ -23,9 +23,32 @@ namespace FluentTerminal.App.ViewModels.Menu
set => Set(ref _description, value);
}
private Mdl2Icon _icon;
private object _icon;
public Mdl2Icon Icon
/// <summary>
/// Defines menu item icon.
/// </summary>
/// <remarks>
/// Acceptable values of this property are:
/// <list type="bullet">
/// <item><see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.iconelement">IconElement</see>
/// (usually <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.symbolicon">SymbolIcon</see>
/// or <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.fonticon">FontIcon</see>);</item>
/// <item><see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.symbol">Symbol</see> enum value,
/// which will be used for creating
/// <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.symbolicon">SymbolIcon</see>;</item>
/// <item><see cref="int"/>, in which case it'll be converted to
/// <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.symbol">Symbol</see> enum value;</item>
/// <item><see cref="string"/>, in which case a new
/// <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.fonticon">FontIcon</see> instance will
/// be created, whose
/// <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.fonticon.glyph">Glyph</see> property
/// will be set to the value of this property.
/// <see cref="!:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.fonticon.fontfamily">FontFamily</see>
/// property of the newly created instance will be set to <c>"Segoe MDL2 Assets"</c>.</item>
/// </list>
/// </remarks>
public object Icon
{
get => _icon;
set => Set(ref _icon, value);
@@ -35,7 +58,7 @@ namespace FluentTerminal.App.ViewModels.Menu
#region Constructor
protected MenuItemViewModelBase(string text, string description, Mdl2Icon icon)
protected MenuItemViewModelBase(string text, string description, object icon)
{
_text = text;
_description = description;
@@ -1,28 +0,0 @@
using System;
namespace FluentTerminal.App.ViewModels.Menu
{
public class RadioMenuItemViewModel : MenuItemViewModelBase
{
public object BindingSource { get; }
public string BindingPath { get; }
public string GroupName { get; }
public RadioMenuItemViewModel(string text, string groupName, object bindingSource, string bindingPath = null, string description = null, Mdl2Icon icon = null)
: base(text, description, icon)
{
GroupName = groupName ?? throw new ArgumentNullException(nameof(groupName));
BindingSource = bindingSource ?? throw new ArgumentNullException(nameof(bindingSource));
BindingPath = bindingPath;
}
public override bool EquivalentTo(MenuItemViewModelBase other)
{
if (!base.EquivalentTo(other)) return false;
if (!(other is RadioMenuItemViewModel radioMenuItem)) return false;
return GroupName == radioMenuItem.GroupName && BindingSource == radioMenuItem.BindingSource && BindingPath == radioMenuItem.BindingPath;
}
}
}
@@ -1,26 +0,0 @@
using System;
namespace FluentTerminal.App.ViewModels.Menu
{
public class ToggleMenuItemViewModel : MenuItemViewModelBase
{
public object BindingSource { get; }
public string BindingPath { get; }
public ToggleMenuItemViewModel(string text, object bindingSource, string bindingPath = null, string description = null, Mdl2Icon icon = null)
: base(text, description, icon)
{
BindingSource = bindingSource ?? throw new ArgumentNullException(nameof(bindingSource));
BindingPath = bindingPath;
}
public override bool EquivalentTo(MenuItemViewModelBase other)
{
if (!base.EquivalentTo(other)) return false;
if (!(other is ToggleMenuItemViewModel toggleMenuItem)) return false;
return BindingSource == toggleMenuItem.BindingSource && BindingPath == toggleMenuItem.BindingPath;
}
}
}
@@ -7,6 +7,7 @@ using System.Web;
using Windows.UI.Core;
using FluentTerminal.App.Services;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using FluentTerminal.Models.Messages;
using GalaSoft.MvvmLight;
@@ -18,6 +19,13 @@ namespace FluentTerminal.App.ViewModels.Profiles
/// </summary>
public abstract class ProfileProviderViewModelBase : ViewModelBase
{
#region Static
private static readonly LineEndingStyle[] LineEndingStylesArray =
Enum.GetValues(typeof(LineEndingStyle)).Cast<LineEndingStyle>().ToArray();
#endregion Static
#region Fields
protected readonly ISettingsService SettingsService;
@@ -60,6 +68,17 @@ namespace FluentTerminal.App.ViewModels.Profiles
public ObservableCollection<TerminalTheme> TerminalThemes { get; }
public ObservableCollection<LineEndingStyle> LineEndingStyles { get; } =
new ObservableCollection<LineEndingStyle>(LineEndingStylesArray);
private LineEndingStyle _lineEndingTranslation;
public LineEndingStyle LineEndingTranslation
{
get => _lineEndingTranslation;
set => Set(ref _lineEndingTranslation, value);
}
private TabTheme _selectedTabTheme;
public TabTheme SelectedTabTheme
@@ -111,7 +130,13 @@ namespace FluentTerminal.App.ViewModels.Profiles
if (theme == null)
{
return;
// How to handle attempt to setting null theme?
// 1) Throw an exception:
//throw new ArgumentNullException();
// 2) Ignore the attempt:
//return;
// 3) Use default theme (probably the best):
theme = TerminalThemes.First();
}
else if (!TerminalThemes.Contains(theme))
{
@@ -148,14 +173,6 @@ 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
@@ -216,8 +233,8 @@ namespace FluentTerminal.App.ViewModels.Profiles
private void Initialize(ShellProfile profile)
{
LineEndingTranslation = profile.LineEndingTranslation;
UseConPty = profile.UseConPty;
UseBuffer = profile.UseBuffer;
TerminalThemeId = profile.TerminalThemeId;
TabThemeId = profile.TabThemeId;
}
@@ -229,8 +246,8 @@ namespace FluentTerminal.App.ViewModels.Profiles
protected virtual Task CopyToProfileAsync(ShellProfile profile)
{
profile.LineEndingTranslation = _lineEndingTranslation;
profile.UseConPty = _useConPty;
profile.UseBuffer = _useBuffer;
profile.TerminalThemeId = _terminalThemeId;
profile.TabThemeId = _tabThemeId;
return Task.CompletedTask;
@@ -247,8 +264,8 @@ namespace FluentTerminal.App.ViewModels.Profiles
/// </summary>
public virtual bool HasChanges()
{
return Model.UseConPty != _useConPty ||
Model.UseBuffer != _useBuffer ||
return Model.LineEndingTranslation != _lineEndingTranslation ||
Model.UseConPty != _useConPty ||
!Model.TerminalThemeId.Equals(_terminalThemeId) ||
Model.TabThemeId != _tabThemeId;
}
@@ -284,7 +301,7 @@ namespace FluentTerminal.App.ViewModels.Profiles
#region Links/shortcuts related
private const string UseConPtyQueryStringName = "conpty";
private const string UseBufferQueryStringName = "buffer";
private const string LineEndingQueryStringName = "lineending";
private const string TerminalThemeIdQueryStringName = "theme";
private const string TabThemeIdQueryStringName = "tab";
@@ -324,7 +341,8 @@ URL={0}
public string GetBaseQueryString()
{
var queryString = $"{UseConPtyQueryStringName}={_useConPty}&{UseBufferQueryStringName}={_useBuffer}";
var queryString =
$"{UseConPtyQueryStringName}={_useConPty}&{LineEndingQueryStringName}={_lineEndingTranslation}";
if (_tabThemeId != TabThemes.First().Id)
{
@@ -355,11 +373,11 @@ URL={0}
}
keyValue = queryStringParams.FirstOrDefault(t =>
UseBufferQueryStringName.Equals(t.Item1, StringComparison.OrdinalIgnoreCase));
LineEndingQueryStringName.Equals(t.Item1, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(keyValue?.Item2) && bool.TryParse(keyValue.Item2?.ToLower(), out bool useBuffer))
if (!string.IsNullOrEmpty(keyValue?.Item2) && Enum.TryParse(keyValue.Item2, true, out LineEndingStyle lineEndingTranslation))
{
UseConPty = useBuffer;
LineEndingTranslation = lineEndingTranslation;
}
keyValue = queryStringParams.FirstOrDefault(t =>
@@ -199,8 +199,8 @@ namespace FluentTerminal.App.ViewModels.Profiles
}
return _sshPort == SshProfile.DefaultSshPort
? $"-i \"{_identityFile}\""
: $"-p {_sshPort:#####} -i \"{_identityFile}\"";
? $"-i '{_identityFile}'"
: $"-p {_sshPort:#####} -i '{_identityFile}'";
}
protected override void LoadFromProfile(ShellProfile profile)
@@ -391,20 +391,6 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
public bool ShowTextCopied
{
get => _applicationSettings.ShowTextCopied;
set
{
if (_applicationSettings.ShowTextCopied != value)
{
_applicationSettings.ShowTextCopied = value;
_settingsService.SaveApplicationSettings(_applicationSettings);
RaisePropertyChanged();
}
}
}
// Requires UI thread
private async Task RestoreDefaultsAsync()
{
@@ -432,7 +418,6 @@ namespace FluentTerminal.App.ViewModels.Settings
PrintableOutputOnly = defaults.PrintableOutputOnly;
LogDirectoryPath = defaults.LogDirectoryPath;
UseConPty = defaults.UseConPty;
ShowTextCopied = defaults.ShowTextCopied;
}
}
@@ -71,12 +71,6 @@ namespace FluentTerminal.App.ViewModels.Settings
set { if (value) MouseRightClickAction = MouseAction.Paste; }
}
public bool MouseRightClickCopySelectionOrPasteIsSelected
{
get => MouseRightClickAction == MouseAction.CopySelectionOrPaste;
set { if (value) MouseRightClickAction = MouseAction.CopySelectionOrPaste; }
}
public MouseAction MouseMiddleClickAction
{
get => _applicationSettings.MouseMiddleClickAction;
@@ -109,12 +103,6 @@ namespace FluentTerminal.App.ViewModels.Settings
set { if (value) MouseMiddleClickAction = MouseAction.Paste; }
}
public bool MouseMiddleClickCopySelectionOrPasteIsSelected
{
get => MouseMiddleClickAction == MouseAction.CopySelectionOrPaste;
set { if (value) MouseMiddleClickAction = MouseAction.CopySelectionOrPaste; }
}
public RelayCommand RestoreDefaultsCommand { get; }
// Requires UI thread
@@ -178,6 +178,20 @@ namespace FluentTerminal.App.ViewModels.Settings
}
}
public bool ShowTextCopied
{
get => _terminalOptions.ShowTextCopied;
set
{
if (_terminalOptions.ShowTextCopied != value)
{
_terminalOptions.ShowTextCopied = value;
_settingsService.SaveTerminalOptions(_terminalOptions);
RaisePropertyChanged();
}
}
}
public IEnumerable<FontInfo> Fonts { get; }
public int FontSize
@@ -245,6 +259,7 @@ namespace FluentTerminal.App.ViewModels.Settings
FontWeight = defaults.FontWeight;
BackgroundOpacity = defaults.BackgroundOpacity;
ScrollBackLimit = defaults.ScrollBackLimit.ToString();
ShowTextCopied = defaults.ShowTextCopied;
WordSeparator = defaults.WordSeparator;
}
}
@@ -1,31 +0,0 @@
using FluentTerminal.Models;
using GalaSoft.MvvmLight;
namespace FluentTerminal.App.ViewModels
{
public class TabThemeViewModel : ViewModelBase
{
private bool _isSelected;
public TabThemeViewModel(TabTheme theme, TerminalViewModel terminal)
{
Theme = theme;
Terminal = terminal;
}
public bool IsSelected
{
get => _isSelected;
set
{
if (Set(ref _isSelected, value) && value)
{
Terminal.TabTheme = this;
}
}
}
public TabTheme Theme { get; }
public TerminalViewModel Terminal { get; }
}
}
@@ -13,11 +13,6 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Windows.UI.Core;
using FluentTerminal.Models.Messages;
using System.Windows.Input;
using FluentTerminal.App.ViewModels.Menu;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml;
using System.Collections.Generic;
namespace FluentTerminal.App.ViewModels
{
@@ -37,12 +32,9 @@ namespace FluentTerminal.App.ViewModels
public string ShellTitle { get; set; }
public string TabTitle { get; set; }
public TerminalTheme TerminalTheme { get; set; }
public int TabThemeId { get; set; }
public TabTheme TabTheme { get; set; }
public bool ShowSearchPanel { get; set; }
public string SearchText { get; set; }
public bool SearchMatchCase { get; set; }
public bool SearchWholeWord { get; set; }
public bool SearchWithRegex { get; set; }
public string XtermBufferState { get; set; }
public byte TerminalId { get; set; }
public ShellProfile ShellProfile { get; set; }
@@ -56,12 +48,9 @@ namespace FluentTerminal.App.ViewModels
ShellTitle = ShellTitle,
TabTitle = TabTitle,
TerminalTheme = TerminalTheme,
TabThemeId = TabTheme.Theme.Id,
TabTheme = TabTheme,
ShowSearchPanel = ShowSearchPanel,
SearchText = SearchText,
SearchMatchCase = SearchMatchCase,
SearchWholeWord = SearchWholeWord,
SearchWithRegex = SearchWithRegex,
XtermBufferState = await SerializeXtermStateAsync().ConfigureAwait(false),
TerminalId = Terminal.Id,
ShellProfile = ShellProfile
@@ -79,17 +68,12 @@ namespace FluentTerminal.App.ViewModels
ShellTitle = state.ShellTitle;
TabTitle = state.TabTitle;
TerminalTheme = state.TerminalTheme;
TabTheme = TabThemes.FirstOrDefault(t => t.Theme.Id == state.TabThemeId);
TabTheme = state.TabTheme;
ShowSearchPanel = state.ShowSearchPanel;
SearchText = state.SearchText;
SearchMatchCase = state.SearchMatchCase;
SearchWholeWord = state.SearchWholeWord;
SearchWithRegex = state.SearchWithRegex;
XtermBufferState = state.XtermBufferState;
_terminalId = state.TerminalId;
ShellProfile = state.ShellProfile;
TabTheme.IsSelected = true;
}
}
@@ -102,21 +86,13 @@ namespace FluentTerminal.App.ViewModels
private bool _hasExitedWithError;
private string _searchText;
private bool _showSearchPanel;
private bool _searchMatchCase;
private bool _searchWholeWord;
private bool _searchWithRegex;
private TabThemeViewModel _tabTheme;
private TabTheme _tabTheme;
private TerminalTheme _terminalTheme;
private TerminalOptions _terminalOptions;
private string _tabTitle;
private string _shellTitle;
private bool _hasCustomTitle;
private byte? _terminalId;
private bool _hasSelection;
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,
@@ -125,7 +101,6 @@ namespace FluentTerminal.App.ViewModels
MessengerInstance.Register<ApplicationSettingsChangedMessage>(this, OnApplicationSettingsChanged);
MessengerInstance.Register<CurrentThemeChangedMessage>(this, OnCurrentThemeChanged);
MessengerInstance.Register<TerminalOptionsChangedMessage>(this, OnTerminalOptionsChanged);
MessengerInstance.Register<KeyBindingsChangedMessage>(this, OnKeyBindingsChanged);
SettingsService = settingsService;
@@ -142,7 +117,9 @@ namespace FluentTerminal.App.ViewModels
ShellProfile = shellProfile;
TerminalTheme = shellProfile.TerminalThemeId == Guid.Empty ? SettingsService.GetCurrentTheme() : SettingsService.GetTheme(shellProfile.TerminalThemeId);
TabThemes = new ObservableCollection<TabThemeViewModel>(SettingsService.GetTabThemes().Select(theme => new TabThemeViewModel(theme, this)));
TabThemes = new ObservableCollection<TabTheme>(SettingsService.GetTabThemes());
TabTheme = TabThemes.FirstOrDefault(t => t.Id == ShellProfile.TabThemeId);
CloseCommand = new AsyncCommand(TryCloseAsync, CanExecuteCommand);
CloseLeftTabsCommand = new RelayCommand(CloseLeftTabs, CanExecuteCommand);
CloseRightTabsCommand = new RelayCommand(CloseRightTabs, CanExecuteCommand);
@@ -150,25 +127,14 @@ namespace FluentTerminal.App.ViewModels
FindNextCommand = new RelayCommand(FindNext, CanExecuteCommand);
FindPreviousCommand = new RelayCommand(FindPrevious, CanExecuteCommand);
CloseSearchPanelCommand = new RelayCommand(CloseSearchPanel, CanExecuteCommand);
SelectTabThemeCommand = new RelayCommand<string>(SelectTabTheme, CanExecuteCommand);
EditTitleCommand = new AsyncCommand(EditTitleAsync, CanExecuteCommand);
DuplicateTabCommand = new RelayCommand(DuplicateTab, CanExecuteCommand);
ReconnectTabCommand = new AsyncCommand(ReconnectTabAsync, () => CanExecuteCommand() && HasExitedWithError);
CopyCommand = new AsyncCommand(Copy, () => HasSelection);
PasteCommand = new AsyncCommand(Paste);
CopyLinkCommand = new AsyncCommand(() => CopyTextAsync(HoveredUri), () => !string.IsNullOrWhiteSpace(HoveredUri));
ShowSearchPanelCommand = new RelayCommand(() => ShowSearchPanel = true, () => !ShowSearchPanel);
if (!string.IsNullOrEmpty(terminalState))
if (!String.IsNullOrEmpty(terminalState))
{
Restore(terminalState);
}
else
{
var defaultTabTheme = TabThemes.FirstOrDefault(t => t.Theme.Id == ShellProfile.TabThemeId);
defaultTabTheme.IsSelected = true;
}
_transparentTabThemeViewModel = TabThemes.FirstOrDefault(t => t.Theme.Id == 0);
Terminal = new Terminal(TrayProcessCommunicationService, _terminalId);
Terminal.KeyboardCommandReceived += Terminal_KeyboardCommandReceived;
@@ -177,21 +143,6 @@ namespace FluentTerminal.App.ViewModels
Terminal.TitleChanged += Terminal_TitleChanged;
Terminal.Exited += Terminal_Exited;
Terminal.Closed += Terminal_Closed;
ContextMenu = BuidContextMenu();
TabContextMenu = BuildTabContextMenu();
}
public MenuViewModel ContextMenu
{
get => _contextMenu;
set => Set(ref _contextMenu, value);
}
public MenuViewModel TabContextMenu
{
get => _tabContextMenu;
set => Set(ref _tabContextMenu, value);
}
private bool _disposalRequested;
@@ -208,8 +159,8 @@ namespace FluentTerminal.App.ViewModels
public event EventHandler Activated;
public event EventHandler Closed;
public event EventHandler<SearchRequest> FindNextRequested;
public event EventHandler<SearchRequest> FindPreviousRequested;
public event EventHandler<string> FindNextRequested;
public event EventHandler<string> FindPreviousRequested;
public event EventHandler SearchStarted;
public event EventHandler<TerminalTheme> ThemeChanged;
public event EventHandler CloseLeftTabsRequested;
@@ -221,13 +172,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 :
SettingsService.GetTabThemes().FirstOrDefault(t => t.Color == null);
}
public IClipboardService ClipboardService { get; }
@@ -254,16 +205,6 @@ namespace FluentTerminal.App.ViewModels
public RelayCommand DuplicateTabCommand { get; }
public AsyncCommand ReconnectTabCommand { get; }
public ICommand CopyLinkCommand { get; private set; }
public ICommand CopyCommand { get; private set; }
public ICommand PasteCommand { get; private set; }
public ICommand ShowSearchPanelCommand { get; private set; }
public double BackgroundOpacity => _terminalOptions?.BackgroundOpacity ?? 1.0;
public bool IsSelected
@@ -275,13 +216,8 @@ namespace FluentTerminal.App.ViewModels
{
if (IsSelected)
{
_keyboardCommandService.RegisterCommandHandler(nameof(Command.Search), () => ShowSearchPanel = !ShowSearchPanel);
HasNewOutput = false;
}
else
{
_keyboardCommandService.DeregisterCommandHandler(nameof(Command.Search));
}
RaisePropertyChanged(nameof(IsUnderlined));
RaisePropertyChanged(nameof(BackgroundTabTheme));
RaisePropertyChanged(nameof(ShowCloseButton));
@@ -289,24 +225,6 @@ namespace FluentTerminal.App.ViewModels
}
}
public bool HasSelection
{
get => _hasSelection;
set => Set(ref _hasSelection, value);
}
public string HoveredUri
{
get => _hoveredUri;
set
{
if (Set(ref _hoveredUri, value))
{
ContextMenu = BuidContextMenu();
}
}
}
public bool IsHovered
{
get => _isHovered;
@@ -325,7 +243,7 @@ namespace FluentTerminal.App.ViewModels
}
public bool IsUnderlined => (IsSelected && ApplicationSettings.UnderlineSelectedTab) ||
(!IsSelected && ApplicationSettings.InactiveTabColorMode == InactiveTabColorMode.Underlined && TabTheme.Theme.Color != null);
(!IsSelected && ApplicationSettings.InactiveTabColorMode == InactiveTabColorMode.Underlined && TabTheme.Color != null);
public bool HasNewOutput
{
@@ -342,7 +260,6 @@ namespace FluentTerminal.App.ViewModels
{
HasNewOutput = false;
}
ReconnectTabCommand.RaiseCanExecuteChanged();
}
}
@@ -352,23 +269,7 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _searchText, value);
}
public bool SearchMatchCase
{
get => _searchMatchCase;
set => Set(ref _searchMatchCase, value);
}
public bool SearchWholeWord
{
get => _searchWholeWord;
set => Set(ref _searchWholeWord, value);
}
public bool SearchWithRegex
{
get => _searchWithRegex;
set => Set(ref _searchWithRegex, value);
}
public RelayCommand<string> SelectTabThemeCommand { get; }
public ISettingsService SettingsService { get; }
@@ -380,7 +281,7 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _showSearchPanel, value);
}
public TabThemeViewModel TabTheme
public TabTheme TabTheme
{
get => _tabTheme;
set
@@ -391,7 +292,7 @@ namespace FluentTerminal.App.ViewModels
}
}
public ObservableCollection<TabThemeViewModel> TabThemes { get; }
public ObservableCollection<TabTheme> TabThemes { get; }
public Terminal Terminal { get; private set; }
@@ -462,7 +363,7 @@ namespace FluentTerminal.App.ViewModels
{
ClipboardService.SetText(text);
if (ApplicationSettings.ShowTextCopied)
if (_terminalOptions.ShowTextCopied)
{
Overlay.Show(I18N.Translate("TextCopied"));
}
@@ -529,7 +430,7 @@ namespace FluentTerminal.App.ViewModels
private void FindNext()
{
FindNextRequested?.Invoke(this, new SearchRequest { MatchCase = SearchMatchCase, Regex = SearchWithRegex, Term = SearchText, WholeWord = SearchWholeWord });
FindNextRequested?.Invoke(this, SearchText);
}
public ITerminalView TerminalView { get; set; }
@@ -541,7 +442,7 @@ namespace FluentTerminal.App.ViewModels
private void FindPrevious()
{
FindPreviousRequested?.Invoke(this, new SearchRequest { MatchCase = SearchMatchCase, Regex = SearchWithRegex, Term = SearchText, WholeWord = SearchWholeWord });
FindPreviousRequested?.Invoke(this, SearchText);
}
private void DuplicateTab()
@@ -549,12 +450,6 @@ namespace FluentTerminal.App.ViewModels
DuplicateTabRequested?.Invoke(this, EventArgs.Empty);
}
public async Task ReconnectTabAsync()
{
HasExitedWithError = false;
await TerminalView?.ReconnectAsync();
}
private void OnApplicationSettingsChanged(ApplicationSettingsChangedMessage message)
{
ApplicationSettings = message.ApplicationSettings;
@@ -587,23 +482,9 @@ namespace FluentTerminal.App.ViewModels
ApplicationView.ExecuteOnUiThreadAsync(() => RaisePropertyChanged(nameof(BackgroundOpacity)), CoreDispatcherPriority.Low);
}
private void OnKeyBindingsChanged(KeyBindingsChangedMessage message)
private void SelectTabTheme(string id)
{
ApplicationView.ExecuteOnUiThreadAsync(() =>
{
var contextMenu = BuidContextMenu();
if (!contextMenu.EquivalentTo(ContextMenu))
{
ContextMenu = contextMenu;
}
var tabContextMenu = BuildTabContextMenu();
if (!tabContextMenu.EquivalentTo(TabContextMenu))
{
TabContextMenu = tabContextMenu;
}
}, CoreDispatcherPriority.Low, true);
TabTheme = TabThemes.FirstOrDefault(t => t.Id == int.Parse(id));
}
private void Terminal_Exited(object sender, int exitCode)
@@ -633,12 +514,18 @@ namespace FluentTerminal.App.ViewModels
{
case nameof(Command.Copy):
{
await Copy().ConfigureAwait(false);
var selection = await Terminal.GetSelectedText().ConfigureAwait(false);
await CopyTextAsync(selection).ConfigureAwait(false);
return;
}
case nameof(Command.Paste):
{
await Paste().ConfigureAwait(false);
string content = await ClipboardService.GetTextAsync().ConfigureAwait(false);
if (content != null)
{
content = ShellProfile.TranslateLineEndings(content);
await TerminalView.PasteAsync(content).ConfigureAwait(false);
}
return;
}
case nameof(Command.PasteWithoutNewlines):
@@ -647,7 +534,7 @@ namespace FluentTerminal.App.ViewModels
if (content != null)
{
content = ShellProfile.NewlinePattern.Replace(content, string.Empty);
TerminalView.Paste(content);
await TerminalView.PasteAsync(content).ConfigureAwait(false);
}
return;
}
@@ -692,7 +579,6 @@ namespace FluentTerminal.App.ViewModels
private void Terminal_TitleChanged(object sender, string e)
{
if (e == Terminal.Profile.Location) return;
ApplicationView.ExecuteOnUiThreadAsync(() => ShellTitle = e);
}
@@ -711,123 +597,5 @@ namespace FluentTerminal.App.ViewModels
await CloseAsync().ConfigureAwait(false);
}
}
private async Task Copy()
{
var selection = await Terminal.GetSelectedText().ConfigureAwait(false);
await CopyTextAsync(selection).ConfigureAwait(false);
}
private async Task Paste()
{
var content = await ClipboardService.GetTextAsync().ConfigureAwait(false);
if (content != null)
{
TerminalView.Paste(content);
}
}
private MenuViewModel BuidContextMenu()
{
var commandKeyBindings = SettingsService.GetCommandKeyBindings();
var contextMenu = new MenuViewModel();
if (!string.IsNullOrWhiteSpace(HoveredUri))
{
var copyLink = new MenuItemViewModel(I18N.Translate("CopyLink"), CopyLinkCommand, icon: Mdl2Icon.Link());
contextMenu.Items.Add(copyLink);
contextMenu.Items.Add(new SeparatorMenuItemViewModel());
}
var copy = new MenuItemViewModel(I18N.Translate("Command.Copy"), CopyCommand, icon: Mdl2Icon.Copy());
AddKeyBindings(copy, Command.Copy, commandKeyBindings);
contextMenu.Items.Add(copy);
var paste = new MenuItemViewModel(I18N.Translate("Command.Paste"), PasteCommand, icon: Mdl2Icon.Paste());
AddKeyBindings(paste, Command.Paste, commandKeyBindings);
contextMenu.Items.Add(paste);
contextMenu.Items.Add(new SeparatorMenuItemViewModel());
var editTitle = new MenuItemViewModel(I18N.Translate("EditTitle.Text"), EditTitleCommand, icon: Mdl2Icon.Edit());
AddKeyBindings(editTitle, Command.ChangeTabTitle, commandKeyBindings);
contextMenu.Items.Add(editTitle);
var search = new MenuItemViewModel(I18N.Translate("Search.Text"), ShowSearchPanelCommand, icon: Mdl2Icon.Search());
AddKeyBindings(search, Command.Search, commandKeyBindings);
contextMenu.Items.Add(search);
contextMenu.Items.Add(new SeparatorMenuItemViewModel());
var duplicate = new MenuItemViewModel(I18N.Translate("Command.DuplicateTab"), DuplicateTabCommand);
AddKeyBindings(duplicate, Command.DuplicateTab, commandKeyBindings);
contextMenu.Items.Add(duplicate);
contextMenu.Items.Add(new SeparatorMenuItemViewModel());
var close = new MenuItemViewModel(I18N.Translate("Close"), CloseCommand, icon: Mdl2Icon.Cancel());
AddKeyBindings(close, Command.CloseTab, commandKeyBindings);
contextMenu.Items.Add(close);
return contextMenu;
}
private MenuViewModel BuildTabContextMenu()
{
var commandKeyBindings = SettingsService.GetCommandKeyBindings();
var contextMenu = new MenuViewModel();
RadioMenuItemViewModel createTabColorItem(TabThemeViewModel tabTheme)
{
//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);
}
var tabColor = new ExpandableMenuItemViewModel(I18N.Translate("Color.Text"));
foreach (var tabTheme in TabThemes)
{
tabColor.SubItems.Add(createTabColorItem(tabTheme));
}
contextMenu.Items.Add(tabColor);
var editTitle = new MenuItemViewModel(I18N.Translate("EditTitle.Text"), EditTitleCommand, icon: Mdl2Icon.Edit());
AddKeyBindings(editTitle, Command.ChangeTabTitle, commandKeyBindings);
contextMenu.Items.Add(editTitle);
contextMenu.Items.Add(new SeparatorMenuItemViewModel());
var duplicate = new MenuItemViewModel(I18N.Translate("Command.DuplicateTab"), DuplicateTabCommand);
AddKeyBindings(duplicate, Command.DuplicateTab, commandKeyBindings);
contextMenu.Items.Add(duplicate);
contextMenu.Items.Add(new SeparatorMenuItemViewModel());
var closeLeft = new MenuItemViewModel(I18N.Translate("CloseLeft.Text"), CloseLeftTabsCommand);
contextMenu.Items.Add(closeLeft);
var closeRight = new MenuItemViewModel(I18N.Translate("CloseRight.Text"), CloseRightTabsCommand);
contextMenu.Items.Add(closeRight);
var closeOther = new MenuItemViewModel(I18N.Translate("CloseOther.Text"), CloseOtherTabsCommand);
contextMenu.Items.Add(closeOther);
var close = new MenuItemViewModel(I18N.Translate("Close"), CloseCommand, icon: Mdl2Icon.Cancel());
AddKeyBindings(close, Command.CloseTab, commandKeyBindings);
contextMenu.Items.Add(close);
return contextMenu;
}
private void AddKeyBindings(MenuItemViewModel menuItem, Command command, IDictionary<string, ICollection<KeyBinding>> commandKeyBindings)
{
var keyBindings = commandKeyBindings[command.ToString()];
if (keyBindings?.Any() == true)
{
menuItem.KeyBinding = new MenuItemKeyBindingViewModel(keyBindings.First());
}
}
}
}
-26
View File
@@ -1,26 +0,0 @@
using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Actions
{
public class FocusAction : DependencyObject, IAction
{
public object Execute(object sender, object parameter)
{
var control = TargetObject ?? sender as Control;
control?.Focus(FocusState.Programmatic);
return null;
}
public Control TargetObject
{
get { return (Control)GetValue(TargetObjectProperty); }
set { SetValue(TargetObjectProperty, value); }
}
public static readonly DependencyProperty TargetObjectProperty =
DependencyProperty.Register(nameof(TargetObject), typeof(Control), typeof(FocusAction), new PropertyMetadata(null));
}
}
-1
View File
@@ -42,7 +42,6 @@
<converters:TrueToBoldConverter x:Key="TrueToBoldConverter" />
<converters:I18NConverter x:Key="I18NConverter" />
<converters:NullToCollapsedConverter x:Key="NullToCollapsedConverter" />
<converters:MenuViewModelToFlyoutMenuConverter x:Key="MenuViewModelToFlyoutMenuConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
+145 -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;
@@ -101,6 +100,7 @@ namespace FluentTerminal.App
builder.RegisterType<FileSystemService>().As<IFileSystemService>().SingleInstance();
builder.RegisterType<ImageFileSystemService>().As<IImageFileSystemService>().SingleInstance();
builder.RegisterType<SystemFontService>().As<ISystemFontService>().SingleInstance();
builder.RegisterType<ShellProfileSelectionDialog>().As<IShellProfileSelectionDialog>().InstancePerDependency();
builder.RegisterType<CreateKeyBindingDialog>().As<ICreateKeyBindingDialog>().InstancePerDependency();
builder.RegisterType<InputDialog>().As<IInputDialog>().InstancePerDependency();
builder.RegisterType<AboutDialog>().As<IAboutDialog>().InstancePerDependency();
@@ -111,13 +111,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 +187,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 +263,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 +348,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 +359,148 @@ 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.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 +755,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,9 +14,6 @@ namespace FluentTerminal.App.CommandLineArguments
[Option("theme")]
public string Theme { get; set; }
[Option("smart-buffer")]
public bool? SmartBuffer { 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.")]
@@ -3,11 +3,10 @@ using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using FluentTerminal.App.ViewModels.Menu;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.Foundation.Metadata;
namespace FluentTerminal.App.Converters
{
public class MenuViewModelToFlyoutMenuConverter : IValueConverter
public class AppMenuViewModelToFlyoutMenuConverter : IValueConverter
{
private static readonly MenuItemViewModelBaseToMenuFlayoutItemBaseConverter ItemConverter =
new MenuItemViewModelBaseToMenuFlayoutItemBaseConverter();
@@ -19,18 +18,18 @@ namespace FluentTerminal.App.Converters
return null;
}
if (!(value is MenuViewModel menuViewModel))
if (!(value is AppMenuViewModel appMenuViewModel))
{
throw new ArgumentException(
$"Invalid {nameof(value)} argument type: {value.GetType()}. {typeof(MenuViewModel)} expected.");
$"Invalid {nameof(value)} argument type: {value.GetType()}. {typeof(AppMenuViewModel)} expected.");
}
var menuFlyout = new MenuFlyout
{
Placement = FlyoutPlacementMode.Bottom
Placement = FlyoutPlacementMode.BottomEdgeAlignedLeft
};
foreach (var menuItemViewModelBase in menuViewModel.Items)
foreach (var menuItemViewModelBase in appMenuViewModel.Items)
{
menuFlyout.Items?.Add((MenuFlyoutItemBase) ItemConverter.Convert(menuItemViewModelBase));
}
@@ -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);
+29 -13
View File
@@ -1,6 +1,4 @@
using FluentTerminal.App.ViewModels.Menu;
using Microsoft.Toolkit.Uwp.Helpers;
using System;
using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
@@ -12,19 +10,37 @@ namespace FluentTerminal.App.Converters
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is Mdl2Icon mdl2Icon)
if (value == null)
{
var fontIcon = new FontIcon { FontFamily = new FontFamily("Segoe MDL2 Assets"), Glyph = mdl2Icon.Glyph };
if(!string.IsNullOrWhiteSpace(mdl2Icon.Color))
{
fontIcon.Foreground = new SolidColorBrush(mdl2Icon.Color.ToColor());
}
return fontIcon;
return null;
}
return null;
if (value is IconElement icon)
{
return icon;
}
if (value is Symbol symbol)
{
return new SymbolIcon(symbol);
}
if (value is int intSymbol)
{
if (Enum.IsDefined(typeof(Symbol), intSymbol))
{
return new SymbolIcon((Symbol) intSymbol);
}
throw new ArgumentException($"Integer value isn't defined in {nameof(Symbol)} enum.", nameof(value));
}
if (value is string glyph)
{
return new FontIcon {FontFamily = new FontFamily("Segoe MDL2 Assets"), Glyph = glyph};
}
throw new ArgumentException($"Invalid {nameof(value)} parameter type: {value.GetType()}.", nameof(value));
}
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
@@ -6,8 +6,6 @@ using Windows.UI.Xaml.Data;
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
@@ -36,16 +34,6 @@ namespace FluentTerminal.App.Converters
return GetRegularItem(regular);
}
if (viewModel is ToggleMenuItemViewModel toggle)
{
return GetToggleItem(toggle);
}
if (viewModel is RadioMenuItemViewModel radio)
{
return GetRadioItem(radio);
}
// Won't happen ever, but still...
throw new NotImplementedException(
$"Unexpected {nameof(MenuItemViewModelBase)} type: {viewModel.GetType()}");
@@ -91,22 +79,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;
@@ -148,85 +126,6 @@ namespace FluentTerminal.App.Converters
return item;
}
private static ToggleMenuFlyoutItem GetToggleItem(ToggleMenuItemViewModel viewModel)
{
var item = new ToggleMenuFlyoutItem();
item.SetBinding(MenuFlyoutItem.TextProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(MenuItemViewModelBase.Text)),
Mode = BindingMode.OneWay
});
item.SetBinding(ToolTipService.ToolTipProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(MenuItemViewModelBase.Description)),
Mode = BindingMode.OneWay
});
item.SetBinding(MenuFlyoutItem.IconProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(MenuItemViewModelBase.Icon)),
Converter = IconConverter,
Mode = BindingMode.OneWay
});
item.SetBinding(ToggleMenuFlyoutItem.IsCheckedProperty, new Binding
{
Source = viewModel.BindingSource,
Path = new PropertyPath(viewModel.BindingPath),
Mode = BindingMode.TwoWay
});
return item;
}
private static RadioMenuFlyoutItem GetRadioItem(RadioMenuItemViewModel viewModel)
{
var item = new RadioMenuFlyoutItem();
item.SetBinding(MenuFlyoutItem.TextProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(MenuItemViewModelBase.Text)),
Mode = BindingMode.OneWay
});
item.SetBinding(ToolTipService.ToolTipProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(MenuItemViewModelBase.Description)),
Mode = BindingMode.OneWay
});
item.SetBinding(MenuFlyoutItem.IconProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(MenuItemViewModelBase.Icon)),
Converter = IconConverter,
Mode = BindingMode.OneWay
});
item.SetBinding(RadioMenuFlyoutItem.GroupNameProperty, new Binding
{
Source = viewModel,
Path = new PropertyPath(nameof(RadioMenuItemViewModel.GroupName)),
Mode = BindingMode.OneWay
});
item.SetBinding(RadioMenuFlyoutItem.IsCheckedProperty, new Binding
{
Source = viewModel.BindingSource,
Path = new PropertyPath(viewModel.BindingPath),
Mode = BindingMode.TwoWay
});
return item;
}
#endregion Static
#region IValueConverter
@@ -1,4 +1,4 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using Microsoft.Toolkit.Uwp.Helpers;
using System;
@@ -12,9 +12,8 @@ namespace FluentTerminal.App.Converters
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is TabThemeViewModel viewModel && Enum.TryParse<TabThemeKey>((string)parameter, true, out TabThemeKey tabThemeKey))
if (value is TabTheme theme && Enum.TryParse<TabThemeKey>((string)parameter, true, out TabThemeKey tabThemeKey))
{
var theme = viewModel.Theme;
switch (tabThemeKey)
{
case TabThemeKey.Background:
@@ -1,5 +1,4 @@
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
using FluentTerminal.Models;
using System;
using Windows.UI.Xaml.Data;
@@ -9,9 +8,9 @@ namespace FluentTerminal.App.Converters
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is TerminalViewModel terminal && parameter is string idString && int.TryParse(idString, out var id))
if (value is TabTheme theme && parameter is string idString && int.TryParse(idString, out var id))
{
return terminal.TabTheme.Theme.Id == id;
return theme.Id == id;
}
return null;
}
@@ -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;
@@ -14,8 +14,8 @@
IsDesignTimeCreatable=False}"
DefaultButton="Primary"
PrimaryButtonClick="OnPrimaryButtonClick"
PrimaryButtonText="Button1"
SecondaryButtonClick="OnSecondaryButtonClick"
PrimaryButtonText="Button1"
SecondaryButtonText="Button2"
mc:Ignorable="d">
<ContentDialog.Resources>
@@ -46,12 +46,9 @@
<AutoSuggestBox.ItemTemplate>
<DataTemplate x:DataType="viewModels:CommandItemViewModel">
<Grid HorizontalAlignment="Stretch">
<ContentControl HorizontalAlignment="Stretch" Content="{x:Bind RichTextBlock, Mode=OneWay}" />
<!-- I've had to create a transparent overlay over RichTextBox in order to make mouse selection work. Weird but true. -->
<Grid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Transparent" />
<ContentControl HorizontalAlignment="Stretch" Content="{x:Bind RichTextBlock, Mode=OneWay}"/>
<!--I've had to create a transparent overlay over RichTextBox in order to make mouse selection work. Weird but true.-->
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent"/>
</Grid>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
@@ -84,14 +81,37 @@
<!-- Row -->
<TextBlock
x:Uid="SshInfoDialog_TabColor"
x:Uid="LineEndingModeOnPaste"
Grid.Row="0"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Line ending on paste:" />
<ComboBox
Grid.Row="0"
Grid.Column="1"
Margin="0,8,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
ItemsSource="{x:Bind ViewModel.LineEndingStyles}"
SelectedItem="{x:Bind ViewModel.LineEndingTranslation, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="enums:LineEndingStyle">
<TextBlock Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=LineEndingStyle}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Row -->
<TextBlock
x:Uid="SshInfoDialog_TabColor"
Grid.Row="1"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Tab color:" />
<ComboBox
Grid.Row="0"
Grid.Row="1"
Grid.Column="1"
Margin="0,8,0,0"
HorizontalAlignment="Stretch"
@@ -102,13 +122,13 @@
<!-- Row -->
<TextBlock
x:Uid="Theme"
Grid.Row="1"
Grid.Row="2"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Theme:" />
<ComboBox
Grid.Row="1"
Grid.Row="2"
Grid.Column="1"
Margin="0,8,0,0"
HorizontalAlignment="Stretch"
@@ -118,22 +138,13 @@
<!-- Row -->
<CheckBox
Grid.Row="2"
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,8,0,0"
Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseConPty}"
IsChecked="{x:Bind ViewModel.UseConPty, Mode=TwoWay}" />
<!-- Row -->
<CheckBox
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,8,0,0"
Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseBuffer}"
IsChecked="{x:Bind ViewModel.UseBuffer, Mode=TwoWay}" />
</Grid>
</controls:Expander>
@@ -0,0 +1,17 @@
<ContentDialog
x:Class="FluentTerminal.App.Dialogs.ShellProfileSelectionDialog"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Uid="SelectProfileUI"
Title="Select Profile"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
PrimaryButtonText="Start"
mc:Ignorable="d">
<ComboBox
HorizontalAlignment="Stretch"
DisplayMemberPath="Name"
ItemsSource="{x:Bind Profiles}"
SelectedItem="{x:Bind SelectedProfile, Mode=TwoWay}" />
</ContentDialog>
@@ -0,0 +1,43 @@
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Dialogs;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.App.Utilities;
using FluentTerminal.Models;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
namespace FluentTerminal.App.Dialogs
{
// ReSharper disable once RedundantExtendsListEntry
public sealed partial class ShellProfileSelectionDialog : ContentDialog, IShellProfileSelectionDialog
{
public ObservableCollection<ShellProfile> Profiles { get; }
public ShellProfile SelectedProfile { get; private set; }
public ShellProfileSelectionDialog(ISettingsService settingsService)
{
Profiles = new ObservableCollection<ShellProfile>(settingsService.GetAllProfiles().OrderBy(p => p.Name));
SelectedProfile = Profiles.First();
InitializeComponent();
PrimaryButtonText = I18N.TranslateWithFallback("OK", "OK");
SecondaryButtonText = I18N.TranslateWithFallback("Cancel", "Cancel");
var currentTheme = settingsService.GetCurrentTheme();
RequestedTheme = ContrastHelper.GetIdealThemeForBackgroundColor(currentTheme.Colors.Background);
}
public Task<ShellProfile> SelectProfileAsync()
{
return ShowAsync().AsTask()
.ContinueWith(t => t.Result == ContentDialogResult.Primary ? SelectedProfile : null,
TaskContinuationOptions.OnlyOnRanToCompletion);
}
}
}
+29 -14
View File
@@ -167,14 +167,38 @@
<!-- Row -->
<TextBlock
x:Uid="SshInfoDialog_TabColor"
x:Uid="LineEndingModeOnPaste"
Grid.Row="1"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Line ending on paste:" />
<ComboBox
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0,8,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
ItemsSource="{x:Bind ViewModel.LineEndingStyles}"
SelectedItem="{x:Bind ViewModel.LineEndingTranslation, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="enums:LineEndingStyle">
<TextBlock Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=LineEndingStyle}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Row -->
<TextBlock
x:Uid="SshInfoDialog_TabColor"
Grid.Row="2"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Tab color:" />
<ComboBox
Grid.Row="1"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0,8,0,0"
@@ -186,13 +210,13 @@
<!-- Row -->
<TextBlock
x:Uid="Theme"
Grid.Row="2"
Grid.Row="3"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Theme:" />
<ComboBox
Grid.Row="2"
Grid.Row="3"
Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0,8,0,0"
@@ -203,22 +227,13 @@
<!-- Row -->
<CheckBox
Grid.Row="3"
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="0,8,0,0"
Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseConPty}"
IsChecked="{x:Bind ViewModel.UseConPty, Mode=TwoWay}" />
<!-- Row -->
<CheckBox
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="0,8,0,0"
Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseBuffer}"
IsChecked="{x:Bind ViewModel.UseBuffer, Mode=TwoWay}" />
</Grid>
</controls:Expander>
+11 -22
View File
@@ -97,7 +97,6 @@
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="Actions\FocusAction.cs" />
<Compile Include="Adapters\ApplicationViewAdapter.cs" />
<Compile Include="Adapters\AppServiceConnectionAdapter.cs" />
<Compile Include="App.xaml.cs">
@@ -108,7 +107,7 @@
<Compile Include="CommandLineArguments\RunVerb.cs" />
<Compile Include="CommandLineArguments\SettingsVerb.cs" />
<Compile Include="CommandLineArguments\Target.cs" />
<Compile Include="Converters\MenuViewModelToFlyoutMenuConverter.cs" />
<Compile Include="Converters\AppMenuViewModelToFlyoutMenuConverter.cs" />
<Compile Include="Converters\BackgroundToApplicationThemeConverter.cs" />
<Compile Include="Converters\BooleanNegationConverter.cs" />
<Compile Include="Converters\ColorResourceKeyFallbackConverter.cs" />
@@ -133,6 +132,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" />
@@ -144,6 +144,9 @@
<Compile Include="Dialogs\InputDialog.xaml.cs">
<DependentUpon>InputDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Dialogs\ShellProfileSelectionDialog.xaml.cs">
<DependentUpon>ShellProfileSelectionDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Dialogs\SshInfoDialog.xaml.cs">
<DependentUpon>SshInfoDialog.xaml</DependentUpon>
</Compile>
@@ -240,7 +243,7 @@
<PRIResource Include="Strings\fr\Resources.resw" />
<PRIResource Include="Strings\es\Resources.resw" />
<PRIResource Include="Strings\de\Resources.resw" />
<PRIResource Include="Strings\zh-Hant\Resources.resw" />
<PRIResource Include="Strings\zh-CN\Resources.resw" />
<PRIResource Include="Strings\en\Resources.resw" />
</ItemGroup>
<ItemGroup>
@@ -266,6 +269,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialogs\ShellProfileSelectionDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialogs\SshInfoDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -356,7 +363,7 @@
<Version>2.7.82</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.10</Version>
<Version>6.2.9</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI">
<Version>6.0.0</Version>
@@ -427,24 +434,6 @@
<ItemGroup>
<PRIResource Include="Strings\uk\Resources.resw" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\ar\Resources.resw" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\id\Resources.resw" />
</ItemGroup>
<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);
}
}
@@ -10,18 +10,14 @@ namespace FluentTerminal.App.Services
private readonly Dictionary<string, string> _languages = new Dictionary<string, string>
{
[""] = "System default",
["ar"] = "العربية",
["ar-IQ"] = "اللهجة العراقية",
["az"] = "azərbaycan dili",
["de"] = "Deutsch",
["en"] = "English",
["es"] = "Español",
["fa"] = "فارسی",
["fr"] = "Français",
["he"] = "עברית",
["hi"] = "हिन्दुस्तानी",
["hu"] = "magyar",
["id"] = "Bahasa Indonesia",
["it"] = "Italiano",
["ja"] = "日本語",
["ko"] = "한국어",
@@ -30,10 +26,8 @@ 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-CN"] = "Chinese (Traditional)"
};
public IEnumerable<string> Languages => _languages.Values;
@@ -50,10 +44,6 @@ namespace FluentTerminal.App.Services
public string GetCurrentLanguage()
{
if (!_languages.ContainsKey(ApplicationLanguages.PrimaryLanguageOverride))
{
ApplicationLanguages.PrimaryLanguageOverride = "en";
}
return _languages[ApplicationLanguages.PrimaryLanguageOverride];
}
}
+16 -24
View File
@@ -637,6 +637,14 @@
<value>إغلاق علامة التبويب</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>علامة تبويب جديدة قابلة للتكوين</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>نافذة جديدة شكلي</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>كيبيندينغس</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>اختر الكل</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>بداية</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>اختر صفحة شخصية</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>إعدادات العرض</value>
<comment>Command</comment>
@@ -1028,28 +1044,4 @@
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" 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
+16 -24
View File
@@ -637,6 +637,14 @@
<value>Nişanı bağlayın</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Yapılandırılabilir yeni nişan</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Tənzimlənən yeni pəncərə</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Keybindings</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>Hamısını seç</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Başlamaq</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Profil seçin</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Parametrləri göstərin</value>
<comment>Command</comment>
@@ -1028,28 +1044,4 @@
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+16 -24
View File
@@ -649,6 +649,14 @@ Fuzzy</comment>
<value>Tab schließen</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Konfigurierbarer neuer Tab</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Konfigurierbares neues Fenster</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Tastaturkürzel</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -691,6 +699,14 @@ Fuzzy</comment>
<value>Alles auswählen</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Start</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Profil auswählen</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Einstellungen öffnen</value>
<comment>Command</comment>
@@ -1061,28 +1077,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Helle Farben</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Link kopieren</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>Regex</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>Ganzes Wort</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Groß-/Kleinschreibung beachten</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Auswahl kopieren oder Einfügen</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Smart Buffer verwenden</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Neu starten</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Sitzung wurde getrennt.</value>
</data>
</root>
+18 -24
View File
@@ -659,6 +659,16 @@ Fuzzy</comment>
<data name="Command.CloseTab" xml:space="preserve">
<value>Close tab</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Configurable new tab</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Configurable new window</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
@@ -709,6 +719,14 @@ Fuzzy</comment>
<comment>Command
Fuzzy</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Start</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Select Profile</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Show settings</value>
<comment>Command
@@ -1093,28 +1111,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+90 -98
View File
@@ -542,7 +542,7 @@ Fuzzy</comment>
<comment>ShellProfileSettings.xaml</comment>
</data>
<data name="ConfirmCloseTab" xml:space="preserve">
<value>¿Estás seguro que quieres cerrar la pestaña &quot;{0}&quot;?</value>
<value>Are you sure you want to close &quot;{0}&quot; tab?</value>
<comment>ViewModel</comment>
</data>
<data name="ConfirmCloseWindow" xml:space="preserve">
@@ -645,6 +645,14 @@ Fuzzy</comment>
<value>Cerrar pestaña</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Nueva pestaña configurable</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Nueva ventana configurable</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Atajos</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -687,6 +695,14 @@ Fuzzy</comment>
<value>Seleccionar todo</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Iniciar</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Selecciona perfil</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Mostar opciones</value>
<comment>Command</comment>
@@ -831,246 +847,222 @@ Fuzzy</comment>
<value>¿Quieres eliminar este perfil?</value>
</data>
<data name="Command.NewSshWindow" xml:space="preserve">
<value>Nueva ventana SSH</value>
<value>New SSH window</value>
</data>
<data name="Setting_SShProfiles.Content" xml:space="preserve">
<value>Perfiles SSH</value>
<value>SSH Profiles</value>
</data>
<data name="SshInfoDialog_TabColor.Text" xml:space="preserve">
<value>Color de pestaña:</value>
<value>Tab color:</value>
</data>
<data name="UseConPty" xml:space="preserve">
<value>Usar ConPty</value>
<value>Use ConPty</value>
</data>
<data name="Username.Header" xml:space="preserve">
<value>Nombre de usuario</value>
<value>Username</value>
</data>
<data name="MoshPortFrom.Header" xml:space="preserve">
<value>Puerto desde</value>
<value>From port</value>
</data>
<data name="MoshPortTo.Header" xml:space="preserve">
<value>a puerto</value>
<value>to port</value>
</data>
<data name="MoshPortRange.Text" xml:space="preserve">
<value>Rango de puertos Mosh</value>
<value>Mosh port range</value>
</data>
<data name="Authenticate" xml:space="preserve">
<value>Autenticar</value>
<value>Authenticate</value>
</data>
<data name="SettingsExported" xml:space="preserve">
<value>Opciones exportadas a archivo</value>
<value>Settings were exported to file</value>
</data>
<data name="SettingsImported" xml:space="preserve">
<value>Opciones importadas desde archivo</value>
<value>Settings were imported from file</value>
</data>
<data name="SshConnectionInfoValidationResult.IdentityFileDoesNotExist" xml:space="preserve">
<value>No existe el archivo de identidad</value>
<value>Identify file does not exist</value>
</data>
<data name="AutoFallbackToWindowsUsername.Header" xml:space="preserve">
<value>Usar nombre de Windows al abrir urls SSH que no especifican uno</value>
<value>Use Windows username when opening SSH URLs that don&apos;t specify one</value>
</data>
<data name="UseMoshByDefault.Header" xml:space="preserve">
<value>Mosh para conexiones SSH por defecto</value>
<value>Default to Mosh for SSH connections</value>
</data>
<data name="RTrimCopiedLines.Header" xml:space="preserve">
<value>Recortar a la derecha las líneas copiadas</value>
<value>Right trim copied lines</value>
</data>
<data name="QuickSshDefault.Header" xml:space="preserve">
<value>Usar SSH rápido por defecto</value>
<value>Use quick SSH by default</value>
</data>
<data name="InvalidCommand" xml:space="preserve">
<value>Comando inválido.</value>
<value>Invalid command.</value>
</data>
<data name="LocationCantBeEmpty" xml:space="preserve">
<value>La ubicación no puede estar vacía.</value>
<value>Location cannot be empty.</value>
</data>
<data name="MuteTerminalBeeps.Header" xml:space="preserve">
<value>Silenciar sonidos de terminal</value>
<value>Mute terminal beeps</value>
</data>
<data name="CommandTextBox.PlaceholderText" xml:space="preserve">
<value>Introduce un comando (p.e. &apos;ssh username@host&apos;)</value>
<value>Enter a command (e.g. &apos;ssh username@host&apos;)</value>
</data>
<data name="CommandLine.Header" xml:space="preserve">
<value>Comando</value>
<value>Command</value>
</data>
<data name="UnsupportedCommand" xml:space="preserve">
<value>Comando no soportado:</value>
<value>Unsupported command:</value>
</data>
<data name="CommandArgumentsMandatory" xml:space="preserve">
<value>Faltan argumentos del comando.</value>
<value>Command arguments are missing.</value>
</data>
<data name="QuickCommandDialog.Title" xml:space="preserve">
<value>Lanzamiento rápido</value>
<value>Quick Launch</value>
</data>
<data name="Command.NewCustomCommandTab" xml:space="preserve">
<value>Nueva pestaña de inicio rápido</value>
<value>New quick launch tab</value>
</data>
<data name="Command.NewCustomCommandWindow" xml:space="preserve">
<value>Lanzar nueva ventana rápida</value>
<value>New quick launch window</value>
</data>
<data name="NewQuickTab.Text" xml:space="preserve">
<value>Nueva pestaña rápida</value>
<value>New quick tab</value>
</data>
<data name="FileNotFound" xml:space="preserve">
<value>Archivo no encontrado:</value>
<value>File not found:</value>
</data>
<data name="InvalidLink" xml:space="preserve">
<value>Enlace inválido.</value>
<value>Invalid link.</value>
</data>
<data name="DropTabHere" xml:space="preserve">
<value>Suelta la pestaña aquí</value>
<value>Drop tab here</value>
</data>
<data name="CloseLeft.Text" xml:space="preserve">
<value>Cerrar pestañas a la izquierda</value>
<value>Close tabs to the left</value>
</data>
<data name="CloseOther.Text" xml:space="preserve">
<value>Cerrar el resto de pestañas</value>
<value>Close other tabs</value>
</data>
<data name="CloseRight.Text" xml:space="preserve">
<value>Cerrar pestañas a la derecha</value>
<value>Close tabs to the right</value>
</data>
<data name="Command.DuplicateTab" xml:space="preserve">
<value>Duplicar pestaña</value>
<value>Duplicate tab</value>
</data>
<data name="Duplicate.Text" xml:space="preserve">
<value>Duplicar</value>
<value>Duplicate</value>
</data>
<data name="DuplicateEnvironmentVariable" xml:space="preserve">
<value>No puedes asignar dos variables de entorno con el mismo nombre.</value>
<value>Cannot define two environment variables with the same name.</value>
</data>
<data name="EmptyEnvironmentVariableName" xml:space="preserve">
<value>No puedes definir una variable de entorno sin nombre.</value>
<value>Cannot define an environment variable without a name.</value>
</data>
<data name="EnvironmentVariables.Text" xml:space="preserve">
<value>Variables de entorno</value>
<value>Environment variables</value>
</data>
<data name="CloseSearchPanel.ToolTipService.ToolTip" xml:space="preserve">
<value>Cerrar panel de búsqueda</value>
<value>Close search panel</value>
</data>
<data name="FindNext.ToolTipService.ToolTip" xml:space="preserve">
<value>Buscar siguiente</value>
<value>Find next</value>
</data>
<data name="FindPrevious.ToolTipService.ToolTip" xml:space="preserve">
<value>Buscar anterior</value>
<value>Find previous</value>
</data>
<data name="SearchTextBox.PlaceholderText" xml:space="preserve">
<value>Ingrese el término de búsqueda</value>
<value>Enter search term</value>
</data>
<data name="Search.Text" xml:space="preserve">
<value>Buscar</value>
<value>Search</value>
</data>
<data name="PrintableOutputOnly.Content" xml:space="preserve">
<value>Solamente salida imprimible</value>
<value>Printable output only</value>
</data>
<data name="EnableLogging.Header" xml:space="preserve">
<value>Registar salida para debugeo</value>
<value>Log output for debugging</value>
</data>
<data name="WordSeparator.Header" xml:space="preserve">
<value>Caracteres separadores de palabras</value>
<value>Word separator characters</value>
</data>
<data name="Recent.Text" xml:space="preserve">
<value>Reciente</value>
<value>Recent</value>
</data>
<data name="NewTab_Description" xml:space="preserve">
<value>Abre el perfil predeterminado en una nueva pestaña.</value>
<value>Opens default profile in a new tab.</value>
</data>
<data name="NewSshTab_Description" xml:space="preserve">
<value>Abre una nueva sesión SSH o Mosh en una nueva pestaña.</value>
<value>Opens a new SSH or Mosh session in a new tab.</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>Abre el cuadro de diálogo &quot;Inicio rápido&quot; e inicia la sesión en una pestaña nueva.</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>Abrir ventana de opciones.</value>
<value>Opens settings window.</value>
</data>
<data name="About_Description" xml:space="preserve">
<value>Información básica sobre la app.</value>
<value>Basic info about the app.</value>
</data>
<data name="Recent_Description" xml:space="preserve">
<value>Sesiones abiertas recientemente.</value>
<value>Recently opened sessions.</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>Inicia una nueva sesión de terminal basada en el perfil predeterminado.</value>
<value>Starts new terminal session based on the default profile.</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>Conexión remota...</value>
<value>Remote Connect...</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>Abre un cuadro de diálogo para iniciar una nueva sesión de terminal SSH o 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>Comida rápida...</value>
<value>Quick Launch...</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>Abre un cuadro de diálogo &quot;Inicio rápido&quot; para iniciar una nueva sesión de terminal.</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>Nueva ventana</value>
<value>New Window</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>Nueva pestaña</value>
<value>New Tab</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>Inicia una sesión en una nueva pestaña.</value>
<value>Launches a session in a new tab.</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>Lanzar nueva sesión en una nueva ventana.</value>
<value>Launches a session in a new window.</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Tipo de menú de la aplicación</value>
<value>Application menu type</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Plano, honrando la configuración &quot;Abrir nuevos terminales como&quot;</value>
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>&quot;Nueva pestaña&quot; / &quot;Nueva ventana&quot; en cascada</value>
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>Salir</value>
<value>Quit</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Salir de Fluent Terminal</value>
<value>Quit Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Habilitado por la política.</value>
<value>Enabled by policy.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Imagen de fondo</value>
<value>Background image</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Usar fondo acrílico</value>
<value>Use acrylic background</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>¿Estás seguro de querer borrar esta imagen de fondo?</value>
<value>Are you sure you want to delete this background image?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colores</value>
<value>Colors</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Colores brillantes</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copiar enlace</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>Regex</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>Toda la palabra</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Distingue mayúsculas y minúsculas</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copiar selección o pegar</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Usar búfer inteligente</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
<value>Bright colors</value>
</data>
</root>
File diff suppressed because it is too large. Load diff
+51 -57
View File
@@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutDialog.Title" xml:space="preserve">
<value>À propos</value>
<value>A propos</value>
<comment>MainPage.xaml
Fuzzy</comment>
</data>
@@ -151,7 +151,7 @@ Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="ColorInactiveTabs.Text" xml:space="preserve">
<value>Couleur des onglets inactifs</value>
<value>Couleur sur les onglets inactifs</value>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="Command.Copy" xml:space="preserve">
@@ -164,7 +164,7 @@ Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="EditTitle.Text" xml:space="preserve">
<value>Éditer le titre</value>
<value>Editer le titre</value>
<comment>TabBar.xaml</comment>
</data>
<data name="General.Text" xml:space="preserve">
@@ -177,11 +177,11 @@ Fuzzy</comment>
Fuzzy</comment>
</data>
<data name="IndicatorOutput.Header" xml:space="preserve">
<value>Afficher l&apos;indicateur de nouvelle sortie sur les onglets en arrière-plan</value>
<value>Afficher le nouvel indicateur de sortie sur les onglets d’arrière-plan</value>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="NeedRelaunch.Text" xml:space="preserve">
<value>Redémarrage de l&apos;application requis pour appliquer le réglage</value>
<value>Relancement requis pour appliquer le réglage</value>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="NewTab.Text" xml:space="preserve">
@@ -658,6 +658,16 @@ Fuzzy</comment>
<data name="Command.CloseTab" xml:space="preserve">
<value>Fermer l&apos;onglet</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Nouvel onglet configurable</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Nouvelle fenêtre configurable</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
@@ -708,6 +718,14 @@ Fuzzy</comment>
<comment>Command
Fuzzy</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Début</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Choisissez un profil</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Afficher les paramètres</value>
<comment>Command
@@ -992,7 +1010,7 @@ Fuzzy</comment>
<value>Trouver le suivant</value>
</data>
<data name="FindPrevious.ToolTipService.ToolTip" xml:space="preserve">
<value>Trouver le précédent</value>
<value>Rechercher précédent</value>
</data>
<data name="SearchTextBox.PlaceholderText" xml:space="preserve">
<value>Entrez le terme de recherche</value>
@@ -1010,108 +1028,84 @@ Fuzzy</comment>
<value>Caractères séparateurs de mots</value>
</data>
<data name="Recent.Text" xml:space="preserve">
<value>Récent</value>
<value>Recent</value>
</data>
<data name="NewTab_Description" xml:space="preserve">
<value>Ouvrir le profile par défaut dans un nouvel onglet.</value>
<value>Opens default profile in a new tab.</value>
</data>
<data name="NewSshTab_Description" xml:space="preserve">
<value>Ouvrir une session SSH ou Msh dans un nouvel onglet.</value>
<value>Opens a new SSH or Mosh session in a new tab.</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>Ouvrir le dialogue &quot;Lancement rapide&quot; et commencer une session dans un nouvel onglet.</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>Ouvrir les paramètres.</value>
<value>Opens settings window.</value>
</data>
<data name="About_Description" xml:space="preserve">
<value>Informations sur l&apos;application.</value>
<value>Basic info about the app.</value>
</data>
<data name="Recent_Description" xml:space="preserve">
<value>Session récentes.</value>
<value>Recently opened sessions.</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>Commencer une nouvelle session du profil par défaut.</value>
<value>Starts new terminal session based on the default profile.</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>Connexion distante...</value>
<value>Remote Connect...</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>Ouvrir un dialogue pour une nouvelle session SSH ou 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>Lancement rapide...</value>
<value>Quick Launch...</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>Ouvrir un dialogue &quot;Lancement rapide&quot; pour un nouvelle session.</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>Nouvelle fenêtre.</value>
<value>New Window</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>Nouvel onglet.</value>
<value>New Tab</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>Lancer une session dans un nouvel onglet.</value>
<value>Launches a session in a new tab.</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>Lancer une session dans une nouvelle fenêtre.</value>
<value>Launches a session in a new window.</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>
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>&quot;Nouvel onglet&quot; / &quot;Nouvelle fenêtre&quot; en cascade.</value>
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>Quitter.</value>
<value>Quit</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Quitter Fluent Terminal</value>
<value>Quit Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Autorisé par la politique.</value>
<value>Enabled by policy.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Image de fond</value>
<value>Background image</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Utilise un fond acrylique.</value>
<value>Use acrylic background</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Êtes vous sûr de vouloir supprimer cette image de fond ?</value>
<value>Are you sure you want to delete this background image?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Couleurs</value>
<value>Colors</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Couleurs claires</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copier le lien</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>Expression régulière</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>Mot entier</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Sensible à la casse.</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copier la sélection ou coller</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Utiliser un tampon rapide</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Redémarrer</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Restart</value>
<value>Bright colors</value>
</data>
</root>
+16 -24
View File
@@ -644,6 +644,14 @@ Fuzzy</comment>
<value>סגור לשונית</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Configurable new tab</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Configurable new window</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>צירופי מקשים</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -684,6 +692,14 @@ Fuzzy</comment>
<value>סמן הכל</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>התחל</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>בחר פרופיל</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>הצג הגדרות</value>
<comment>Command</comment>
@@ -1037,28 +1053,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+16 -24
View File
@@ -637,6 +637,14 @@
<value>टैब बंद करें</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>कॉन्फ़िगर करने योग्य नया टैब</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>कॉन्फ़िगर करने योग्य नई विंडो</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>कुंजी बाइंडिंग</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>सभी का चयन करे</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>शुरू</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>प्रोफ़ाइल चुनें</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>सेटिंग दिखाएँ</value>
<comment>Command</comment>
@@ -1028,28 +1044,4 @@
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" 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
File diff suppressed because it is too large. Load diff
+35 -43
View File
@@ -641,6 +641,14 @@ Fuzzy</comment>
<value>Chiudi scheda</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Nuova scheda con profilo</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Nuova finestra con profilo</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Combinazioni di tasti</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -681,6 +689,14 @@ Fuzzy</comment>
<value>Seleziona tutto</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Avvia</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Seleziona profilo</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Mostra le impostazioni</value>
<comment>Command</comment>
@@ -969,7 +985,7 @@ Fuzzy</comment>
<value>Apre una sessione SSH o Mosh in una nuova scheda</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>Apre la schermata di &quot;Avvio rapido&quot; e avvia la sessione in una nuova scheda</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>Apre la finestra impostazioni</value>
@@ -981,87 +997,63 @@ Fuzzy</comment>
<value>Sessioni aperte di recente</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>Avvia una nuova sessione di terminale con il profilo predefinito</value>
<value>Starts new terminal session based on the default profile.</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>Connessione remota...</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>Apre una schermata per la creazione di una sessione SSH o 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>Avvio rapido...</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>Apre la schermata di &quot;Avvio rapido&quot; per una nuova sessione di terminale</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>Nuova finestra</value>
<value>New Window</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>Nuova scheda</value>
<value>New Tab</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>Avvia la sessione in una nuova scheda</value>
<value>Launches a session in a new tab.</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>Avvia la sessione in una nuova finestra</value>
<value>Launches a session in a new window.</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Formato menu applicazione</value>
<value>Application menu type</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Lineare, le azioni seguiranno l&apos;impostazione &quot;Apri i nuovi terminali come&quot;</value>
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>Menù a cascata &quot;Nuova Scheda&quot; / &quot;Nuova finestra&quot;</value>
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>Chiudi</value>
<value>Quit</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Chiudi Fluent Terminal</value>
<value>Quit Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Attivato da policy</value>
<value>Enabled by policy.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Immagine di sfondo</value>
<value>Background image</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Usa la sfumatura acrilica per lo sfondo</value>
<value>Use acrylic background</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Vuoi davvero eliminare questa immagine di sfondo?</value>
<value>Are you sure you want to delete this background image?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colori</value>
<value>Colors</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Colori brillanti</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copia link</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>Regex</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>Parola intera</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Sensibile a maiuscole/minuscole</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copia selezione o incolla</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Usa smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Riavvia</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Sessione terminata.</value>
<value>Bright colors</value>
</data>
</root>
+16 -24
View File
@@ -637,6 +637,14 @@
<value>タブを閉じる</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>新規タブ (プロファイル選択可能)</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>新規ウィンドウ (プロファイル選択可能)</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>キー割り当て</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>すべて選択</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>開始</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>プロファイル選択</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>設定表示</value>
<comment>Command</comment>
@@ -1028,28 +1044,4 @@
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+16 -24
View File
@@ -641,6 +641,14 @@ Fuzzy</comment>
<value>탭 닫기</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>설정 가능한 새 탭</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>설정 가능한 새 창</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>키 설정</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -681,6 +689,14 @@ Fuzzy</comment>
<value>모두 선택</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>시작</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>프로필 선택</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>설정 표시</value>
<comment>Command</comment>
@@ -1037,28 +1053,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+18 -24
View File
@@ -659,6 +659,16 @@ Fuzzy</comment>
<data name="Command.CloseTab" xml:space="preserve">
<value>Sluit tab</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Configureerbaare nieuwe tab</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Configureerbaar nieuwe window</value>
<comment>Command
Fuzzy</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
@@ -709,6 +719,14 @@ Fuzzy</comment>
<comment>Command
Fuzzy</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Start</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Selecteer Profiel</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Laat settings zien</value>
<comment>Command
@@ -1092,28 +1110,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+16 -24
View File
@@ -638,6 +638,14 @@ Fuzzy</comment>
<value>Zamknij kartę</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Konfigurowalna nowa karta</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Konfigurowalne nowe okno</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Skróty klawiszowe</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -678,6 +686,14 @@ Fuzzy</comment>
<value>Zaznacz wszysto</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Start</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Wybierz profil</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Pokaż ustawienia</value>
<comment>Command</comment>
@@ -1029,28 +1045,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+16 -24
View File
@@ -638,6 +638,14 @@ Fuzzy</comment>
<value>Fechar aba</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Nova aba configurável</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Nova janela configurável</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Teclas associadas</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -678,6 +686,14 @@ Fuzzy</comment>
<value>Selecionar tudo</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Iniciar</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Selecionar Perfil</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Exibir configurações</value>
<comment>Command</comment>
@@ -1029,28 +1045,4 @@ Fuzzy</comment>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+21 -29
View File
@@ -637,6 +637,14 @@
<value>Închideți fila</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Filă nouă configurabilă</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Fereastră nouă configurabilă</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Legături de taste</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>Selectează tot</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Start</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Selectați profilul</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Afișare setări</value>
<comment>Command</comment>
@@ -1014,42 +1030,18 @@
<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>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copiere 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>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Potrivire litere</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copiați selecția sau lipiți</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Folosiți tampon inteligent</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Repornire</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Sesiunea a fost deconectată.</value>
<value>Bright colors</value>
</data>
</root>
+23 -31
View File
@@ -637,6 +637,14 @@
<value>Закрыть вкладку</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Настраиваемая новая вкладка</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Настраиваемое новое окно</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Горячие клавиши</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>Выделить всё</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Старт</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Выбрать профиль</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Показать настройки</value>
<comment>Command</comment>
@@ -996,10 +1012,10 @@
<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>Плоская, с учетом настройки &quot;Открыть новый терминал как&quot;</value>
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>Открывать новые окна и вкладки каскадом.</value>
@@ -1015,42 +1031,18 @@
<comment>There should be something explaining by what &quot;policy&quot; this was enabled? (e.g. &quot;local policy&quot; or smth.)</comment>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Фоновое изображение</value>
<value>Background image</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>
<value>Colors</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Яркие цвета</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Скопировать ссылку</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>Регулярные выражения</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>Целый мир</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Деликатный случай</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Скопировать выделение или вставить</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
<value>Bright colors</value>
</data>
</root>
File diff suppressed because it is too large. Load diff
+16 -24
View File
@@ -637,6 +637,14 @@
<value>Закрити вкладку</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>Налаштувати нову вкладку</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>Налаштувати нове вікно</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>Гарячі клавіші</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -677,6 +685,14 @@
<value>Виділити все</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>Почати</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>Обрати профіль</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>Показати налаштування</value>
<comment>Command</comment>
@@ -1028,28 +1044,4 @@
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
</data>
<data name="CopyLink" xml:space="preserve">
<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>Whole word</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>Case sensitive</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>Copy selection or paste</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
@@ -119,103 +119,83 @@
</resheader>
<data name="AboutDialog.Title" xml:space="preserve">
<value>关于</value>
<comment>MainPage.xaml
Fuzzy</comment>
<comment>MainPage.xaml</comment>
</data>
<data name="Background.Content" xml:space="preserve">
<value>背景色</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="TabTheme.Blue" xml:space="preserve">
<value>蓝色</value>
<comment>TabBar.xaml
Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="Close" xml:space="preserve">
<value>关闭</value>
<comment>TabBar.xaml
Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="ConfirmWindowClosing.Header" xml:space="preserve">
<value>在关闭窗口之前询问</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="ConfirmTabClosing.Header" xml:space="preserve">
<value>在关闭标签页之前询问</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="Color.Text" xml:space="preserve">
<value>标签颜色</value>
<comment>TabBar.xaml
Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="ColorInactiveTabs.Text" xml:space="preserve">
<value>非活动选项卡上的颜色</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="Command.Copy" xml:space="preserve">
<value>复制</value>
<comment>XtermTerminalView.xaml.cs
Fuzzy</comment>
<comment>XtermTerminalView.xaml.cs</comment>
</data>
<data name="CustomTitle.Header" xml:space="preserve">
<value>在标题栏显示自定义标题</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="EditTitle.Text" xml:space="preserve">
<value>修改标题</value>
<comment>TabBar.xaml
Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="General.Text" xml:space="preserve">
<value>常规</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="TabTheme.Green" xml:space="preserve">
<value>绿色</value>
<comment>TabBar.xaml
Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="IndicatorOutput.Header" xml:space="preserve">
<value>非活动选项卡输出提示</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="NeedRelaunch.Text" xml:space="preserve">
<value>下次启动生效</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="NewTab.Text" xml:space="preserve">
<value>新标签页</value>
<comment>MainPage.xaml
Fuzzy</comment>
<comment>MainPage.xaml</comment>
</data>
<data name="TabTheme.None" xml:space="preserve">
<value>无</value>
<comment>TabBar.xaml
Fuzzy</comment>
<comment>TabBar.xaml</comment>
</data>
<data name="ONTA_Tabs.Content" xml:space="preserve">
<value>新的标签页</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="ONTA_Windows.Content" xml:space="preserve">
<value>新的窗口</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="OpenNewTerminalAs.Text" xml:space="preserve">
<value>打开新的终端</value>
<comment>GeneralSettings.xaml
Fuzzy</comment>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="TabTheme.Orange" xml:space="preserve">
<value>橙色</value>
@@ -386,7 +366,7 @@ Fuzzy</comment>
<comment>ShellProfileSettings.xaml</comment>
</data>
<data name="LineEndingStyle.DoNotModify" xml:space="preserve">
<value>不改变结束行</value>
<value>不改变</value>
<comment>ShellProfileSettings.xaml</comment>
</data>
<data name="EditAppBarButton.Label" xml:space="preserve">
@@ -446,7 +426,7 @@ Fuzzy</comment>
<comment>MouseSettings.xaml</comment>
</data>
<data name="MouseNothing.Content" xml:space="preserve">
<value>没做什么</value>
<value>无</value>
<comment>MouseSettings.xaml</comment>
</data>
<data name="MousePaste.Content" xml:space="preserve">
@@ -657,6 +637,14 @@ Fuzzy</comment>
<value>关闭标签页</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewTab" xml:space="preserve">
<value>新的标签页(自定义配置)</value>
<comment>Command</comment>
</data>
<data name="Command.ConfigurableNewWindow" xml:space="preserve">
<value>新的窗口(自定义配置)</value>
<comment>Command</comment>
</data>
<data name="Keybindings.Text" xml:space="preserve">
<value>快捷键</value>
<comment>KeyBindingSettings.xaml</comment>
@@ -697,6 +685,14 @@ Fuzzy</comment>
<value>全选</value>
<comment>Command</comment>
</data>
<data name="SelectProfileUI.PrimaryButtonText" xml:space="preserve">
<value>启动</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="SelectProfileUI.Title" xml:space="preserve">
<value>选择一个配置</value>
<comment>ShellProfileSelectionDialog.xaml</comment>
</data>
<data name="Command.ShowSettings" xml:space="preserve">
<value>显示设置</value>
<comment>Command</comment>
@@ -974,102 +970,78 @@ Fuzzy</comment>
<value>在新标签打开默认配置。</value>
</data>
<data name="NewSshTab_Description" xml:space="preserve">
<value>从新标签页打开SSH或Mosh会话</value>
<value>在新标签打开 SSH 或 Mosh 会话。</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>打开“快速启动”对话框并在新标签中开启会话。</value>
</data>
<data name="Settings_Description" xml:space="preserve">
<value>打开设置页面</value>
<value>打开设置窗口。</value>
</data>
<data name="About_Description" xml:space="preserve">
<value>关于</value>
<value>关于应用的基本信息。</value>
</data>
<data name="Recent_Description" xml:space="preserve">
<value>最近打开的会话</value>
<value>最近打开的会话。</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>基于默认配置开启新的终端会话。</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>远程连接</value>
<value>远程连接……</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>打开对话框开启新的 SSH 或 Mosh 终端会话。</value>
</data>
<data name="MenuItem_QuickLaunch_Text" xml:space="preserve">
<value>快捷启动</value>
<value>快速启动……</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>打开“快速启动”对话框并开启终端会话。</value>
</data>
<data name="MenuItem_NewWindow_Text" xml:space="preserve">
<value>新建窗口</value>
<value>新窗口</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>新建标签页</value>
<value>新标签页</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>从新标签页启动会话</value>
<value>在新标签页中打开会话</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>从新窗口启动会话</value>
<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>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>退出关于</value>
<value>Quit Fluent Terminal</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>
<value>Background image</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>
<value>Colors</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>亮色</value>
</data>
<data name="CopyLink" xml:space="preserve">
<value>复制链接</value>
</data>
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
<value>正则表达式</value>
</data>
<data name="SearchWholeWord.ToolTipService.ToolTip" xml:space="preserve">
<value>全字匹配</value>
</data>
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
<value>大小写敏感</value>
</data>
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
<value>复制或者粘贴选中的文本</value>
</data>
<data name="UseBuffer" xml:space="preserve">
<value>Use smart buffer</value>
</data>
<data name="RestartSession.Content" xml:space="preserve">
<value>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
<value>Bright colors</value>
</data>
</root>
File diff suppressed because it is too large. Load diff
+3 -2
View File
@@ -14,6 +14,7 @@
</Page.Background>
<Page.Resources>
<converters:TerminalViewModelToViewConverter x:Key="TerminalViewModelToViewConverter" />
<converters:AppMenuViewModelToFlyoutMenuConverter x:Key="AppMenuViewModelToFlyoutMenuConverter" />
</Page.Resources>
<Grid x:Name="Root">
<Grid.Background>
@@ -39,10 +40,10 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Flyout="{x:Bind ViewModel.AppMenuViewModel, Mode=OneWay, Converter={StaticResource MenuViewModelToFlyoutMenuConverter}}" Style="{StaticResource TitleBarButtonStyle}">
<Button Flyout="{x:Bind ViewModel.MenuViewModel, Mode=OneWay, Converter={StaticResource AppMenuViewModelToFlyoutMenuConverter}}" Style="{StaticResource TitleBarButtonStyle}">
<Button.Content>
<Viewbox Width="16" Height="16">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE700;" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE700;" />
</Viewbox>
</Button.Content>
</Button>
+10 -14
View File
@@ -2,28 +2,24 @@
x:Class="FluentTerminal.App.Views.OverlayView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:FluentTerminal.App.ViewModels"
d:DesignHeight="300"
d:DesignWidth="600"
Visibility="{Binding ShowOverlay, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}"
mc:Ignorable="d">
mc:Ignorable="d"
Visibility="{Binding ShowOverlay, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<UserControl.DataContext>
<viewModels:OverlayViewModel />
</UserControl.DataContext>
<controls:DropShadowPanel
<Grid
Margin="12"
Padding="6"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
ShadowOpacity="0.5"
Color="Black">
<Grid Padding="6" CornerRadius="4">
<Grid.Background>
<SolidColorBrush Color="{ThemeResource SystemAccentColor}" />
</Grid.Background>
<TextBlock Foreground="White" Text="{Binding OverlayContent}" />
</Grid>
</controls:DropShadowPanel>
VerticalAlignment="Bottom">
<Grid.Background>
<SolidColorBrush Color="{ThemeResource SystemAccentColor}" />
</Grid.Background>
<TextBlock Foreground="White" Text="{Binding OverlayContent}" />
</Grid>
</UserControl>
+15 -15
View File
@@ -33,8 +33,8 @@
Tag="general">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE713;"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="e"
ToolTipService.ToolTip="General" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -44,8 +44,8 @@
Tag="terminal">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE771;"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="d"
ToolTipService.ToolTip="Terminal" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -55,8 +55,8 @@
Tag="profiles">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE756;"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="a"
ToolTipService.ToolTip="Shell" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -66,8 +66,8 @@
Tag="sshprofiles">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE774;"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="a"
ToolTipService.ToolTip="Shell" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -77,8 +77,8 @@
Tag="keyBindings">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE765;"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="b"
ToolTipService.ToolTip="Keybindings" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -88,9 +88,9 @@
Tag="mouse">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE962;"
ToolTipService.ToolTip="Mouse" />
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="g"
ToolTipService.ToolTip="Keybindings" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
<controls:NavigationViewItem
@@ -99,8 +99,8 @@
Tag="themes">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE790;"
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="c"
ToolTipService.ToolTip="Themes" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -2,9 +2,9 @@
x:Class="FluentTerminal.App.Views.SettingsPages.GeneralSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:FluentTerminal.App.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="using:FluentTerminal.App.Converters"
mc:Ignorable="d">
<Page.Resources>
@@ -24,6 +24,7 @@
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="General"
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
@@ -177,12 +178,6 @@
Header="Show new output indicator on background tabs"
IsOn="{x:Bind ViewModel.ShowNewOutputIndicator, Mode=TwoWay}" />
<ToggleSwitch
x:Uid="CopiedNotification"
Margin="{StaticResource ItemMargin}"
Header="Text copied notification"
IsOn="{x:Bind ViewModel.ShowTextCopied, Mode=TwoWay}" />
<ToggleSwitch
x:Uid="UseMoshByDefault"
Margin="{StaticResource ItemMargin}"
@@ -215,20 +210,19 @@
<CheckBox
x:Uid="PrintableOutputOnly"
Content="Printable output only"
IsChecked="{x:Bind ViewModel.PrintableOutputOnly, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}" />
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}"
IsChecked="{x:Bind ViewModel.PrintableOutputOnly, Mode=TwoWay}" />
<StackPanel Orientation="Horizontal" Spacing="5">
<TextBox
x:Uid="LogDirectoryPath"
MinWidth="250"
MaxWidth="250"
Text="{x:Bind ViewModel.LogDirectoryPath, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}"
Text="{x:Bind ViewModel.LogDirectoryPath, Mode=TwoWay}" />
MaxWidth="250" MinWidth="250" />
<Button
x:Uid="BrowseButton"
Command="{x:Bind ViewModel.BrowseLogDirectoryCommand}"
Content="Browse"
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}" />
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}"/>
</StackPanel>
</StackPanel>
@@ -19,10 +19,11 @@
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="Keybindings"
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
x:Uid="Keybindings"
Text="Keybindings" />
<CommandBar
Grid.Column="1"
@@ -30,19 +31,16 @@
VerticalAlignment="Top"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
x:Uid="AddAppBarButton"
Icon="Add"
Label="Add">
<AppBarButton x:Uid="AddAppBarButton" Icon="Add" Label="Add">
<AppBarButton.Flyout>
<MenuFlyout x:Name="AddCommandMenu" />
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton
x:Uid="Restore"
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
CommandParameter="keyBindings"
Icon="Undo"
x:Uid="Restore"
Label="Restore Defaults" />
</CommandBar>
</Grid>
@@ -18,10 +18,11 @@
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="Mouse"
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
x:Uid="Mouse"
Text="Mouse" />
<CommandBar
Grid.Column="1"
@@ -30,25 +31,22 @@
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
DefaultLabelPosition="Right">
<AppBarButton
x:Uid="Restore"
Command="{x:Bind ViewModel.RestoreDefaultsCommand}"
Icon="Undo"
x:Uid="Restore"
Label="Restore Defaults" />
</CommandBar>
</Grid>
<ScrollViewer Grid.Row="2">
<StackPanel Margin="{StaticResource ContainerMargin}">
<ToggleSwitch
x:Uid="CopyOnSelect"
Margin="{StaticResource ItemMargin}"
x:Uid="CopyOnSelect"
Header="Copy on select"
IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}" />
<StackPanel Margin="{StaticResource ItemMargin}">
<TextBlock
x:Uid="MiddleButtonAction"
Margin="0,0,0,8"
Text="Middle button action" />
<TextBlock Margin="0,0,0,8" x:Uid="MiddleButtonAction" Text="Middle button action" />
<RadioButton
x:Uid="MouseNothing"
Content="Nothing"
@@ -64,18 +62,10 @@
Content="Paste"
GroupName="MiddleButton"
IsChecked="{x:Bind ViewModel.MouseMiddleClickPasteIsSelected, Mode=TwoWay}" />
<RadioButton
x:Uid="MouseCopySelectionOrPaste"
Content="Copy selection or paste"
GroupName="MiddleButton"
IsChecked="{x:Bind ViewModel.MouseMiddleClickCopySelectionOrPasteIsSelected, Mode=TwoWay}" />
</StackPanel>
<StackPanel Margin="{StaticResource ItemMargin}">
<TextBlock
x:Uid="RightButtonAction"
Margin="0,0,0,8"
Text="Right button action" />
<TextBlock Margin="0,0,0,8" x:Uid="RightButtonAction" Text="Right button action" />
<RadioButton
x:Uid="MouseNothing"
Content="Nothing"
@@ -91,11 +81,6 @@
Content="Paste"
GroupName="RightButton"
IsChecked="{x:Bind ViewModel.MouseRightClickPasteIsSelected, Mode=TwoWay}" />
<RadioButton
x:Uid="MouseCopySelectionOrPaste"
Content="Copy selection or paste"
GroupName="RightButton"
IsChecked="{x:Bind ViewModel.MouseRightClickCopySelectionOrPasteIsSelected, Mode=TwoWay}" />
</StackPanel>
</StackPanel>
</ScrollViewer>
@@ -249,12 +249,18 @@
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsOn="{x:Bind ProfileVm.UseConPty, Mode=TwoWay}" />
<ToggleSwitch
x:Uid="UseBuffer"
<ComboBox
x:Uid="LineEndingMode"
Margin="{StaticResource ItemMargin}"
Header="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseBuffer}"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsOn="{x:Bind ProfileVm.UseBuffer, Mode=TwoWay}" />
VerticalAlignment="Center"
ItemsSource="{x:Bind ProfileVm.LineEndingStyles}"
SelectedItem="{Binding ProfileVm.LineEndingTranslation, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="enums:LineEndingStyle">
<TextBlock Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=LineEndingStyle}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel Margin="{StaticResource ItemMargin}">
<TextBlock
@@ -350,18 +356,6 @@
FontWeight="Light" />
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
Margin="{StaticResource ItemMargin}"
HorizontalContentAlignment="Stretch"
Header="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseBuffer}">
<ContentControl
Margin="0,6,0,0"
Content="{x:Bind ProfileVm.UseBuffer, Mode=OneWay}"
ContentTemplateSelector="{StaticResource UseConPtyTemplateSelector}"
FontSize="18"
FontWeight="Light" />
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
Margin="{StaticResource ItemMargin}"
HorizontalContentAlignment="Stretch"
@@ -386,6 +380,18 @@
</ItemsControl>
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
x:Uid="LineEndingMode"
Margin="{StaticResource ItemMargin}"
HorizontalContentAlignment="Stretch"
Header="Line ending translation mode">
<ContentControl
Content="{x:Bind ProfileVm.LineEndingTranslation, Mode=OneWay, Converter={StaticResource I18NConverter}, ConverterParameter=LineEndingStyle}"
ContentTemplateSelector="{StaticResource TerminalThemeTemplateSelector}"
FontSize="18"
FontWeight="Light" />
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
x:Uid="KeyboardShortcut"
Margin="{StaticResource ItemMargin}"
@@ -291,12 +291,6 @@
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsOn="{x:Bind ProfileVm.UseConPty, Mode=TwoWay}" />
<ToggleSwitch
Margin="{StaticResource ItemMargin}"
Header="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseBuffer}"
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsOn="{x:Bind ProfileVm.UseBuffer, Mode=TwoWay}" />
<StackPanel Margin="{StaticResource ItemMargin}">
<TextBlock
x:Uid="EnvironmentVariables"
@@ -305,6 +299,19 @@
<views:EnvironmentVariablesView EnvironmentVariables="{x:Bind EnvironmentVariables, Mode=OneWay}" />
</StackPanel>
<ComboBox
x:Uid="LineEndingMode"
Margin="{StaticResource ItemMargin}"
VerticalAlignment="Center"
ItemsSource="{x:Bind ProfileVm.LineEndingStyles}"
SelectedItem="{Binding ProfileVm.LineEndingTranslation, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="enums:LineEndingStyle">
<TextBlock Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=LineEndingStyle}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel Margin="{StaticResource ItemMargin}">
<TextBlock
x:Uid="KeyboardShortcut1"
@@ -468,19 +475,6 @@
FontWeight="Light" />
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
Margin="{StaticResource ItemMargin}"
HorizontalContentAlignment="Stretch"
DataContext="{Binding ProfileVm}"
Header="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=UseBuffer}">
<ContentControl
Margin="0,6,0,0"
Content="{Binding UseBuffer, Mode=OneWay}"
ContentTemplateSelector="{StaticResource UseConPtyTemplateSelector}"
FontSize="18"
FontWeight="Light" />
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
Margin="{StaticResource ItemMargin}"
HorizontalContentAlignment="Stretch"
@@ -505,6 +499,19 @@
</ItemsControl>
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
x:Uid="LineEndingMode"
Margin="{StaticResource ItemMargin}"
HorizontalContentAlignment="Stretch"
DataContext="{Binding ProfileVm}"
Header="Line ending translation mode">
<ContentControl
Content="{Binding LineEndingTranslation, Mode=OneWay, Converter={StaticResource I18NConverter}, ConverterParameter=LineEndingStyle}"
ContentTemplateSelector="{StaticResource TerminalThemeTemplateSelector}"
FontSize="18"
FontWeight="Light" />
</controls:HeaderedContentControl>
<controls:HeaderedContentControl
x:Uid="KeyboardShortcut"
Margin="{StaticResource ItemMargin}"
@@ -23,6 +23,7 @@
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="Terminal"
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
@@ -165,6 +166,12 @@
IsChecked="{x:Bind ViewModel.VisibleIsSelected, Mode=TwoWay}" />
</StackPanel>
<ToggleSwitch
x:Uid="CopiedNotification"
Margin="{StaticResource ItemMargin}"
Header="Text copied notification"
IsOn="{x:Bind ViewModel.ShowTextCopied, Mode=TwoWay}" />
<TextBox
x:Uid="WordSeparator"
Width="200"
@@ -58,7 +58,7 @@
Command="{x:Bind ViewModel.SelectedTheme.ExportCommand, Mode=OneWay}"
Label="Export">
<AppBarButton.Icon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xEE71;" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEE71;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
+108 -11
View File
@@ -2,10 +2,10 @@
x:Class="FluentTerminal.App.Views.TabBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:FluentTerminal.App.Behaviors"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:utilities="using:FluentTerminal.App.Utilities"
xmlns:viewmodels="using:FluentTerminal.App.ViewModels"
@@ -28,12 +28,12 @@
Padding="0,0,0,0"
Click="OnScrollLeftButtonTapped"
Style="{StaticResource TitleBarRepeatButtonStyle}"
Tapped="OnScrollLeftButtonTapped"
ToolTipService.ToolTip="Scroll left"
Visibility="Collapsed">
Visibility="Collapsed"
Tapped="OnScrollLeftButtonTapped">
<RepeatButton.Content>
<Viewbox Width="12" Height="12">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE76B;" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76B;" />
</Viewbox>
</RepeatButton.Content>
</RepeatButton>
@@ -68,7 +68,6 @@
Height="32"
Margin="0"
Background="Transparent"
ContextFlyout="{x:Bind TabContextMenu, Converter={StaticResource MenuViewModelToFlyoutMenuConverter}, Mode=OneWay}"
ToolTipService.ToolTip="{x:Bind TabTitle, Mode=OneWay}">
<interactivity:Interaction.Behaviors>
@@ -79,10 +78,108 @@
</behaviors:MiddleClickBehavior>
</interactivity:Interaction.Behaviors>
<RelativePanel.ContextFlyout>
<MenuFlyout>
<MenuFlyoutSubItem x:Uid="Color">
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="0"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=0}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.None}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xF126;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="1"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=1}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.Red}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Foreground="#E81123"
Glyph="&#xF127;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="2"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=2}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.Green}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Foreground="#10893E"
Glyph="&#xF127;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="3"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=3}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.Blue}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Foreground="#0078D7"
Glyph="&#xF127;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="4"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=4}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.Purple}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Foreground="#881798"
Glyph="&#xF127;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="5"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=5}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.Orange}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Foreground="#FF8C00"
Glyph="&#xF127;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
<ToggleMenuFlyoutItem
Command="{x:Bind SelectTabThemeCommand}"
CommandParameter="6"
IsChecked="{x:Bind TabTheme, Mode=OneWay, Converter={StaticResource TabThemeSelectedConverter}, ConverterParameter=6}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=TabTheme.Teal}">
<ToggleMenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
Foreground="#00B7C3"
Glyph="&#xF127;" />
</ToggleMenuFlyoutItem.Icon>
</ToggleMenuFlyoutItem>
</MenuFlyoutSubItem>
<MenuFlyoutItem x:Uid="EditTitle" Command="{x:Bind EditTitleCommand}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="Duplicate" Command="{x:Bind DuplicateTabCommand}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="CloseLeft" Command="{x:Bind CloseLeftTabsCommand}" />
<MenuFlyoutItem x:Uid="CloseRight" Command="{x:Bind CloseRightTabsCommand}" />
<MenuFlyoutItem x:Uid="CloseOther" Command="{x:Bind CloseOtherTabsCommand}" />
<MenuFlyoutItem
x:Uid="Close"
Command="{x:Bind CloseCommand}"
Text="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=Close}" />
</MenuFlyout>
</RelativePanel.ContextFlyout>
<Border
Height="3"
VerticalAlignment="Bottom"
Background="{x:Bind TabTheme.Theme.Color, Mode=OneWay, Converter={StaticResource ColorResourceKeyFallbackConverter}, ConverterParameter=SystemControlHighlightAccentBrush}"
Background="{x:Bind TabTheme.Color, Mode=OneWay, Converter={StaticResource ColorResourceKeyFallbackConverter}, ConverterParameter=SystemControlHighlightAccentBrush}"
RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
@@ -99,7 +196,7 @@
Height="12"
VerticalAlignment="Center"
ToolTipService.ToolTip="Exited with error">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE814;" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE814;" />
</Viewbox>
</Grid>
<TextBlock
@@ -131,7 +228,7 @@
Height="12"
VerticalAlignment="Center"
ToolTipService.ToolTip="New output">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xEA38;" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEA38;" />
</Viewbox>
</Grid>
</Grid>
@@ -263,12 +360,12 @@
Padding="0,0,0,0"
Click="OnScrollRightButtonTapped"
Style="{StaticResource TitleBarRepeatButtonStyle}"
Tapped="OnScrollRightButtonTapped"
ToolTipService.ToolTip="Scroll right"
Visibility="Collapsed">
Visibility="Collapsed"
Tapped="OnScrollRightButtonTapped">
<RepeatButton.Content>
<Viewbox Width="12" Height="12">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE76C;" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76C;" />
</Viewbox>
</RepeatButton.Content>
</RepeatButton>
+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="Segoe MDL2 Assets"
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="Segoe MDL2 Assets"
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>
+54 -140
View File
@@ -2,10 +2,6 @@
x:Class="FluentTerminal.App.Views.TerminalView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:actions="using:FluentTerminal.App.Actions"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:FluentTerminal.App.Views"
@@ -14,144 +10,62 @@
mc:Ignorable="d">
<Grid>
<Grid x:Name="TerminalContainer" />
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="TerminalContainer" Grid.Row="0" />
<views:OverlayView x:Name="MessageOverlay" />
<controls:DropShadowPanel
Height="64"
Margin="12"
HorizontalAlignment="Right"
VerticalAlignment="Top"
ShadowOpacity="0.5"
Visibility="{x:Bind ViewModel.ShowSearchPanel, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}"
Color="Black">
<StackPanel
Padding="6"
Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}"
CornerRadius="4"
Orientation="Horizontal">
<Viewbox
Width="16"
Height="16"
Margin="6,0,0,0">
<SymbolIcon Symbol="Find" />
</Viewbox>
<TextBox
Name="SearchTextBox"
x:Uid="SearchTextBox"
Width="200"
Margin="6,0,6,0"
Background="Transparent"
BorderThickness="0"
IsTabStop="True"
KeyUp="OnSearchTextBoxKeyUp"
PlaceholderText="Enter search term"
Text="{x:Bind ViewModel.SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{x:Bind ViewModel.ShowSearchPanel, Mode=OneWay}" Value="true">
<actions:FocusAction />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBox>
<ToggleButton
x:Uid="SearchCaseSensitive"
Background="Transparent"
IsChecked="{x:Bind ViewModel.SearchMatchCase, Mode=TwoWay}"
ToolTipService.ToolTip="Case sensitive">
<Viewbox Width="16" Height="16">
<TextBlock Text="Aa" />
</Viewbox>
</ToggleButton>
<ToggleButton
x:Uid="SearchWholeWord"
Margin="2,0,2,0"
Background="Transparent"
IsChecked="{x:Bind ViewModel.SearchWholeWord, Mode=TwoWay}"
ToolTipService.ToolTip="Whole word">
<Viewbox Width="16" Height="16">
<TextBlock Text="Ab" TextDecorations="Underline" />
</Viewbox>
</ToggleButton>
<ToggleButton
x:Uid="SearchWithRegex"
Background="Transparent"
IsChecked="{x:Bind ViewModel.SearchWithRegex, Mode=TwoWay}"
ToolTipService.ToolTip="Regex">
<Viewbox Width="16" Height="16">
<TextBlock Text=".*" />
</Viewbox>
</ToggleButton>
<Button
Name="PreviousButton"
x:Uid="FindPrevious"
Margin="6,0,0,0"
Background="Transparent"
Command="{x:Bind ViewModel.FindPreviousCommand}"
ToolTipService.ToolTip="Find previous">
<Button.Content>
<Viewbox Width="16" Height="16">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE971;" />
</Viewbox>
</Button.Content>
</Button>
<Button
x:Uid="FindNext"
Margin="0,0,6,0"
Background="Transparent"
Command="{x:Bind ViewModel.FindNextCommand}"
ToolTipService.ToolTip="Find next">
<Button.Content>
<Viewbox Width="16" Height="16">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE972;" />
</Viewbox>
</Button.Content>
</Button>
<Button
x:Uid="CloseSearchPanel"
Background="Transparent"
Command="{x:Bind ViewModel.CloseSearchPanelCommand}"
ToolTipService.ToolTip="Close search panel">
<Button.Content>
<Viewbox Width="16" Height="16">
<SymbolIcon Symbol="Cancel" />
</Viewbox>
</Button.Content>
</Button>
</StackPanel>
</controls:DropShadowPanel>
<controls:DropShadowPanel
Margin="12"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
ShadowOpacity="0.5"
Visibility="{x:Bind ViewModel.HasExitedWithError, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}"
Color="Black">
<StackPanel
Padding="6"
CornerRadius="4"
Orientation="Horizontal">
<StackPanel.Background>
<SolidColorBrush Color="{ThemeResource SystemAccentColor}" />
</StackPanel.Background>
<TextBlock
x:Uid="SessionDisconnected"
Margin="6,0,24,0"
VerticalAlignment="Center"
Text="Session disconnected" />
<Button
x:Uid="RestartSession"
Margin="0,0,6,0"
Command="{x:Bind ViewModel.ReconnectTabCommand, Mode=OneWay}"
Content="Restart"
IsEnabled="{x:Bind ViewModel.HasExitedWithError, Mode=OneWay}" />
<Button Command="{x:Bind ViewModel.CloseCommand, Mode=OneWay}" Content="{x:Bind Converter={StaticResource I18NConverter}, ConverterParameter=Close}" />
</StackPanel>
</controls:DropShadowPanel>
<RelativePanel
Grid.Row="1"
Padding="12"
Visibility="{x:Bind ViewModel.ShowSearchPanel, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
<TextBlock
x:Uid="Search"
Name="SearchLabel"
Margin="0,6,0,0"
RelativePanel.AlignLeftWithPanel="True"
Text="Search" />
<TextBox
x:Uid="SearchTextBox"
Name="SearchTextBox"
Width="300"
Margin="6,0,6,0"
KeyUp="OnSearchTextBoxKeyUp"
PlaceholderText="Enter search term"
RelativePanel.RightOf="SearchLabel"
Text="{x:Bind ViewModel.SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
x:Uid="FindPrevious"
Name="PreviousButton"
Margin="0,0,6,0"
Command="{x:Bind ViewModel.FindPreviousCommand}"
RelativePanel.RightOf="SearchTextBox"
ToolTipService.ToolTip="Find previous">
<Button.Content>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76B;" />
</Button.Content>
</Button>
<Button
x:Uid="FindNext"
Command="{x:Bind ViewModel.FindNextCommand}"
RelativePanel.RightOf="PreviousButton"
ToolTipService.ToolTip="Find next">
<Button.Content>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76C;" />
</Button.Content>
</Button>
<Button
x:Uid="CloseSearchPanel"
Command="{x:Bind ViewModel.CloseSearchPanelCommand}"
RelativePanel.AlignRightWithPanel="True"
ToolTipService.ToolTip="Close search panel">
<Button.Content>
<SymbolIcon Symbol="Cancel" />
</Button.Content>
</Button>
</RelativePanel>
</Grid>
</UserControl>
@@ -8,6 +8,7 @@ using GalaSoft.MvvmLight.Messaging;
using FluentTerminal.Models;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using FluentTerminal.App.Utilities;
using Windows.UI;
namespace FluentTerminal.App.Views
@@ -65,12 +66,12 @@ namespace FluentTerminal.App.Views
_terminalView?.FocusTerminalAsync();
}
private void OnFindNextRequested(object sender, SearchRequest e)
private void OnFindNextRequested(object sender, string e)
{
_terminalView.FindNextAsync(e);
}
private void OnFindPreviousRequested(object sender, SearchRequest e)
private void OnFindPreviousRequested(object sender, string e)
{
_terminalView.FindPreviousAsync(e);
}
@@ -98,7 +99,7 @@ namespace FluentTerminal.App.Views
}
else if (e.Key == VirtualKey.Enter)
{
ViewModel.FindPreviousCommand.Execute(null);
ViewModel.FindNextCommand.Execute(null);
}
}
@@ -1,5 +1,6 @@
using FluentTerminal.App.Converters;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.App.Utilities;
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
@@ -12,19 +13,21 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
namespace FluentTerminal.App.Views
{
// ReSharper disable once RedundantExtendsListEntry
public sealed partial class XtermTerminalView : UserControl, IxtermEventListener, ITerminalView
{
private readonly MenuFlyoutItem _copyMenuItem;
private readonly MenuFlyoutItem _pasteMenuItem;
private WebView _webView;
private readonly DelayedAction<TerminalOptions> _optionsChanged;
private TerminalBridge _terminalBridge;
@@ -117,7 +120,6 @@ namespace FluentTerminal.App.Views
#endregion Resize handling
public event EventHandler<object> OnOutput;
public event EventHandler<string> OnPaste;
public XtermTerminalView()
{
@@ -133,6 +135,17 @@ namespace FluentTerminal.App.Views
_webView.NavigationStarting += _webView_NavigationStarting;
_webView.NewWindowRequested += _webView_NewWindowRequested;
_copyMenuItem = new MenuFlyoutItem { Text = I18N.Translate("Command.Copy") };
_copyMenuItem.Click += Copy_Click;
_pasteMenuItem = new MenuFlyoutItem { Text = I18N.Translate("Command.Paste") };
_pasteMenuItem.Click += Paste_Click;
_webView.ContextFlyout = new MenuFlyout
{
Items = { _copyMenuItem, _pasteMenuItem }
};
_optionsChanged = new DelayedAction<TerminalOptions>(async options =>
{
var serialized = JsonConvert.SerializeObject(options);
@@ -189,24 +202,24 @@ namespace FluentTerminal.App.Views
return ExecuteScriptAsync(@"serializeTerminal()");
}
public Task FindNextAsync(SearchRequest request)
public Task FindNextAsync(string searchText)
{
if (_terminalClosed)
{
return Task.CompletedTask;
}
return ExecuteScriptAsync($"findNext('{request.Term}', {request.MatchCase.ToString().ToLower()}, {request.WholeWord.ToString().ToLower()}, {request.Regex.ToString().ToLower()})");
return ExecuteScriptAsync($"findNext('{searchText}')");
}
public Task FindPreviousAsync(SearchRequest request)
public Task FindPreviousAsync(string searchText)
{
if (_terminalClosed)
{
return Task.CompletedTask;
}
return ExecuteScriptAsync($"findPrevious('{request.Term}', {request.MatchCase.ToString().ToLower()}, {request.WholeWord.ToString().ToLower()}, {request.Regex.ToString().ToLower()})");
return ExecuteScriptAsync($"findPrevious('{searchText}')");
}
public Task FocusTerminalAsync()
@@ -224,18 +237,7 @@ namespace FluentTerminal.App.Views
return Task.CompletedTask;
}
public async Task ReconnectAsync()
{
// Fill full screen with new output to not allow erasing of available output on start of new shell
Terminal_OutputReceived(this, System.Text.Encoding.UTF8.GetBytes(new String('\n', _requestedSize.Rows + 1)));
if (true == await StartShellProcessAsync(_requestedSize).ConfigureAwait(false))
{
ViewModel.Terminal.Reconnect();
}
}
public async Task InitializeAsync(TerminalViewModel viewModel)
{
ViewModel = viewModel;
@@ -243,14 +245,6 @@ namespace FluentTerminal.App.Views
ViewModel.Terminal.RegisterSelectedTextCallback(() => ExecuteScriptAsync("term.getSelection()"));
ViewModel.Terminal.Closed += Terminal_Closed;
_webView.SetBinding(ContextFlyoutProperty, new Binding
{
Converter = (IValueConverter)Application.Current.Resources["MenuViewModelToFlyoutMenuConverter"],
Mode = BindingMode.OneWay,
Source = ViewModel,
Path = new PropertyPath(nameof(TerminalViewModel.ContextMenu))
});
var options = ViewModel.SettingsService.GetTerminalOptions();
var keyBindings = ViewModel.SettingsService.GetCommandKeyBindings();
var profiles = ViewModel.SettingsService.GetShellProfiles();
@@ -266,6 +260,12 @@ namespace FluentTerminal.App.Views
// Waiting for IxtermEventListener.OnInitialized() call to happen
await _tcsConnected.Task;
var sessionType =
ViewModel.ShellProfile.UseConPty &&
ViewModel.ApplicationView.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7)
? SessionType.ConPty
: SessionType.WinPty;
lock (_resizeLock)
{
// Check to see if some resizing has happened meanwhile
@@ -279,8 +279,14 @@ namespace FluentTerminal.App.Views
}
}
if (false == await StartShellProcessAsync(size).ConfigureAwait(false))
var response = await ViewModel.Terminal.StartShellProcessAsync(ViewModel.ShellProfile, size, sessionType, ViewModel.XtermBufferState).ConfigureAwait(false);
if (!response.Success)
{
await Dispatcher.ExecuteAsync(async () =>
await ViewModel.DialogService.ShowMessageDialogAsync("Error", response.Error, DialogButton.OK))
.ConfigureAwait(false);
ViewModel.Terminal.ReportLauchFailed();
return;
}
@@ -335,40 +341,31 @@ namespace FluentTerminal.App.Views
}
}
void IxtermEventListener.OnMouseClick(MouseButton mouseButton, int x, int y, bool hasSelection, string hoveredUri)
void IxtermEventListener.OnMouseClick(MouseButton mouseButton, int x, int y, bool hasSelection)
{
if (_terminalClosed)
{
return;
}
var action = MouseAction.None;
switch (mouseButton)
if (mouseButton == MouseButton.Middle)
{
case MouseButton.Middle:
action = ViewModel.ApplicationSettings.MouseMiddleClickAction;
break;
case MouseButton.Right:
action = ViewModel.ApplicationSettings.MouseRightClickAction;
break;
}
if (action == MouseAction.ContextMenu)
{
Dispatcher.ExecuteAsync(() => ShowContextMenu(x, y, hasSelection, hoveredUri), enforceNewSchedule: true);
}
else if (action == MouseAction.Paste)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
else if (action == MouseAction.CopySelectionOrPaste)
{
if (hasSelection)
if (ViewModel.ApplicationSettings.MouseMiddleClickAction == MouseAction.ContextMenu)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Copy));
Dispatcher.ExecuteAsync(() => ShowContextMenu(x, y, hasSelection), enforceNewSchedule: true);
}
else
else if (ViewModel.ApplicationSettings.MouseMiddleClickAction == MouseAction.Paste)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
}
else if (mouseButton == MouseButton.Right)
{
if (ViewModel.ApplicationSettings.MouseRightClickAction == MouseAction.ContextMenu)
{
Dispatcher.ExecuteAsync(() => ShowContextMenu(x, y, hasSelection), enforceNewSchedule: true);
}
else if (ViewModel.ApplicationSettings.MouseRightClickAction == MouseAction.Paste)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
@@ -446,6 +443,11 @@ namespace FluentTerminal.App.Views
_ = Launcher.LaunchUriAsync(args.Uri);
}
private void Copy_Click(object sender, RoutedEventArgs e)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Copy));
}
private Task<TerminalSize> CreateXtermViewAsync(TerminalOptions options, TerminalColors theme, IEnumerable<KeyBinding> keyBindings)
{
var serializedOptions = JsonConvert.SerializeObject(options);
@@ -468,7 +470,6 @@ namespace FluentTerminal.App.Views
var scriptTask = await Dispatcher.ExecuteAsync(() => _webView.InvokeScriptAsync("eval", new[] {script}))
.ConfigureAwait(false);
return await scriptTask;
}
catch (Exception e)
@@ -484,11 +485,15 @@ namespace FluentTerminal.App.Views
return commandKeyBindings.Values.SelectMany(k => k).Concat(profiles.SelectMany(x => x.KeyBindings).Concat(sshprofiles.SelectMany(x => x.KeyBindings)));
}
private void ShowContextMenu(int x, int y, bool terminalHasSelection, string hoveredUri)
private void Paste_Click(object sender, RoutedEventArgs e)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
private void ShowContextMenu(int x, int y, bool terminalHasSelection)
{
ViewModel.HoveredUri = hoveredUri;
ViewModel.HasSelection = terminalHasSelection;
var flyout = (MenuFlyout)_webView.ContextFlyout;
_copyMenuItem.IsEnabled = terminalHasSelection;
flyout.ShowAt(_webView, new Point(x, y));
}
@@ -509,6 +514,9 @@ namespace FluentTerminal.App.Views
_webView?.Navigate(new Uri("about:blank"));
Root.Children.Remove(_webView);
_webView = null;
_copyMenuItem.Click -= Copy_Click;
_pasteMenuItem.Click -= Paste_Click;
if (Window.Current.Content is Frame frame && frame.Content is Page mainPage)
{
@@ -560,26 +568,7 @@ namespace FluentTerminal.App.Views
_outputBlockedBuffer?.Dispose();
}
public void Paste(string text) => OnPaste?.Invoke(this, text);
private async Task<bool> StartShellProcessAsync(TerminalSize size)
{
var sessionType = ViewModel.ShellProfile.UseConPty &&
ViewModel.ApplicationView.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7)
? SessionType.ConPty
: SessionType.WinPty;
var response = await ViewModel.Terminal.StartShellProcessAsync(ViewModel.ShellProfile, size, sessionType, ViewModel.XtermBufferState).ConfigureAwait(false);
if (!response.Success)
{
await Dispatcher.ExecuteAsync(async () =>
await ViewModel.DialogService.ShowMessageDialogAsync("Error", response.Error, DialogButton.OK))
.ConfigureAwait(false);
ViewModel.Terminal.ReportLauchFailed();
return false;
}
return true;
}
public Task PasteAsync(string text) => ExecuteScriptAsync(
$"window.term.paste('{text.Replace(@"\", @"\\").Replace("'", @"\'").Replace("\n", @"\n").Replace("\r", @"\r")}')");
}
}
+503 -470
View File
File diff suppressed because it is too large. Load diff
+8 -8
View File
@@ -10,17 +10,17 @@
"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": "^4.4.0",
"xterm-addon-fit": "^0.3.0",
"xterm-addon-search": "^0.6.0",
"xterm-addon-serialize": "^0.2.0",
"xterm-addon-search": "^0.4.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"
}
}
+52 -34
View File
@@ -5,19 +5,20 @@ import { WebLinksAddon } from 'xterm-addon-web-links';
import { SerializeAddon } from "xterm-addon-serialize";
import { Unicode11Addon } from "xterm-addon-unicode11";
interface ExtendedWindow extends Window {
keyBindings: any[];
term: Terminal;
terminalBridge: any;
hoveredUri: string;
createTerminal(options: any, theme: any, keyBindings: any): void;
connectToWebSocket(url: string): void;
changeTheme(theme: any): void;
changeOptions(options: any): void;
changeKeyBindings(keyBindings: any): void;
findNext(content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean): void;
findPrevious(content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean): void;
findNext(content: string): void;
findPrevious(content: string): void;
serializeTerminal() : void;
}
@@ -29,7 +30,6 @@ let searchAddon: SearchAddon;
let serializeAddon: SerializeAddon;
let webLinksAddon: WebLinksAddon;
let unicode11Addon: Unicode11Addon;
let altGrPressed = false;
const terminalContainer = document.getElementById('terminal-container');
@@ -56,7 +56,6 @@ window.createTerminal = (options, theme, keyBindings) => {
theme = JSON.parse(theme);
window.keyBindings = JSON.parse(keyBindings);
window.hoveredUri = "";
options = JSON.parse(options);
@@ -80,14 +79,50 @@ window.createTerminal = (options, theme, keyBindings) => {
term = new Terminal(terminalOptions);
const linkMatcherOptions: ILinkMatcherOptions = {
leaveCallback: () => {
window.hoveredUri = "";
},
tooltipCallback: (event: MouseEvent, uri: string) => {
window.hoveredUri = uri;
leaveCallback: () => window.onmouseup = (e) => defaultOnMouseUpHandler(e),
willLinkActivate: (event: MouseEvent, uri: string) => {
window.onmouseup = (e) => linkHoverOnMouseUpHandler(event, uri);
return true;
}
};
function defaultOnMouseUpHandler(e: MouseEvent): void {
if (e.button == 1) {
window.terminalBridge.notifyMiddleClick(e.clientX, e.clientY, term.hasSelection());
} else if (e.button == 2) {
window.terminalBridge.notifyRightClick(e.clientX, e.clientY, term.hasSelection());
}
}
function linkHoverOnMouseUpHandler(e: MouseEvent, u: string): void {
if (e.button == 1) {
window.terminalBridge.notifyMiddleClick(e.clientX, e.clientY, term.hasSelection());
} else if (e.button == 2) {
let pos = findInMouseRow(u, e.clientY);
if(pos !== undefined) {
term.select(pos.col, pos.row, u.length);
window.terminalBridge.notifyRightClick(e.clientX, e.clientY, term.hasSelection());
}
}
}
function findInMouseRow(str: string, mouseY: number): {col: number, row: number} | undefined {
const lineHeight: number = Math.round(window.innerHeight / window.term.rows) - 1;
const mouseRow: number = mouseY / lineHeight;
let col: number, row: number = (mouseRow === Math.ceil(mouseRow) ? mouseRow : Math.floor(mouseRow)) - 1;
let line = window.term.buffer.getLine(row);
if(line === undefined) return;
col = line.translateToString().indexOf(str);
if (col === -1) return;
return {
col: col,
row: row
};
}
searchAddon = new SearchAddon();
term.loadAddon(searchAddon);
fitAddon = new FitAddon();
@@ -106,10 +141,6 @@ window.createTerminal = (options, theme, keyBindings) => {
term.writeUtf8(data);
});
window.terminalBridge.onpaste = (text => {
term.paste(text);
});
term.onData(data => {
window.terminalBridge.inputReceived(data);
});
@@ -142,17 +173,11 @@ window.createTerminal = (options, theme, keyBindings) => {
resizeTimeout = setTimeout(() => fitAddon.fit(), 500);
}
window.onmouseup = (e) => {
if (e.button == 1) {
window.terminalBridge.notifyMiddleClick(e.clientX, e.clientY, term.hasSelection(), window.hoveredUri);
} else if (e.button == 2) {
window.terminalBridge.notifyRightClick(e.clientX, e.clientY, term.hasSelection(), window.hoveredUri);
}
}
window.onmouseup = (e) => defaultOnMouseUpHandler(e);
window.onkeydown = (e) => {
// Disable WebView zooming to prevent crash on too small font size
if ((e.ctrlKey && !e.altKey && (e.keyCode === 189 || e.keyCode === 187)) ||
if ((e.ctrlKey && (e.keyCode === 189 || e.keyCode === 187)) ||
(e.ctrlKey && (e.key === "Add" || e.key === "Subtract"))) {
e.preventDefault();
}
@@ -166,16 +191,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
@@ -254,12 +272,12 @@ window.changeKeyBindings = (keyBindings) => {
window["keyBindings"] = keyBindings;
}
window.findNext = (content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean) => {
searchAddon.findNext(content, { caseSensitive: caseSensitive, wholeWord: wholeWord, regex: regex });
window.findNext = (content: string) => {
searchAddon.findNext(content);
}
window.findPrevious = (content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean) => {
searchAddon.findPrevious(content, { caseSensitive: caseSensitive, wholeWord: wholeWord, regex: regex });
window.findPrevious = (content: string) => {
searchAddon.findPrevious(content);
}
document.oncontextmenu = function () {
+1 -3
View File
@@ -25,7 +25,6 @@ namespace FluentTerminal.Models
public bool PrintableOutputOnly { get; set; }
public string LogDirectoryPath { get; set; }
public bool UseConPty { get; set; }
public bool ShowTextCopied { get; set; }
public ApplicationSettings Clone() => new ApplicationSettings
{
@@ -49,8 +48,7 @@ namespace FluentTerminal.Models
EnableLogging = EnableLogging,
PrintableOutputOnly = PrintableOutputOnly,
LogDirectoryPath = LogDirectoryPath,
UseConPty = UseConPty,
ShowTextCopied = ShowTextCopied
UseConPty = UseConPty
};
}
}
+3 -2
View File
@@ -7,6 +7,8 @@
PreviousTab,
NewTab,
NewWindow,
ConfigurableNewTab,
ConfigurableNewWindow,
NewSshTab,
NewSshWindow,
NewCustomCommandTab,
@@ -30,7 +32,6 @@
SwitchToTerm7,
SwitchToTerm8,
SwitchToTerm9,
DuplicateTab,
ReconnectTab
DuplicateTab
}
}
@@ -0,0 +1,12 @@
// ReSharper disable InconsistentNaming
namespace FluentTerminal.Models.Enums
{
public enum LineEndingStyle
{
DoNotModify = 0,
ToCR,
ToCRLF,
ToLF
}
}
+1 -2
View File
@@ -4,7 +4,6 @@
{
None,
ContextMenu,
Paste,
CopySelectionOrPaste
Paste
}
}
+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,9 +1,9 @@
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; }
public string ShellExecutableName { 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; }
}
Loaded 100 of 233 files, more files were not shown because too many files have changed in this diff. Show more