Compare commits

...
Author SHA1 Message Date
Max Risuhin fe60f37213 Fixes performance issues of multiple ConPty sessions with fast output. 2020-04-12 03:14:16 +03:00
Felix Seidl 0dc1a1cd5d don't treat AltGr like Alt+Ctrl
fixes #699
2020-04-10 15:03:19 +02:00
Felix Seidl e1fc980779 fix missing translations for tab color names 2020-04-10 14:00:40 +02:00
Felix Seidl ccd8c1eaa4 improve settings import/export 2020-04-10 13:52:23 +02:00
Restia666Ashdoll ad1a933207 Update README.md (#707) 2020-04-08 08:04:46 +02:00
Felix Seidl 8d7c57d6fe allow more keybindings (again)
fixes #697
2020-04-05 18:33:43 +02:00
Felix Seidl 8d039f59ef prevent conpty from changing the title to its executable location
fixes #687
2020-04-05 17:43:53 +02:00
Felix Seidl cb8d3cabc7 fix missing tab color names 2020-04-05 17:23:47 +02:00
Felix Seidl 579def4f63 Fix tab color for unselected tabs
fixes #688
2020-04-05 17:19:08 +02:00
Max Hora 5d54d448b0 Rollback to use double quotes around identity file for ssh cli cmd. (#698) 2020-04-05 13:28:46 +02:00
Max HoraandFelix Seidl dec492e39a Reconnect failed tab. (#682)
* Reconnect failed tab.

* Reconnect session overlay; Reconnect tab command is removed from context menus.

* some ui changes + localization

Co-authored-by: Felix Seidl <f.seidl@me.com>
2020-03-31 20:01:09 +02:00
Felix Seidl 20540937fe Update main.yml 2020-03-27 12:26:04 +01:00
Felix Seidl 3dd29d7bb7 Update readme 2020-03-27 12:05:35 +01:00
Felix Seidl 90ac2b0c7c Increase version 2020-03-27 11:56:47 +01:00
Felix Seidl e459255b23 Update translations 2020-03-25 19:27:45 +01:00
Felix Seidl 9165716899 Update main.yml 2020-03-25 19:14:16 +01:00
Felix Seidl 49cf63c6b8 use xterm fork to fix selection color issues 2020-03-25 18:42:47 +01:00
Felix Seidl d0b5f99e28 fix issue displaying the selected terminal theme in settings 2020-03-25 17:49:17 +01:00
Felix Seidl e1b28d2f83 fix crash on quick launch to new window (#672) 2020-03-25 17:47:32 +01:00
Felix Seidl 24a2a23b23 compress large tile png to fix CI 2020-03-24 23:15:38 +01:00
Felix Seidl 25536e9bcb New icon 2020-03-24 23:01:33 +01:00
Felix Seidl 2f984fc411 addded chinese simplified, indonesian and arabic localizations 2020-03-24 21:48:59 +01:00
Aleksandar Pesic 596eee712b "Use buffer" profile settings implemented. (#680) 2020-03-23 18:54:06 +01:00
Felix Seidl 7b18037862 Update to latest UWP version 2020-03-21 10:05:16 +01:00
Felix Seidl 41cffb1a1c fix security issues 2020-03-20 16:32:35 +01:00
Felix Seidl 6ddfba93d9 fix app menu placement 2020-03-15 11:18:31 +01:00
Felix Seidl 6a1e12c83a Fix crash when opening menu in older Windows 10 versions
fixes #528
2020-03-15 10:54:48 +01:00
Felix Seidl e24261ab02 added new mouse action: copy selection or paste if none
fixes #298
2020-03-07 14:25:08 +01:00
Felix Seidl 60d294b20f improved icons in app menu 2020-03-07 11:59:23 +01:00
Felix Seidl 1ee051a106 remove obsolete line ending translation setting 2020-03-07 11:41:19 +01:00
Felix Seidl ea1a167dd3 improve paste implementation 2020-03-07 11:09:21 +01:00
Felix Seidl 1a91a6b22e small layout fix 2020-03-07 10:36:30 +01:00
Felix Seidl 941c525409 fix ~ input on german keyboard layout 2020-03-05 15:59:26 +01:00
Felix Seidl d7f741c2ad Move show text copied notification option to general settings 2020-03-04 22:21:24 +01:00
Felix Seidl ab73b28582 Use profile name as default tab title
fixes #639
2020-03-03 22:40:36 +01:00
Felix Seidl 95ccf3a984 Removed profile selection dialog 2020-03-03 22:10:33 +01:00
Felix Seidl 93eccc3470 Localize search options, focus search on open 2020-03-03 21:33:05 +01:00
Felix Seidl f86f20321d Rework tab context menu 2020-03-03 18:39:38 +01:00
Felix Seidl 475e2da999 Reworked context menu 2020-03-01 13:04:26 +01:00
Felix Seidl 985cac99e6 Use MDL2 icons for settings 2020-02-29 22:18:55 +01:00
Felix Seidl 832b9bdf97 Align resize overlay style to new search overlay 2020-02-29 21:45:40 +01:00
Max Risuhin 264502e1e6 Disable WebView zooming to prevent crash on too small font size. (#673) 2020-02-29 20:40:34 +01:00
Felix Seidl 6015dbda2f fix crash on ctrl+f when search is open 2020-02-29 20:40:01 +01:00
Felix Seidl d879ee02fc better background color for search overlay 2020-02-29 20:39:43 +01:00
Felix Seidl 27c55c6f09 Reworked search view, added search options 2020-02-29 19:09:54 +01:00
230 changed files with 8963 additions and 7326 deletions

No files matched your search

+3 -3
View File
@@ -13,11 +13,11 @@ jobs:
- name: Build client
working-directory: ./FluentTerminal.Client
run: |
npm install
npm run build
yarn
yarn build
- name: Setup MSBuild.exe
uses: warrenbuckley/Setup-MSBuild@v1
- name: MSBuild
run: msbuild FluentTerminal.sln -t:build -p:Configuration=Debug -p:Platform=x64 -m -restore
run: msbuild FluentTerminal.sln -t:build -p:Configuration=Debug -p:Platform=x64 -p:AppxPackage=false -m -restore
@@ -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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, () => createKeyBindingDialog.Object, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(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,30 +75,19 @@ 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(Mock.Of<IShellProfileSelectionDialog>, () => messageDialog.Object, Mock.Of<ICreateKeyBindingDialog>, Mock.Of<IInputDialog>, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(() => 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<IShellProfileSelectionDialog>, Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, () => inputDialog.Object, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
var dialogService = new DialogService(Mock.Of<IMessageDialog>, Mock.Of<ICreateKeyBindingDialog>, () => inputDialog.Object, Mock.Of<ISshConnectionInfoDialog>, Mock.Of<ICustomCommandDialog>, Mock.Of<IAboutDialog>);
dialogService.ShowInputDialogAsync(title);
@@ -1,12 +0,0 @@
using FluentTerminal.Models;
using System.Threading.Tasks;
namespace FluentTerminal.App.Services.Dialogs
{
public interface IShellProfileSelectionDialog
{
ShellProfile SelectedProfile { get; }
Task<ShellProfile> SelectProfileAsync();
}
}
@@ -0,0 +1,23 @@
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)
{
}
}
}
@@ -1,12 +0,0 @@
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,9 +14,8 @@ namespace FluentTerminal.App.Services
{
Task<DialogButton> ShowMessageDialogAsync(string title, string content, params DialogButton[] buttons);
Task<ShellProfile> ShowProfileSelectionDialogAsync();
Task<KeyBinding> ShowCreateKeyBindingDialog();
Task<string> ShowInputDialogAsync(string title);
Task<SshProfile> ShowSshConnectionInfoDialogAsync(SshProfile input = null);
@@ -35,6 +35,8 @@ namespace FluentTerminal.App.Services
Task SaveTextFileAsync(string path, string content);
Task<string> ReadTextFileAsync(string path);
Task<string> GetSshConfigDirAsync();
Task<string[]> GetFilesFromSshConfigDirAsync();
@@ -1,5 +1,4 @@
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
using System;
using System.Collections.Generic;
@@ -42,7 +41,8 @@ namespace FluentTerminal.App.Services.Implementation
EnableLogging = false,
PrintableOutputOnly = true,
LogDirectoryPath = logDirectoryPath,
UseConPty = true
UseConPty = true,
ShowTextCopied = false
};
}
@@ -114,6 +114,18 @@ 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>
{
@@ -126,18 +138,6 @@ 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,
Shift = true,
Key = (int)ExtendedVirtualKey.Q
Alt = true,
Key = (int)ExtendedVirtualKey.T
}
};
@@ -182,7 +182,7 @@ namespace FluentTerminal.App.Services.Implementation
Command = nameof(Command.NewCustomCommandWindow),
Ctrl = true,
Alt = true,
Key = (int)ExtendedVirtualKey.Q
Key = (int)ExtendedVirtualKey.N
}
};
@@ -222,18 +222,6 @@ 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>
{
@@ -242,8 +230,7 @@ namespace FluentTerminal.App.Services.Implementation
Command = nameof(Command.ShowSettings),
Ctrl = true,
Shift = true,
// 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
Key = (int)ExtendedVirtualKey.Comma
}
};
@@ -353,7 +340,7 @@ namespace FluentTerminal.App.Services.Implementation
new TabTheme
{
Id = 0,
Name = I18N.Translate("TabTheme.None"),
Name = "TabTheme.None",
BackgroundOpacity = double.NaN,
BackgroundPointerOverOpacity = double.NaN,
BackgroundPressedOpacity = double.NaN,
@@ -364,37 +351,37 @@ namespace FluentTerminal.App.Services.Implementation
new TabTheme
{
Id = 1,
Name = I18N.Translate("TabTheme.Red"),
Name = "TabTheme.Red",
Color = "#E81123"
},
new TabTheme
{
Id = 2,
Name = I18N.Translate("TabTheme.Green"),
Name = "TabTheme.Green",
Color = "#10893E"
},
new TabTheme
{
Id = 3,
Name = I18N.Translate("TabTheme.Blue"),
Name = "TabTheme.Blue",
Color = "#0078D7"
},
new TabTheme
{
Id = 4,
Name = I18N.Translate("TabTheme.Purple"),
Name = "TabTheme.Purple",
Color = "#881798"
},
new TabTheme
{
Id = 5,
Name = I18N.Translate("TabTheme.Orange"),
Name = "TabTheme.Orange",
Color = "#FF8C00"
},
new TabTheme
{
Id = 6,
Name = I18N.Translate("TabTheme.Teal"),
Name = "TabTheme.Teal",
Color = "#00B7C3"
}
};
@@ -437,8 +424,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"
@@ -465,8 +452,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"
@@ -493,8 +480,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,7 +7,6 @@ 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;
@@ -15,13 +14,11 @@ namespace FluentTerminal.App.Services.Implementation
private readonly Func<ICustomCommandDialog> _customCommandDialogFactory;
private readonly Func<IAboutDialog> _aboutDialogFactory;
public DialogService(Func<IShellProfileSelectionDialog> shellProfileSelectionDialogFactory,
Func<IMessageDialog> messageDialogFactory, Func<ICreateKeyBindingDialog> createKeyBindingDialogFactory,
public DialogService(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;
@@ -74,13 +71,6 @@ 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().Where(x => !x.PreInstalled))
foreach (var profile in GetShellProfiles())
{
config.Profiles.Add(profile);
}
@@ -117,22 +117,18 @@ namespace FluentTerminal.App.Services.Implementation
SaveTheme(theme, existingTheme != null);
}
// Can't create pre-installed profiles
foreach (var profile in config.Profiles.Where(x => !x.PreInstalled))
foreach (var profile in config.Profiles)
{
var existingProfile = GetShellProfile(profile.Id);
var isNew = existingProfile.EqualTo(default);
var isNew = existingProfile == default;
// You can only edit certain parts of preinstalled profiles
if (!isNew && existingProfile.PreInstalled)
{
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);
// those cannot be edited
profile.Name = existingProfile.Name;
profile.Location = existingProfile.Location;
SaveShellProfile(profile, false);
continue;
}
SaveShellProfile(profile, isNew);
@@ -141,7 +137,7 @@ namespace FluentTerminal.App.Services.Implementation
foreach (var profile in config.SshProfiles)
{
var existingProfile = GetSshProfile(profile.Id);
var isNew = existingProfile.EqualTo(default(SshProfile));
var isNew = existingProfile == default;
SaveSshProfile(profile, isNew);
}
@@ -84,6 +84,18 @@ 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))
+11 -1
View File
@@ -24,6 +24,12 @@ 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)
@@ -71,6 +77,8 @@ namespace FluentTerminal.App.Services
public byte Id { get; }
public ShellProfile Profile { get; private set; }
/// <summary>
/// To be called by either view or viewmodel
/// </summary>
@@ -137,6 +145,8 @@ 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));
@@ -151,7 +161,7 @@ namespace FluentTerminal.App.Services
if (response.Success)
{
_fallbackTitle = response.ShellExecutableName;
_fallbackTitle = response.Name;
SetTitle(_fallbackTitle);
}
return response;
@@ -10,11 +10,12 @@ namespace FluentTerminal.App.ViewModels
Task ChangeKeyBindingsAsync();
Task ChangeOptionsAsync(TerminalOptions options);
Task InitializeAsync(TerminalViewModel viewModel);
Task ReconnectAsync();
void DisposalPrepare();
Task FindNextAsync(string searchText);
Task FindPreviousAsync(string searchText);
Task FindNextAsync(SearchRequest request);
Task FindPreviousAsync(SearchRequest request);
Task FocusTerminalAsync();
Task<string> SerializeXtermStateAsync();
Task PasteAsync(string text);
void Paste(string text);
}
}
File diff suppressed because it is too large. Load diff
@@ -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, object icon = null) : base(text, description, icon)
string description = null, Mdl2Icon icon = null) : base(text, description, icon)
{
if (subItems == null)
{
@@ -0,0 +1,50 @@
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,12 +1,15 @@
using FluentTerminal.Models;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.Models;
using FluentTerminal.Models.Enums;
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
@@ -80,9 +83,21 @@ namespace FluentTerminal.App.ViewModels.Menu
}
}
#endregion Properties
public bool IsExtendedVirtualKey => !Enum.IsDefined(typeof(VirtualKey), Key);
#region Constructors
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);
}
public MenuItemKeyBindingViewModel(int key = 0, bool ctrl = false, bool alt = false, bool shift = false,
bool windows = false)
@@ -101,9 +116,7 @@ namespace FluentTerminal.App.ViewModels.Menu
{
}
#endregion Constructors
#region Methods
private void SetKeyModifiers()
{
@@ -142,6 +155,5 @@ 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, object icon = null,
public MenuItemViewModel(string text, ICommand command, string description = null, Mdl2Icon icon = null,
MenuItemKeyBindingViewModel keyBinding = null) : base(text, description, icon)
{
_keyBinding = keyBinding;
@@ -23,32 +23,9 @@ namespace FluentTerminal.App.ViewModels.Menu
set => Set(ref _description, value);
}
private object _icon;
private 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
public Mdl2Icon Icon
{
get => _icon;
set => Set(ref _icon, value);
@@ -58,7 +35,7 @@ namespace FluentTerminal.App.ViewModels.Menu
#region Constructor
protected MenuItemViewModelBase(string text, string description, object icon)
protected MenuItemViewModelBase(string text, string description, Mdl2Icon icon)
{
_text = text;
_description = description;
@@ -5,11 +5,11 @@ using GalaSoft.MvvmLight;
namespace FluentTerminal.App.ViewModels.Menu
{
public class AppMenuViewModel : ViewModelBase
public class MenuViewModel : ViewModelBase
{
public ObservableCollection<MenuItemViewModelBase> Items { get; }
public AppMenuViewModel(IEnumerable<MenuItemViewModelBase> items = null)
public MenuViewModel(IEnumerable<MenuItemViewModelBase> items = null)
{
if (items == null)
{
@@ -25,7 +25,7 @@ namespace FluentTerminal.App.ViewModels.Menu
}
}
public bool EquivalentTo(AppMenuViewModel other)
public bool EquivalentTo(MenuViewModel other)
{
if (ReferenceEquals(this, other)) return true;
@@ -0,0 +1,28 @@
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;
}
}
}
@@ -0,0 +1,26 @@
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,7 +7,6 @@ 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;
@@ -19,13 +18,6 @@ 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;
@@ -68,17 +60,6 @@ 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
@@ -130,13 +111,7 @@ namespace FluentTerminal.App.ViewModels.Profiles
if (theme == null)
{
// 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();
return;
}
else if (!TerminalThemes.Contains(theme))
{
@@ -173,6 +148,14 @@ namespace FluentTerminal.App.ViewModels.Profiles
set => Set(ref _useConPty, value);
}
private bool _useBuffer;
public bool UseBuffer
{
get => _useBuffer;
set => Set(ref _useBuffer, value);
}
#endregion Properties
#region Constructor
@@ -233,8 +216,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;
}
@@ -246,8 +229,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;
@@ -264,8 +247,8 @@ namespace FluentTerminal.App.ViewModels.Profiles
/// </summary>
public virtual bool HasChanges()
{
return Model.LineEndingTranslation != _lineEndingTranslation ||
Model.UseConPty != _useConPty ||
return Model.UseConPty != _useConPty ||
Model.UseBuffer != _useBuffer ||
!Model.TerminalThemeId.Equals(_terminalThemeId) ||
Model.TabThemeId != _tabThemeId;
}
@@ -301,7 +284,7 @@ namespace FluentTerminal.App.ViewModels.Profiles
#region Links/shortcuts related
private const string UseConPtyQueryStringName = "conpty";
private const string LineEndingQueryStringName = "lineending";
private const string UseBufferQueryStringName = "buffer";
private const string TerminalThemeIdQueryStringName = "theme";
private const string TabThemeIdQueryStringName = "tab";
@@ -341,8 +324,7 @@ URL={0}
public string GetBaseQueryString()
{
var queryString =
$"{UseConPtyQueryStringName}={_useConPty}&{LineEndingQueryStringName}={_lineEndingTranslation}";
var queryString = $"{UseConPtyQueryStringName}={_useConPty}&{UseBufferQueryStringName}={_useBuffer}";
if (_tabThemeId != TabThemes.First().Id)
{
@@ -373,11 +355,11 @@ URL={0}
}
keyValue = queryStringParams.FirstOrDefault(t =>
LineEndingQueryStringName.Equals(t.Item1, StringComparison.OrdinalIgnoreCase));
UseBufferQueryStringName.Equals(t.Item1, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(keyValue?.Item2) && Enum.TryParse(keyValue.Item2, true, out LineEndingStyle lineEndingTranslation))
if (!string.IsNullOrEmpty(keyValue?.Item2) && bool.TryParse(keyValue.Item2?.ToLower(), out bool useBuffer))
{
LineEndingTranslation = lineEndingTranslation;
UseConPty = useBuffer;
}
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,6 +391,20 @@ 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()
{
@@ -418,6 +432,7 @@ namespace FluentTerminal.App.ViewModels.Settings
PrintableOutputOnly = defaults.PrintableOutputOnly;
LogDirectoryPath = defaults.LogDirectoryPath;
UseConPty = defaults.UseConPty;
ShowTextCopied = defaults.ShowTextCopied;
}
}
@@ -71,6 +71,12 @@ 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;
@@ -103,6 +109,12 @@ 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,20 +178,6 @@ 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
@@ -259,7 +245,6 @@ namespace FluentTerminal.App.ViewModels.Settings
FontWeight = defaults.FontWeight;
BackgroundOpacity = defaults.BackgroundOpacity;
ScrollBackLimit = defaults.ScrollBackLimit.ToString();
ShowTextCopied = defaults.ShowTextCopied;
WordSeparator = defaults.WordSeparator;
}
}
@@ -0,0 +1,31 @@
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,6 +13,11 @@ 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
{
@@ -32,9 +37,12 @@ namespace FluentTerminal.App.ViewModels
public string ShellTitle { get; set; }
public string TabTitle { get; set; }
public TerminalTheme TerminalTheme { get; set; }
public TabTheme TabTheme { get; set; }
public int TabThemeId { 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; }
@@ -48,9 +56,12 @@ namespace FluentTerminal.App.ViewModels
ShellTitle = ShellTitle,
TabTitle = TabTitle,
TerminalTheme = TerminalTheme,
TabTheme = TabTheme,
TabThemeId = TabTheme.Theme.Id,
ShowSearchPanel = ShowSearchPanel,
SearchText = SearchText,
SearchMatchCase = SearchMatchCase,
SearchWholeWord = SearchWholeWord,
SearchWithRegex = SearchWithRegex,
XtermBufferState = await SerializeXtermStateAsync().ConfigureAwait(false),
TerminalId = Terminal.Id,
ShellProfile = ShellProfile
@@ -68,12 +79,17 @@ namespace FluentTerminal.App.ViewModels
ShellTitle = state.ShellTitle;
TabTitle = state.TabTitle;
TerminalTheme = state.TerminalTheme;
TabTheme = state.TabTheme;
TabTheme = TabThemes.FirstOrDefault(t => t.Theme.Id == state.TabThemeId);
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;
}
}
@@ -86,13 +102,21 @@ namespace FluentTerminal.App.ViewModels
private bool _hasExitedWithError;
private string _searchText;
private bool _showSearchPanel;
private TabTheme _tabTheme;
private bool _searchMatchCase;
private bool _searchWholeWord;
private bool _searchWithRegex;
private TabThemeViewModel _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,
@@ -101,6 +125,7 @@ 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;
@@ -117,9 +142,7 @@ namespace FluentTerminal.App.ViewModels
ShellProfile = shellProfile;
TerminalTheme = shellProfile.TerminalThemeId == Guid.Empty ? SettingsService.GetCurrentTheme() : SettingsService.GetTheme(shellProfile.TerminalThemeId);
TabThemes = new ObservableCollection<TabTheme>(SettingsService.GetTabThemes());
TabTheme = TabThemes.FirstOrDefault(t => t.Id == ShellProfile.TabThemeId);
TabThemes = new ObservableCollection<TabThemeViewModel>(SettingsService.GetTabThemes().Select(theme => new TabThemeViewModel(theme, this)));
CloseCommand = new AsyncCommand(TryCloseAsync, CanExecuteCommand);
CloseLeftTabsCommand = new RelayCommand(CloseLeftTabs, CanExecuteCommand);
CloseRightTabsCommand = new RelayCommand(CloseRightTabs, CanExecuteCommand);
@@ -127,14 +150,25 @@ 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;
@@ -143,6 +177,21 @@ 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;
@@ -159,8 +208,8 @@ namespace FluentTerminal.App.ViewModels
public event EventHandler Activated;
public event EventHandler Closed;
public event EventHandler<string> FindNextRequested;
public event EventHandler<string> FindPreviousRequested;
public event EventHandler<SearchRequest> FindNextRequested;
public event EventHandler<SearchRequest> FindPreviousRequested;
public event EventHandler SearchStarted;
public event EventHandler<TerminalTheme> ThemeChanged;
public event EventHandler CloseLeftTabsRequested;
@@ -172,13 +221,13 @@ namespace FluentTerminal.App.ViewModels
public IApplicationView ApplicationView { get; }
public TabTheme BackgroundTabTheme
public TabThemeViewModel 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 :
SettingsService.GetTabThemes().FirstOrDefault(t => t.Color == null);
TabTheme :
_transparentTabThemeViewModel;
}
public IClipboardService ClipboardService { get; }
@@ -205,6 +254,16 @@ 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
@@ -216,8 +275,13 @@ 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));
@@ -225,6 +289,24 @@ 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;
@@ -243,7 +325,7 @@ namespace FluentTerminal.App.ViewModels
}
public bool IsUnderlined => (IsSelected && ApplicationSettings.UnderlineSelectedTab) ||
(!IsSelected && ApplicationSettings.InactiveTabColorMode == InactiveTabColorMode.Underlined && TabTheme.Color != null);
(!IsSelected && ApplicationSettings.InactiveTabColorMode == InactiveTabColorMode.Underlined && TabTheme.Theme.Color != null);
public bool HasNewOutput
{
@@ -260,6 +342,7 @@ namespace FluentTerminal.App.ViewModels
{
HasNewOutput = false;
}
ReconnectTabCommand.RaiseCanExecuteChanged();
}
}
@@ -269,7 +352,23 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _searchText, value);
}
public RelayCommand<string> SelectTabThemeCommand { get; }
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 ISettingsService SettingsService { get; }
@@ -281,7 +380,7 @@ namespace FluentTerminal.App.ViewModels
set => Set(ref _showSearchPanel, value);
}
public TabTheme TabTheme
public TabThemeViewModel TabTheme
{
get => _tabTheme;
set
@@ -292,7 +391,7 @@ namespace FluentTerminal.App.ViewModels
}
}
public ObservableCollection<TabTheme> TabThemes { get; }
public ObservableCollection<TabThemeViewModel> TabThemes { get; }
public Terminal Terminal { get; private set; }
@@ -363,7 +462,7 @@ namespace FluentTerminal.App.ViewModels
{
ClipboardService.SetText(text);
if (_terminalOptions.ShowTextCopied)
if (ApplicationSettings.ShowTextCopied)
{
Overlay.Show(I18N.Translate("TextCopied"));
}
@@ -430,7 +529,7 @@ namespace FluentTerminal.App.ViewModels
private void FindNext()
{
FindNextRequested?.Invoke(this, SearchText);
FindNextRequested?.Invoke(this, new SearchRequest { MatchCase = SearchMatchCase, Regex = SearchWithRegex, Term = SearchText, WholeWord = SearchWholeWord });
}
public ITerminalView TerminalView { get; set; }
@@ -442,7 +541,7 @@ namespace FluentTerminal.App.ViewModels
private void FindPrevious()
{
FindPreviousRequested?.Invoke(this, SearchText);
FindPreviousRequested?.Invoke(this, new SearchRequest { MatchCase = SearchMatchCase, Regex = SearchWithRegex, Term = SearchText, WholeWord = SearchWholeWord });
}
private void DuplicateTab()
@@ -450,6 +549,12 @@ 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;
@@ -482,9 +587,23 @@ namespace FluentTerminal.App.ViewModels
ApplicationView.ExecuteOnUiThreadAsync(() => RaisePropertyChanged(nameof(BackgroundOpacity)), CoreDispatcherPriority.Low);
}
private void SelectTabTheme(string id)
private void OnKeyBindingsChanged(KeyBindingsChangedMessage message)
{
TabTheme = TabThemes.FirstOrDefault(t => t.Id == int.Parse(id));
ApplicationView.ExecuteOnUiThreadAsync(() =>
{
var contextMenu = BuidContextMenu();
if (!contextMenu.EquivalentTo(ContextMenu))
{
ContextMenu = contextMenu;
}
var tabContextMenu = BuildTabContextMenu();
if (!tabContextMenu.EquivalentTo(TabContextMenu))
{
TabContextMenu = tabContextMenu;
}
}, CoreDispatcherPriority.Low, true);
}
private void Terminal_Exited(object sender, int exitCode)
@@ -514,18 +633,12 @@ namespace FluentTerminal.App.ViewModels
{
case nameof(Command.Copy):
{
var selection = await Terminal.GetSelectedText().ConfigureAwait(false);
await CopyTextAsync(selection).ConfigureAwait(false);
await Copy().ConfigureAwait(false);
return;
}
case nameof(Command.Paste):
{
string content = await ClipboardService.GetTextAsync().ConfigureAwait(false);
if (content != null)
{
content = ShellProfile.TranslateLineEndings(content);
await TerminalView.PasteAsync(content).ConfigureAwait(false);
}
await Paste().ConfigureAwait(false);
return;
}
case nameof(Command.PasteWithoutNewlines):
@@ -534,7 +647,7 @@ namespace FluentTerminal.App.ViewModels
if (content != null)
{
content = ShellProfile.NewlinePattern.Replace(content, string.Empty);
await TerminalView.PasteAsync(content).ConfigureAwait(false);
TerminalView.Paste(content);
}
return;
}
@@ -579,6 +692,7 @@ namespace FluentTerminal.App.ViewModels
private void Terminal_TitleChanged(object sender, string e)
{
if (e == Terminal.Profile.Location) return;
ApplicationView.ExecuteOnUiThreadAsync(() => ShellTitle = e);
}
@@ -597,5 +711,123 @@ 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
@@ -0,0 +1,26 @@
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,6 +42,7 @@
<converters:TrueToBoldConverter x:Key="TrueToBoldConverter" />
<converters:I18NConverter x:Key="I18NConverter" />
<converters:NullToCollapsedConverter x:Key="NullToCollapsedConverter" />
<converters:MenuViewModelToFlyoutMenuConverter x:Key="MenuViewModelToFlyoutMenuConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
+193 -145
View File
@@ -47,6 +47,7 @@ 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;
@@ -100,7 +101,6 @@ 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,7 +187,189 @@ namespace FluentTerminal.App
protected override async void OnActivated(IActivatedEventArgs args)
{
if (args is ProtocolActivatedEventArgs protocolActivated)
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 (protocolActivated.Uri == new Uri("ftcmd://fluent.terminal?focus"))
{
@@ -263,7 +445,7 @@ namespace FluentTerminal.App
var error = await vm.AcceptChangesAsync(true);
var profile = (SshProfile) vm.Model;
var profile = (SshProfile)vm.Model;
if (!string.IsNullOrEmpty(error))
{
@@ -348,8 +530,7 @@ namespace FluentTerminal.App
return;
}
if (args is CommandLineActivatedEventArgs commandLineActivated)
else if (args is CommandLineActivatedEventArgs commandLineActivated)
{
var arguments = commandLineActivated.Operation.Arguments;
if (string.IsNullOrWhiteSpace(arguments))
@@ -359,148 +540,10 @@ namespace FluentTerminal.App
_commandLineParser
.ParseArguments(SplitArguments(arguments), typeof(NewVerb), typeof(RunVerb), typeof(SettingsVerb))
.WithParsed(async verb => await CliRunAsync(verb, commandLineActivated));
.WithParsed(async verb => await ParseCommandLineArgumentsAsync(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);
@@ -755,6 +798,11 @@ 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,6 +14,9 @@ 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.")]
public bool Import { get; set; }
HelpText = "Import settings from specified file.")]
public string Import { get; set; }
[Option('e', "export",
HelpText = "Export settings.")]
@@ -20,6 +20,10 @@ 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);
+9 -25
View File
@@ -1,4 +1,6 @@
using System;
using FluentTerminal.App.ViewModels.Menu;
using Microsoft.Toolkit.Uwp.Helpers;
using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
@@ -10,37 +12,19 @@ namespace FluentTerminal.App.Converters
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
if (value is Mdl2Icon mdl2Icon)
{
return null;
}
var fontIcon = new FontIcon { FontFamily = new FontFamily("Segoe MDL2 Assets"), Glyph = mdl2Icon.Glyph };
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))
if(!string.IsNullOrWhiteSpace(mdl2Icon.Color))
{
return new SymbolIcon((Symbol) intSymbol);
fontIcon.Foreground = new SolidColorBrush(mdl2Icon.Color.ToColor());
}
throw new ArgumentException($"Integer value isn't defined in {nameof(Symbol)} enum.", nameof(value));
return fontIcon;
}
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));
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
@@ -6,6 +6,8 @@ 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
@@ -34,6 +36,16 @@ 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()}");
@@ -79,12 +91,22 @@ namespace FluentTerminal.App.Converters
if (viewModel.KeyBinding != null)
{
item.KeyboardAccelerators?.Add(new KeyboardAccelerator
if (viewModel.KeyBinding.IsExtendedVirtualKey)
{
Key = (VirtualKey) viewModel.KeyBinding.Key,
Modifiers = (VirtualKeyModifiers) viewModel.KeyBinding.KeyModifiers,
IsEnabled = true
});
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
});
}
}
return item;
@@ -126,6 +148,85 @@ 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
@@ -3,10 +3,11 @@ 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 AppMenuViewModelToFlyoutMenuConverter : IValueConverter
public class MenuViewModelToFlyoutMenuConverter : IValueConverter
{
private static readonly MenuItemViewModelBaseToMenuFlayoutItemBaseConverter ItemConverter =
new MenuItemViewModelBaseToMenuFlayoutItemBaseConverter();
@@ -18,18 +19,18 @@ namespace FluentTerminal.App.Converters
return null;
}
if (!(value is AppMenuViewModel appMenuViewModel))
if (!(value is MenuViewModel menuViewModel))
{
throw new ArgumentException(
$"Invalid {nameof(value)} argument type: {value.GetType()}. {typeof(AppMenuViewModel)} expected.");
$"Invalid {nameof(value)} argument type: {value.GetType()}. {typeof(MenuViewModel)} expected.");
}
var menuFlyout = new MenuFlyout
{
Placement = FlyoutPlacementMode.BottomEdgeAlignedLeft
Placement = FlyoutPlacementMode.Bottom
};
foreach (var menuItemViewModelBase in appMenuViewModel.Items)
foreach (var menuItemViewModelBase in menuViewModel.Items)
{
menuFlyout.Items?.Add((MenuFlyoutItemBase) ItemConverter.Convert(menuItemViewModelBase));
}
@@ -1,4 +1,4 @@
using FluentTerminal.Models;
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models.Enums;
using Microsoft.Toolkit.Uwp.Helpers;
using System;
@@ -12,8 +12,9 @@ namespace FluentTerminal.App.Converters
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is TabTheme theme && Enum.TryParse<TabThemeKey>((string)parameter, true, out TabThemeKey tabThemeKey))
if (value is TabThemeViewModel viewModel && Enum.TryParse<TabThemeKey>((string)parameter, true, out TabThemeKey tabThemeKey))
{
var theme = viewModel.Theme;
switch (tabThemeKey)
{
case TabThemeKey.Background:
@@ -1,4 +1,5 @@
using FluentTerminal.Models;
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
using System;
using Windows.UI.Xaml.Data;
@@ -8,9 +9,9 @@ namespace FluentTerminal.App.Converters
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is TabTheme theme && parameter is string idString && int.TryParse(idString, out var id))
if (value is TerminalViewModel terminal && parameter is string idString && int.TryParse(idString, out var id))
{
return theme.Id == id;
return terminal.TabTheme.Theme.Id == id;
}
return null;
}
@@ -16,8 +16,6 @@ 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;
@@ -53,17 +51,12 @@ namespace FluentTerminal.App.Dialogs
get => _key;
set
{
// We're ignoring invalid keys.
if (_acceleratorKeyValidator.Valid(value))
{
Set(ref _key, value);
}
Set(ref _key, value);
}
}
public CreateKeyBindingDialog(IAcceleratorKeyValidator acceleratorKeyValidator)
public CreateKeyBindingDialog()
{
_acceleratorKeyValidator = acceleratorKeyValidator;
InitializeComponent();
ResetCommand = new RelayCommand(Reset);
PreviewKeyDown += RegisterKeyBindingDialog_PreviewKeyDown;
@@ -14,8 +14,8 @@
IsDesignTimeCreatable=False}"
DefaultButton="Primary"
PrimaryButtonClick="OnPrimaryButtonClick"
SecondaryButtonClick="OnSecondaryButtonClick"
PrimaryButtonText="Button1"
SecondaryButtonClick="OnSecondaryButtonClick"
SecondaryButtonText="Button2"
mc:Ignorable="d">
<ContentDialog.Resources>
@@ -46,9 +46,12 @@
<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>
@@ -79,39 +82,16 @@
<RowDefinition />
</Grid.RowDefinitions>
<!-- Row -->
<TextBlock
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.Row="0"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Tab color:" />
<ComboBox
Grid.Row="1"
Grid.Row="0"
Grid.Column="1"
Margin="0,8,0,0"
HorizontalAlignment="Stretch"
@@ -122,13 +102,13 @@
<!-- Row -->
<TextBlock
x:Uid="Theme"
Grid.Row="2"
Grid.Row="1"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Theme:" />
<ComboBox
Grid.Row="2"
Grid.Row="1"
Grid.Column="1"
Margin="0,8,0,0"
HorizontalAlignment="Stretch"
@@ -138,13 +118,22 @@
<!-- Row -->
<CheckBox
Grid.Row="3"
Grid.Row="2"
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>
@@ -1,17 +0,0 @@
<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>
@@ -1,43 +0,0 @@
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);
}
}
}
+14 -29
View File
@@ -165,40 +165,16 @@
Text="{x:Bind ViewModel.MoshPortTo, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.UseMosh, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}" />
<!-- Row -->
<TextBlock
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.Row="1"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Tab color:" />
<ComboBox
Grid.Row="2"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0,8,0,0"
@@ -210,13 +186,13 @@
<!-- Row -->
<TextBlock
x:Uid="Theme"
Grid.Row="3"
Grid.Row="2"
Grid.Column="0"
Margin="0,8,8,0"
VerticalAlignment="Center"
Text="Theme:" />
<ComboBox
Grid.Row="3"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0,8,0,0"
@@ -227,13 +203,22 @@
<!-- Row -->
<CheckBox
Grid.Row="4"
Grid.Row="3"
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>
+13 -11
View File
@@ -97,6 +97,7 @@
<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">
@@ -107,7 +108,7 @@
<Compile Include="CommandLineArguments\RunVerb.cs" />
<Compile Include="CommandLineArguments\SettingsVerb.cs" />
<Compile Include="CommandLineArguments\Target.cs" />
<Compile Include="Converters\AppMenuViewModelToFlyoutMenuConverter.cs" />
<Compile Include="Converters\MenuViewModelToFlyoutMenuConverter.cs" />
<Compile Include="Converters\BackgroundToApplicationThemeConverter.cs" />
<Compile Include="Converters\BooleanNegationConverter.cs" />
<Compile Include="Converters\ColorResourceKeyFallbackConverter.cs" />
@@ -132,7 +133,6 @@
<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,9 +144,6 @@
<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>
@@ -243,7 +240,7 @@
<PRIResource Include="Strings\fr\Resources.resw" />
<PRIResource Include="Strings\es\Resources.resw" />
<PRIResource Include="Strings\de\Resources.resw" />
<PRIResource Include="Strings\zh-CN\Resources.resw" />
<PRIResource Include="Strings\zh-Hant\Resources.resw" />
<PRIResource Include="Strings\en\Resources.resw" />
</ItemGroup>
<ItemGroup>
@@ -269,10 +266,6 @@
<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>
@@ -363,7 +356,7 @@
<Version>2.7.82</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.9</Version>
<Version>6.2.10</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI">
<Version>6.0.0</Version>
@@ -434,6 +427,15 @@
<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>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
@@ -1,13 +0,0 @@
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,6 +10,7 @@ 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",
@@ -18,6 +19,7 @@ namespace FluentTerminal.App.Services
["fr"] = "Français",
["he"] = "עברית",
["hi"] = "हिन्दुस्तानी",
["id"] = "Bahasa Indonesia",
["it"] = "Italiano",
["ja"] = "日本語",
["ko"] = "한국어",
@@ -27,7 +29,8 @@ namespace FluentTerminal.App.Services
["ro"] = "Română",
["ru"] = "Pусский",
["uk"] = "Українська",
["zh-Hans-CN"] = "Chinese (Traditional)"
["zh-Hans"] = "繁體中文",
["zh-Hant"] = "简体中文"
};
public IEnumerable<string> Languages => _languages.Values;
@@ -44,6 +47,10 @@ namespace FluentTerminal.App.Services
public string GetCurrentLanguage()
{
if (!_languages.ContainsKey(ApplicationLanguages.PrimaryLanguageOverride))
{
ApplicationLanguages.PrimaryLanguageOverride = "en";
}
return _languages[ApplicationLanguages.PrimaryLanguageOverride];
}
}
+24 -16
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1044,4 +1028,28 @@
<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
+24 -16
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1044,4 +1028,28 @@
<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>
+24 -16
View File
@@ -649,14 +649,6 @@ 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>
@@ -699,14 +691,6 @@ 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>
@@ -1077,4 +1061,28 @@ 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>
+24 -18
View File
@@ -659,16 +659,6 @@ 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">
@@ -719,14 +709,6 @@ 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
@@ -1111,4 +1093,28 @@ 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>
+98 -90
View File
@@ -542,7 +542,7 @@ Fuzzy</comment>
<comment>ShellProfileSettings.xaml</comment>
</data>
<data name="ConfirmCloseTab" xml:space="preserve">
<value>Are you sure you want to close &quot;{0}&quot; tab?</value>
<value>¿Estás seguro que quieres cerrar la pestaña &quot;{0}&quot;?</value>
<comment>ViewModel</comment>
</data>
<data name="ConfirmCloseWindow" xml:space="preserve">
@@ -645,14 +645,6 @@ 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>
@@ -695,14 +687,6 @@ 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>
@@ -847,222 +831,246 @@ Fuzzy</comment>
<value>¿Quieres eliminar este perfil?</value>
</data>
<data name="Command.NewSshWindow" xml:space="preserve">
<value>New SSH window</value>
<value>Nueva ventana SSH</value>
</data>
<data name="Setting_SShProfiles.Content" xml:space="preserve">
<value>SSH Profiles</value>
<value>Perfiles SSH</value>
</data>
<data name="SshInfoDialog_TabColor.Text" xml:space="preserve">
<value>Tab color:</value>
<value>Color de pestaña:</value>
</data>
<data name="UseConPty" xml:space="preserve">
<value>Use ConPty</value>
<value>Usar ConPty</value>
</data>
<data name="Username.Header" xml:space="preserve">
<value>Username</value>
<value>Nombre de usuario</value>
</data>
<data name="MoshPortFrom.Header" xml:space="preserve">
<value>From port</value>
<value>Puerto desde</value>
</data>
<data name="MoshPortTo.Header" xml:space="preserve">
<value>to port</value>
<value>a puerto</value>
</data>
<data name="MoshPortRange.Text" xml:space="preserve">
<value>Mosh port range</value>
<value>Rango de puertos Mosh</value>
</data>
<data name="Authenticate" xml:space="preserve">
<value>Authenticate</value>
<value>Autenticar</value>
</data>
<data name="SettingsExported" xml:space="preserve">
<value>Settings were exported to file</value>
<value>Opciones exportadas a archivo</value>
</data>
<data name="SettingsImported" xml:space="preserve">
<value>Settings were imported from file</value>
<value>Opciones importadas desde archivo</value>
</data>
<data name="SshConnectionInfoValidationResult.IdentityFileDoesNotExist" xml:space="preserve">
<value>Identify file does not exist</value>
<value>No existe el archivo de identidad</value>
</data>
<data name="AutoFallbackToWindowsUsername.Header" xml:space="preserve">
<value>Use Windows username when opening SSH URLs that don&apos;t specify one</value>
<value>Usar nombre de Windows al abrir urls SSH que no especifican uno</value>
</data>
<data name="UseMoshByDefault.Header" xml:space="preserve">
<value>Default to Mosh for SSH connections</value>
<value>Mosh para conexiones SSH por defecto</value>
</data>
<data name="RTrimCopiedLines.Header" xml:space="preserve">
<value>Right trim copied lines</value>
<value>Recortar a la derecha las líneas copiadas</value>
</data>
<data name="QuickSshDefault.Header" xml:space="preserve">
<value>Use quick SSH by default</value>
<value>Usar SSH rápido por defecto</value>
</data>
<data name="InvalidCommand" xml:space="preserve">
<value>Invalid command.</value>
<value>Comando inválido.</value>
</data>
<data name="LocationCantBeEmpty" xml:space="preserve">
<value>Location cannot be empty.</value>
<value>La ubicación no puede estar vacía.</value>
</data>
<data name="MuteTerminalBeeps.Header" xml:space="preserve">
<value>Mute terminal beeps</value>
<value>Silenciar sonidos de terminal</value>
</data>
<data name="CommandTextBox.PlaceholderText" xml:space="preserve">
<value>Enter a command (e.g. &apos;ssh username@host&apos;)</value>
<value>Introduce un comando (p.e. &apos;ssh username@host&apos;)</value>
</data>
<data name="CommandLine.Header" xml:space="preserve">
<value>Command</value>
<value>Comando</value>
</data>
<data name="UnsupportedCommand" xml:space="preserve">
<value>Unsupported command:</value>
<value>Comando no soportado:</value>
</data>
<data name="CommandArgumentsMandatory" xml:space="preserve">
<value>Command arguments are missing.</value>
<value>Faltan argumentos del comando.</value>
</data>
<data name="QuickCommandDialog.Title" xml:space="preserve">
<value>Quick Launch</value>
<value>Lanzamiento rápido</value>
</data>
<data name="Command.NewCustomCommandTab" xml:space="preserve">
<value>New quick launch tab</value>
<value>Nueva pestaña de inicio rápido</value>
</data>
<data name="Command.NewCustomCommandWindow" xml:space="preserve">
<value>New quick launch window</value>
<value>Lanzar nueva ventana rápida</value>
</data>
<data name="NewQuickTab.Text" xml:space="preserve">
<value>New quick tab</value>
<value>Nueva pestaña rápida</value>
</data>
<data name="FileNotFound" xml:space="preserve">
<value>File not found:</value>
<value>Archivo no encontrado:</value>
</data>
<data name="InvalidLink" xml:space="preserve">
<value>Invalid link.</value>
<value>Enlace inválido.</value>
</data>
<data name="DropTabHere" xml:space="preserve">
<value>Drop tab here</value>
<value>Suelta la pestaña aquí</value>
</data>
<data name="CloseLeft.Text" xml:space="preserve">
<value>Close tabs to the left</value>
<value>Cerrar pestañas a la izquierda</value>
</data>
<data name="CloseOther.Text" xml:space="preserve">
<value>Close other tabs</value>
<value>Cerrar el resto de pestañas</value>
</data>
<data name="CloseRight.Text" xml:space="preserve">
<value>Close tabs to the right</value>
<value>Cerrar pestañas a la derecha</value>
</data>
<data name="Command.DuplicateTab" xml:space="preserve">
<value>Duplicate tab</value>
<value>Duplicar pestaña</value>
</data>
<data name="Duplicate.Text" xml:space="preserve">
<value>Duplicate</value>
<value>Duplicar</value>
</data>
<data name="DuplicateEnvironmentVariable" xml:space="preserve">
<value>Cannot define two environment variables with the same name.</value>
<value>No puedes asignar dos variables de entorno con el mismo nombre.</value>
</data>
<data name="EmptyEnvironmentVariableName" xml:space="preserve">
<value>Cannot define an environment variable without a name.</value>
<value>No puedes definir una variable de entorno sin nombre.</value>
</data>
<data name="EnvironmentVariables.Text" xml:space="preserve">
<value>Environment variables</value>
<value>Variables de entorno</value>
</data>
<data name="CloseSearchPanel.ToolTipService.ToolTip" xml:space="preserve">
<value>Close search panel</value>
<value>Cerrar panel de búsqueda</value>
</data>
<data name="FindNext.ToolTipService.ToolTip" xml:space="preserve">
<value>Find next</value>
<value>Buscar siguiente</value>
</data>
<data name="FindPrevious.ToolTipService.ToolTip" xml:space="preserve">
<value>Find previous</value>
<value>Buscar anterior</value>
</data>
<data name="SearchTextBox.PlaceholderText" xml:space="preserve">
<value>Enter search term</value>
<value>Ingrese el término de búsqueda</value>
</data>
<data name="Search.Text" xml:space="preserve">
<value>Search</value>
<value>Buscar</value>
</data>
<data name="PrintableOutputOnly.Content" xml:space="preserve">
<value>Printable output only</value>
<value>Solamente salida imprimible</value>
</data>
<data name="EnableLogging.Header" xml:space="preserve">
<value>Log output for debugging</value>
<value>Registar salida para debugeo</value>
</data>
<data name="WordSeparator.Header" xml:space="preserve">
<value>Word separator characters</value>
<value>Caracteres separadores de palabras</value>
</data>
<data name="Recent.Text" xml:space="preserve">
<value>Recent</value>
<value>Reciente</value>
</data>
<data name="NewTab_Description" xml:space="preserve">
<value>Opens default profile in a new tab.</value>
<value>Abre el perfil predeterminado en una nueva pestaña.</value>
</data>
<data name="NewSshTab_Description" xml:space="preserve">
<value>Opens a new SSH or Mosh session in a new tab.</value>
<value>Abre una nueva sesión SSH o Mosh en una nueva pestaña.</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>Opens &quot;Quick Launch&quot; dialog and starts session in a new tab.</value>
<value>Abre el cuadro de diálogo &quot;Inicio rápido&quot; e inicia la sesión en una pestaña nueva.</value>
</data>
<data name="Settings_Description" xml:space="preserve">
<value>Opens settings window.</value>
<value>Abrir ventana de opciones.</value>
</data>
<data name="About_Description" xml:space="preserve">
<value>Basic info about the app.</value>
<value>Información básica sobre la app.</value>
</data>
<data name="Recent_Description" xml:space="preserve">
<value>Recently opened sessions.</value>
<value>Sesiones abiertas recientemente.</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>Starts new terminal session based on the default profile.</value>
<value>Inicia una nueva sesión de terminal basada en el perfil predeterminado.</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>Remote Connect...</value>
<value>Conexión remota...</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>Opens a dialog for launching a new SSH or Mosh terminal session.</value>
<value>Abre un cuadro de diálogo para iniciar una nueva sesión de terminal SSH o Mosh.</value>
</data>
<data name="MenuItem_QuickLaunch_Text" xml:space="preserve">
<value>Quick Launch...</value>
<value>Comida rápida...</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>Opens a &quot;Quick Launch&quot; dialog for starting a new terminal session.</value>
<value>Abre un cuadro de diálogo &quot;Inicio rápido&quot; para iniciar una nueva sesión de terminal.</value>
</data>
<data name="MenuItem_NewWindow_Text" xml:space="preserve">
<value>New Window</value>
<value>Nueva ventana</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>New Tab</value>
<value>Nueva pestaña</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>Launches a session in a new tab.</value>
<value>Inicia una sesión en una nueva pestaña.</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>Launches a session in a new window.</value>
<value>Lanzar nueva sesión en una nueva ventana.</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Application menu type</value>
<value>Tipo de menú de la aplicación</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
<value>Plano, honrando la configuración &quot;Abrir nuevos terminales como&quot;</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
<value>&quot;Nueva pestaña&quot; / &quot;Nueva ventana&quot; en cascada</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>Quit</value>
<value>Salir</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Quit Fluent Terminal</value>
<value>Salir de Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Enabled by policy.</value>
<value>Habilitado por la política.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Background image</value>
<value>Imagen de fondo</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Use acrylic background</value>
<value>Usar fondo acrílico</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Are you sure you want to delete this background image?</value>
<value>¿Estás seguro de querer borrar esta imagen de fondo?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colors</value>
<value>Colores</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
<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>
</data>
</root>
+56 -50
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>A propos</value>
<value>À 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 sur les onglets inactifs</value>
<value>Couleur des 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>Editer le titre</value>
<value>Éditer 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 le nouvel indicateur de sortie sur les onglets d’arrière-plan</value>
<value>Afficher l&apos;indicateur de nouvelle sortie sur les onglets en arrière-plan</value>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="NeedRelaunch.Text" xml:space="preserve">
<value>Relancement requis pour appliquer le réglage</value>
<value>Redémarrage de l&apos;application requis pour appliquer le réglage</value>
<comment>GeneralSettings.xaml</comment>
</data>
<data name="NewTab.Text" xml:space="preserve">
@@ -658,16 +658,6 @@ 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">
@@ -718,14 +708,6 @@ 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
@@ -1010,7 +992,7 @@ Fuzzy</comment>
<value>Trouver le suivant</value>
</data>
<data name="FindPrevious.ToolTipService.ToolTip" xml:space="preserve">
<value>Rechercher précédent</value>
<value>Trouver le précédent</value>
</data>
<data name="SearchTextBox.PlaceholderText" xml:space="preserve">
<value>Entrez le terme de recherche</value>
@@ -1028,84 +1010,108 @@ Fuzzy</comment>
<value>Caractères séparateurs de mots</value>
</data>
<data name="Recent.Text" xml:space="preserve">
<value>Recent</value>
<value>Récent</value>
</data>
<data name="NewTab_Description" xml:space="preserve">
<value>Opens default profile in a new tab.</value>
<value>Ouvrir le profile par défaut dans un nouvel onglet.</value>
</data>
<data name="NewSshTab_Description" xml:space="preserve">
<value>Opens a new SSH or Mosh session in a new tab.</value>
<value>Ouvrir une session SSH ou Msh dans un nouvel onglet.</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>Opens &quot;Quick Launch&quot; dialog and starts session in a new tab.</value>
<value>Ouvrir le dialogue &quot;Lancement rapide&quot; et commencer une session dans un nouvel onglet.</value>
</data>
<data name="Settings_Description" xml:space="preserve">
<value>Opens settings window.</value>
<value>Ouvrir les paramètres.</value>
</data>
<data name="About_Description" xml:space="preserve">
<value>Basic info about the app.</value>
<value>Informations sur l&apos;application.</value>
</data>
<data name="Recent_Description" xml:space="preserve">
<value>Recently opened sessions.</value>
<value>Session récentes.</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>Starts new terminal session based on the default profile.</value>
<value>Commencer une nouvelle session du profil par défaut.</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>Remote Connect...</value>
<value>Connexion distante...</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>Opens a dialog for launching a new SSH or Mosh terminal session.</value>
<value>Ouvrir un dialogue pour une nouvelle session SSH ou Mosh.</value>
</data>
<data name="MenuItem_QuickLaunch_Text" xml:space="preserve">
<value>Quick Launch...</value>
<value>Lancement rapide...</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>Opens a &quot;Quick Launch&quot; dialog for starting a new terminal session.</value>
<value>Ouvrir un dialogue &quot;Lancement rapide&quot; pour un nouvelle session.</value>
</data>
<data name="MenuItem_NewWindow_Text" xml:space="preserve">
<value>New Window</value>
<value>Nouvelle fenêtre.</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>New Tab</value>
<value>Nouvel onglet.</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>Launches a session in a new tab.</value>
<value>Lancer une session dans un nouvel onglet.</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>Launches a session in a new window.</value>
<value>Lancer une session dans une nouvelle fenêtre.</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Application menu type</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
<value>Plat, honorant le paramètre &quot;Ouvrir de nouveaux terminaux comme&quot;</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
<value>&quot;Nouvel onglet&quot; / &quot;Nouvelle fenêtre&quot; en cascade.</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>Quit</value>
<value>Quitter.</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Quit Fluent Terminal</value>
<value>Quitter Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Enabled by policy.</value>
<value>Autorisé par la politique.</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Background image</value>
<value>Image de fond</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Use acrylic background</value>
<value>Utilise un fond acrylique.</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Are you sure you want to delete this background image?</value>
<value>Êtes vous sûr de vouloir supprimer cette image de fond ?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colors</value>
<value>Couleurs</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
<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>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>
+24 -16
View File
@@ -644,14 +644,6 @@ 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>
@@ -692,14 +684,6 @@ 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>
@@ -1053,4 +1037,28 @@ 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>
+24 -16
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1044,4 +1028,28 @@
<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
+43 -35
View File
@@ -641,14 +641,6 @@ 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>
@@ -689,14 +681,6 @@ 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>
@@ -985,7 +969,7 @@ Fuzzy</comment>
<value>Apre una sessione SSH o Mosh in una nuova scheda</value>
</data>
<data name="NewQuickTab_Description" xml:space="preserve">
<value>Opens &quot;Quick Launch&quot; dialog and starts session in a new tab.</value>
<value>Apre la schermata di &quot;Avvio rapido&quot; e avvia la sessione in una nuova scheda</value>
</data>
<data name="Settings_Description" xml:space="preserve">
<value>Apre la finestra impostazioni</value>
@@ -997,63 +981,87 @@ Fuzzy</comment>
<value>Sessioni aperte di recente</value>
</data>
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
<value>Starts new terminal session based on the default profile.</value>
<value>Avvia una nuova sessione di terminale con il profilo predefinito</value>
</data>
<data name="MenuItem_Remote_Text" xml:space="preserve">
<value>Connessione remota...</value>
</data>
<data name="MenuItem_Remote_Description" xml:space="preserve">
<value>Opens a dialog for launching a new SSH or Mosh terminal session.</value>
<value>Apre una schermata per la creazione di una sessione SSH o Mosh</value>
</data>
<data name="MenuItem_QuickLaunch_Text" xml:space="preserve">
<value>Avvio rapido...</value>
</data>
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
<value>Opens a &quot;Quick Launch&quot; dialog for starting a new terminal session.</value>
<value>Apre la schermata di &quot;Avvio rapido&quot; per una nuova sessione di terminale</value>
</data>
<data name="MenuItem_NewWindow_Text" xml:space="preserve">
<value>New Window</value>
<value>Nuova finestra</value>
</data>
<data name="MenuItem_NewTab_Text" xml:space="preserve">
<value>New Tab</value>
<value>Nuova scheda</value>
</data>
<data name="MenuItem_NewTab_Description" xml:space="preserve">
<value>Launches a session in a new tab.</value>
<value>Avvia la sessione in una nuova scheda</value>
</data>
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
<value>Launches a session in a new window.</value>
<value>Avvia la sessione in una nuova finestra</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Application menu type</value>
<value>Formato menu applicazione</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
<value>Lineare, le azioni seguiranno l&apos;impostazione &quot;Apri i nuovi terminali come&quot;</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
<value>Menù a cascata &quot;Nuova Scheda&quot; / &quot;Nuova finestra&quot;</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>Quit</value>
<value>Chiudi</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Quit Fluent Terminal</value>
<value>Chiudi Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Enabled by policy.</value>
<value>Attivato da policy</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Background image</value>
<value>Immagine di sfondo</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Use acrylic background</value>
<value>Usa la sfumatura acrilica per lo sfondo</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Are you sure you want to delete this background image?</value>
<value>Vuoi davvero eliminare questa immagine di sfondo?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colors</value>
<value>Colori</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
<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>Restart</value>
</data>
<data name="SessionDisconnected.Text" xml:space="preserve">
<value>Session disconnected.</value>
</data>
</root>
+24 -16
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1044,4 +1028,28 @@
<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>
+24 -16
View File
@@ -641,14 +641,6 @@ 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>
@@ -689,14 +681,6 @@ 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>
@@ -1053,4 +1037,28 @@ 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>
+24 -18
View File
@@ -659,16 +659,6 @@ 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">
@@ -719,14 +709,6 @@ 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
@@ -1110,4 +1092,28 @@ 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>
+24 -16
View File
@@ -638,14 +638,6 @@ 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>
@@ -686,14 +678,6 @@ 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>
@@ -1045,4 +1029,28 @@ 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>
+24 -16
View File
@@ -638,14 +638,6 @@ 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>
@@ -686,14 +678,6 @@ 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>
@@ -1045,4 +1029,28 @@ 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>
+24 -16
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1044,4 +1028,28 @@
<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>
+31 -23
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1012,10 +996,10 @@
<value>Запуск сессии в новом окне.</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Application menu type</value>
<value>Тип меню приложения</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
<value>Плоская, с учетом настройки &quot;Открыть новый терминал как&quot;</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>Открывать новые окна и вкладки каскадом.</value>
@@ -1031,18 +1015,42 @@
<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>Background image</value>
<value>Фоновое изображение</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Use acrylic background</value>
<value>Использовать акриловый фон</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Are you sure you want to delete this background image?</value>
<value>Удалить это фоновое изображение?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colors</value>
<value>Цвета</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
<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>
</data>
</root>
+24 -16
View File
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1044,4 +1028,28 @@
<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
@@ -637,14 +637,6 @@
<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>
@@ -685,14 +677,6 @@
<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>
@@ -1012,36 +996,60 @@
<value>在新窗口中打开会话</value>
</data>
<data name="AppMenuType.Text" xml:space="preserve">
<value>Application menu type</value>
<value>应用菜单类型</value>
</data>
<data name="AppMenuType_Flat.Content" xml:space="preserve">
<value>Flat, honoring &quot;Open new terminals as&quot; setting</value>
<value>扁平,荣耀的“打开新的终端”设置</value>
</data>
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
<value>&quot;New Tab&quot; / &quot;New Window&quot; cascading</value>
<value>“新标签”/“新窗口”级联菜单</value>
</data>
<data name="Quit.Text" xml:space="preserve">
<value>退出</value>
</data>
<data name="Quit.Description" xml:space="preserve">
<value>Quit Fluent Terminal</value>
<value>退出 Fluent Terminal</value>
</data>
<data name="EnabledByPolicy" xml:space="preserve">
<value>Enabled by policy.</value>
<value>根据策略启用。</value>
</data>
<data name="BackgroundImage.Content" xml:space="preserve">
<value>Background image</value>
<value>背景图片</value>
</data>
<data name="AcrylicBackground.Header" xml:space="preserve">
<value>Use acrylic background</value>
<value>使用亚克力背景</value>
</data>
<data name="ConfirmDeleteBackgroundImage" xml:space="preserve">
<value>Are you sure you want to delete this background image?</value>
<value>确定要删除该背景图片吗?</value>
</data>
<data name="Colors.Text" xml:space="preserve">
<value>Colors</value>
<value>颜色</value>
</data>
<data name="BrightColors.Text" xml:space="preserve">
<value>Bright colors</value>
<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>
</data>
</root>
+2 -3
View File
@@ -14,7 +14,6 @@
</Page.Background>
<Page.Resources>
<converters:TerminalViewModelToViewConverter x:Key="TerminalViewModelToViewConverter" />
<converters:AppMenuViewModelToFlyoutMenuConverter x:Key="AppMenuViewModelToFlyoutMenuConverter" />
</Page.Resources>
<Grid x:Name="Root">
<Grid.Background>
@@ -40,10 +39,10 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Flyout="{x:Bind ViewModel.MenuViewModel, Mode=OneWay, Converter={StaticResource AppMenuViewModelToFlyoutMenuConverter}}" Style="{StaticResource TitleBarButtonStyle}">
<Button Flyout="{x:Bind ViewModel.AppMenuViewModel, Mode=OneWay, Converter={StaticResource MenuViewModelToFlyoutMenuConverter}}" Style="{StaticResource TitleBarButtonStyle}">
<Button.Content>
<Viewbox Width="16" Height="16">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE700;" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE700;" />
</Viewbox>
</Button.Content>
</Button>
+14 -10
View File
@@ -2,24 +2,28 @@
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"
mc:Ignorable="d"
Visibility="{Binding ShowOverlay, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}">
Visibility="{Binding ShowOverlay, Mode=OneWay, Converter={StaticResource TrueToVisibleConverter}}"
mc:Ignorable="d">
<UserControl.DataContext>
<viewModels:OverlayViewModel />
</UserControl.DataContext>
<Grid
<controls:DropShadowPanel
Margin="12"
Padding="6"
HorizontalAlignment="Right"
VerticalAlignment="Bottom">
<Grid.Background>
<SolidColorBrush Color="{ThemeResource SystemAccentColor}" />
</Grid.Background>
<TextBlock Foreground="White" Text="{Binding OverlayContent}" />
</Grid>
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>
</UserControl>
+15 -15
View File
@@ -33,8 +33,8 @@
Tag="general">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="e"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE713;"
ToolTipService.ToolTip="General" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -44,8 +44,8 @@
Tag="terminal">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="d"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE771;"
ToolTipService.ToolTip="Terminal" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -55,8 +55,8 @@
Tag="profiles">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="a"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE756;"
ToolTipService.ToolTip="Shell" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -66,8 +66,8 @@
Tag="sshprofiles">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="a"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE774;"
ToolTipService.ToolTip="Shell" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -77,8 +77,8 @@
Tag="keyBindings">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="b"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE765;"
ToolTipService.ToolTip="Keybindings" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
@@ -88,9 +88,9 @@
Tag="mouse">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="g"
ToolTipService.ToolTip="Keybindings" />
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE962;"
ToolTipService.ToolTip="Mouse" />
</controls:NavigationViewItem.Icon>
</controls:NavigationViewItem>
<controls:NavigationViewItem
@@ -99,8 +99,8 @@
Tag="themes">
<controls:NavigationViewItem.Icon>
<FontIcon
FontFamily="/Assets/settingsicons.ttf#settingsicons"
Glyph="c"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xE790;"
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,7 +24,6 @@
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="General"
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
@@ -178,6 +177,12 @@
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}"
@@ -210,19 +215,20 @@
<CheckBox
x:Uid="PrintableOutputOnly"
Content="Printable output only"
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}"
IsChecked="{x:Bind ViewModel.PrintableOutputOnly, Mode=TwoWay}" />
IsChecked="{x:Bind ViewModel.PrintableOutputOnly, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}" />
<StackPanel Orientation="Horizontal" Spacing="5">
<TextBox
x:Uid="LogDirectoryPath"
Text="{x:Bind ViewModel.LogDirectoryPath, Mode=TwoWay}"
MinWidth="250"
MaxWidth="250"
IsEnabled="{x:Bind ViewModel.EnableLogging, Mode=OneWay}"
MaxWidth="250" MinWidth="250" />
Text="{x:Bind ViewModel.LogDirectoryPath, Mode=TwoWay}" />
<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,11 +19,10 @@
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,10,0,0"
x:Uid="Keybindings"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
x:Uid="Keybindings"
Text="Keybindings" />
<CommandBar
Grid.Column="1"
@@ -31,16 +30,19 @@
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,11 +18,10 @@
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,10,0,0"
x:Uid="Mouse"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
x:Uid="Mouse"
Text="Mouse" />
<CommandBar
Grid.Column="1"
@@ -31,22 +30,25 @@
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
Margin="{StaticResource ItemMargin}"
x:Uid="CopyOnSelect"
Margin="{StaticResource ItemMargin}"
Header="Copy on select"
IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}" />
<StackPanel Margin="{StaticResource ItemMargin}">
<TextBlock Margin="0,0,0,8" x:Uid="MiddleButtonAction" Text="Middle button action" />
<TextBlock
x:Uid="MiddleButtonAction"
Margin="0,0,0,8"
Text="Middle button action" />
<RadioButton
x:Uid="MouseNothing"
Content="Nothing"
@@ -62,10 +64,18 @@
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 Margin="0,0,0,8" x:Uid="RightButtonAction" Text="Right button action" />
<TextBlock
x:Uid="RightButtonAction"
Margin="0,0,0,8"
Text="Right button action" />
<RadioButton
x:Uid="MouseNothing"
Content="Nothing"
@@ -81,6 +91,11 @@
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,18 +249,12 @@
IsEnabled="{x:Bind InEditMode, Mode=OneWay}"
IsOn="{x:Bind ProfileVm.UseConPty, Mode=TwoWay}" />
<ComboBox
x:Uid="LineEndingMode"
<ToggleSwitch
x:Uid="UseBuffer"
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>
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
@@ -356,6 +350,18 @@
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"
@@ -380,18 +386,6 @@
</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,6 +291,12 @@
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"
@@ -299,19 +305,6 @@
<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"
@@ -475,6 +468,19 @@
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"
@@ -499,19 +505,6 @@
</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,7 +23,6 @@
</Grid.ColumnDefinitions>
<TextBlock
x:Uid="Terminal"
Margin="0,10,0,0"
VerticalAlignment="Center"
FontSize="28"
Style="{StaticResource TitleTextBlockStyle}"
@@ -166,12 +165,6 @@
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="Segoe MDL2 Assets" Glyph="&#xEE71;" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xEE71;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
+11 -108
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"
Tapped="OnScrollLeftButtonTapped">
Visibility="Collapsed">
<RepeatButton.Content>
<Viewbox Width="12" Height="12">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76B;" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE76B;" />
</Viewbox>
</RepeatButton.Content>
</RepeatButton>
@@ -68,6 +68,7 @@
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>
@@ -78,108 +79,10 @@
</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.Color, Mode=OneWay, Converter={StaticResource ColorResourceKeyFallbackConverter}, ConverterParameter=SystemControlHighlightAccentBrush}"
Background="{x:Bind TabTheme.Theme.Color, Mode=OneWay, Converter={StaticResource ColorResourceKeyFallbackConverter}, ConverterParameter=SystemControlHighlightAccentBrush}"
RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
@@ -196,7 +99,7 @@
Height="12"
VerticalAlignment="Center"
ToolTipService.ToolTip="Exited with error">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE814;" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE814;" />
</Viewbox>
</Grid>
<TextBlock
@@ -228,7 +131,7 @@
Height="12"
VerticalAlignment="Center"
ToolTipService.ToolTip="New output">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEA38;" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xEA38;" />
</Viewbox>
</Grid>
</Grid>
@@ -360,12 +263,12 @@
Padding="0,0,0,0"
Click="OnScrollRightButtonTapped"
Style="{StaticResource TitleBarRepeatButtonStyle}"
Tapped="OnScrollRightButtonTapped"
ToolTipService.ToolTip="Scroll right"
Visibility="Collapsed"
Tapped="OnScrollRightButtonTapped">
Visibility="Collapsed">
<RepeatButton.Content>
<Viewbox Width="12" Height="12">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE76C;" />
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" 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:settings="using:FluentTerminal.App.ViewModels.Settings"
xmlns:views="using:FluentTerminal.App.Views">
<views:TabThemeTemplateSelector x:Key="TabThemeTemplateSelector">
<views:TabThemeTemplateSelector.DefaultTemplate>
<DataTemplate x:DataType="models:TabTheme">
<StackPanel Orientation="Horizontal">
<FontIcon
Margin="0,0,6,0"
FontFamily="Segoe MDL2 Assets"
Glyph="&#xF126;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
Margin="0,0,6,0"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Glyph="&#xF126;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay, Converter={StaticResource I18NConverter}}" />
</StackPanel>
</DataTemplate>
</views:TabThemeTemplateSelector.DefaultTemplate>
@@ -21,11 +21,11 @@
<DataTemplate x:DataType="models:TabTheme">
<StackPanel Orientation="Horizontal">
<FontIcon
Margin="0,0,6,0"
FontFamily="Segoe MDL2 Assets"
Foreground="{x:Bind Color}"
Glyph="&#xF127;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
Margin="0,0,6,0"
FontFamily="{StaticResource SymbolThemeFontFamily}"
Foreground="{x:Bind Color}"
Glyph="&#xF127;" />
<TextBlock Text="{x:Bind Name, Mode=OneWay, Converter={StaticResource I18NConverter}}" />
</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>
+140 -54
View File
@@ -2,6 +2,10 @@
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"
@@ -10,62 +14,144 @@
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="TerminalContainer" Grid.Row="0" />
<Grid x:Name="TerminalContainer" />
<views:OverlayView x:Name="MessageOverlay" />
<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>
<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">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xF78B;" />
</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>
</Grid>
</UserControl>
@@ -8,7 +8,6 @@ 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
@@ -66,12 +65,12 @@ namespace FluentTerminal.App.Views
_terminalView?.FocusTerminalAsync();
}
private void OnFindNextRequested(object sender, string e)
private void OnFindNextRequested(object sender, SearchRequest e)
{
_terminalView.FindNextAsync(e);
}
private void OnFindPreviousRequested(object sender, string e)
private void OnFindPreviousRequested(object sender, SearchRequest e)
{
_terminalView.FindPreviousAsync(e);
}
@@ -99,7 +98,7 @@ namespace FluentTerminal.App.Views
}
else if (e.Key == VirtualKey.Enter)
{
ViewModel.FindNextCommand.Execute(null);
ViewModel.FindPreviousCommand.Execute(null);
}
}
@@ -1,6 +1,5 @@
using FluentTerminal.App.Converters;
using FluentTerminal.App.Services;
using FluentTerminal.App.Services.Utilities;
using FluentTerminal.App.Utilities;
using FluentTerminal.App.ViewModels;
using FluentTerminal.Models;
@@ -13,21 +12,19 @@ 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;
@@ -120,6 +117,7 @@ namespace FluentTerminal.App.Views
#endregion Resize handling
public event EventHandler<object> OnOutput;
public event EventHandler<string> OnPaste;
public XtermTerminalView()
{
@@ -135,17 +133,6 @@ 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);
@@ -202,24 +189,24 @@ namespace FluentTerminal.App.Views
return ExecuteScriptAsync(@"serializeTerminal()");
}
public Task FindNextAsync(string searchText)
public Task FindNextAsync(SearchRequest request)
{
if (_terminalClosed)
{
return Task.CompletedTask;
}
return ExecuteScriptAsync($"findNext('{searchText}')");
return ExecuteScriptAsync($"findNext('{request.Term}', {request.MatchCase.ToString().ToLower()}, {request.WholeWord.ToString().ToLower()}, {request.Regex.ToString().ToLower()})");
}
public Task FindPreviousAsync(string searchText)
public Task FindPreviousAsync(SearchRequest request)
{
if (_terminalClosed)
{
return Task.CompletedTask;
}
return ExecuteScriptAsync($"findPrevious('{searchText}')");
return ExecuteScriptAsync($"findPrevious('{request.Term}', {request.MatchCase.ToString().ToLower()}, {request.WholeWord.ToString().ToLower()}, {request.Regex.ToString().ToLower()})");
}
public Task FocusTerminalAsync()
@@ -237,7 +224,18 @@ 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;
@@ -245,6 +243,14 @@ 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();
@@ -260,12 +266,6 @@ 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,14 +279,8 @@ namespace FluentTerminal.App.Views
}
}
var response = await ViewModel.Terminal.StartShellProcessAsync(ViewModel.ShellProfile, size, sessionType, ViewModel.XtermBufferState).ConfigureAwait(false);
if (!response.Success)
if (false == await StartShellProcessAsync(size).ConfigureAwait(false))
{
await Dispatcher.ExecuteAsync(async () =>
await ViewModel.DialogService.ShowMessageDialogAsync("Error", response.Error, DialogButton.OK))
.ConfigureAwait(false);
ViewModel.Terminal.ReportLauchFailed();
return;
}
@@ -341,31 +335,40 @@ namespace FluentTerminal.App.Views
}
}
void IxtermEventListener.OnMouseClick(MouseButton mouseButton, int x, int y, bool hasSelection)
void IxtermEventListener.OnMouseClick(MouseButton mouseButton, int x, int y, bool hasSelection, string hoveredUri)
{
if (_terminalClosed)
{
return;
}
if (mouseButton == MouseButton.Middle)
var action = MouseAction.None;
switch (mouseButton)
{
if (ViewModel.ApplicationSettings.MouseMiddleClickAction == MouseAction.ContextMenu)
{
Dispatcher.ExecuteAsync(() => ShowContextMenu(x, y, hasSelection), enforceNewSchedule: true);
}
else if (ViewModel.ApplicationSettings.MouseMiddleClickAction == MouseAction.Paste)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
case MouseButton.Middle:
action = ViewModel.ApplicationSettings.MouseMiddleClickAction;
break;
case MouseButton.Right:
action = ViewModel.ApplicationSettings.MouseRightClickAction;
break;
}
else if (mouseButton == MouseButton.Right)
if (action == MouseAction.ContextMenu)
{
if (ViewModel.ApplicationSettings.MouseRightClickAction == 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)
{
Dispatcher.ExecuteAsync(() => ShowContextMenu(x, y, hasSelection), enforceNewSchedule: true);
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Copy));
}
else if (ViewModel.ApplicationSettings.MouseRightClickAction == MouseAction.Paste)
else
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
@@ -443,11 +446,6 @@ 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);
@@ -470,6 +468,7 @@ namespace FluentTerminal.App.Views
var scriptTask = await Dispatcher.ExecuteAsync(() => _webView.InvokeScriptAsync("eval", new[] {script}))
.ConfigureAwait(false);
return await scriptTask;
}
catch (Exception e)
@@ -485,15 +484,11 @@ namespace FluentTerminal.App.Views
return commandKeyBindings.Values.SelectMany(k => k).Concat(profiles.SelectMany(x => x.KeyBindings).Concat(sshprofiles.SelectMany(x => x.KeyBindings)));
}
private void Paste_Click(object sender, RoutedEventArgs e)
{
((IxtermEventListener)this).OnKeyboardCommand(nameof(Command.Paste));
}
private void ShowContextMenu(int x, int y, bool terminalHasSelection)
private void ShowContextMenu(int x, int y, bool terminalHasSelection, string hoveredUri)
{
ViewModel.HoveredUri = hoveredUri;
ViewModel.HasSelection = terminalHasSelection;
var flyout = (MenuFlyout)_webView.ContextFlyout;
_copyMenuItem.IsEnabled = terminalHasSelection;
flyout.ShowAt(_webView, new Point(x, y));
}
@@ -514,9 +509,6 @@ 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)
{
@@ -568,7 +560,26 @@ namespace FluentTerminal.App.Views
_outputBlockedBuffer?.Dispose();
}
public Task PasteAsync(string text) => ExecuteScriptAsync(
$"window.term.paste('{text.Replace(@"\", @"\\").Replace("'", @"\'").Replace("\n", @"\n").Replace("\r", @"\r")}')");
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;
}
}
}
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -5,7 +5,7 @@
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "xcopy /y /s node_modules\\xterm\\css\\xterm.css dist\\ && xcopy /y /s src\\style.css dist\\ && xcopy /y /s src\\index.html dist\\ && npx webpack --config webpack.config.js"
"build": "xcopy /y /s node_modules\\xterm\\css\\xterm.css dist\\ && xcopy /y /s src\\style.css dist\\ && xcopy /y /s src\\index.html dist\\ && cd node_modules/xterm && yarn && yarn package && cd ../.. && npx webpack --config webpack.config.js"
},
"author": "FS Apps",
"license": "GPL-3.0",
@@ -16,9 +16,9 @@
"webpack-cli": "^3.2.3"
},
"dependencies": {
"xterm": "^4.4.0",
"xterm": "felixse/xterm.js#fix-edge-selection-color",
"xterm-addon-fit": "^0.3.0",
"xterm-addon-search": "^0.4.0",
"xterm-addon-search": "^0.5.0",
"xterm-addon-serialize": "^0.1.2",
"xterm-addon-unicode11": "^0.1.1",
"xterm-addon-web-links": "^0.2.1"
+48 -51
View File
@@ -5,20 +5,19 @@ 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): void;
findPrevious(content: string): void;
findNext(content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean): void;
findPrevious(content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean): void;
serializeTerminal() : void;
}
@@ -30,6 +29,7 @@ let searchAddon: SearchAddon;
let serializeAddon: SerializeAddon;
let webLinksAddon: WebLinksAddon;
let unicode11Addon: Unicode11Addon;
let altGrPressed = false;
const terminalContainer = document.getElementById('terminal-container');
@@ -56,6 +56,7 @@ window.createTerminal = (options, theme, keyBindings) => {
theme = JSON.parse(theme);
window.keyBindings = JSON.parse(keyBindings);
window.hoveredUri = "";
options = JSON.parse(options);
@@ -79,50 +80,14 @@ window.createTerminal = (options, theme, keyBindings) => {
term = new Terminal(terminalOptions);
const linkMatcherOptions: ILinkMatcherOptions = {
leaveCallback: () => window.onmouseup = (e) => defaultOnMouseUpHandler(e),
willLinkActivate: (event: MouseEvent, uri: string) => {
window.onmouseup = (e) => linkHoverOnMouseUpHandler(event, uri);
return true;
leaveCallback: () => {
window.hoveredUri = "";
},
tooltipCallback: (event: MouseEvent, uri: string) => {
window.hoveredUri = uri;
}
};
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();
@@ -141,6 +106,10 @@ window.createTerminal = (options, theme, keyBindings) => {
term.writeUtf8(data);
});
window.terminalBridge.onpaste = (text => {
term.paste(text);
});
term.onData(data => {
window.terminalBridge.inputReceived(data);
});
@@ -173,12 +142,40 @@ window.createTerminal = (options, theme, keyBindings) => {
resizeTimeout = setTimeout(() => fitAddon.fit(), 500);
}
window.onmouseup = (e) => defaultOnMouseUpHandler(e);
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.onkeydown = (e) => {
// Disable WebView zooming to prevent crash on too small font size
if ((e.ctrlKey && !e.altKey && (e.keyCode === 189 || e.keyCode === 187)) ||
(e.ctrlKey && (e.key === "Add" || e.key === "Subtract"))) {
e.preventDefault();
}
}
window.addEventListener("wheel", function(event){
// Disable WebView zooming to prevent crash on too small font size
if(event.ctrlKey){
event.preventDefault();
}
});
term.attachCustomKeyEventHandler(function (e) {
if (e.type != "keydown") {
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) {
return true;
}
for (var i = 0; i < window.keyBindings.length; i++) {
var keyBinding = window.keyBindings[i];
if (keyBinding.ctrl == e.ctrlKey
@@ -257,12 +254,12 @@ window.changeKeyBindings = (keyBindings) => {
window["keyBindings"] = keyBindings;
}
window.findNext = (content: string) => {
searchAddon.findNext(content);
window.findNext = (content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean) => {
searchAddon.findNext(content, { caseSensitive: caseSensitive, wholeWord: wholeWord, regex: regex });
}
window.findPrevious = (content: string) => {
searchAddon.findPrevious(content);
window.findPrevious = (content: string, caseSensitive: boolean, wholeWord: boolean, regex: boolean) => {
searchAddon.findPrevious(content, { caseSensitive: caseSensitive, wholeWord: wholeWord, regex: regex });
}
document.oncontextmenu = function () {
File diff suppressed because it is too large. Load diff
+3 -1
View File
@@ -25,6 +25,7 @@ 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
{
@@ -48,7 +49,8 @@ namespace FluentTerminal.Models
EnableLogging = EnableLogging,
PrintableOutputOnly = PrintableOutputOnly,
LogDirectoryPath = LogDirectoryPath,
UseConPty = UseConPty
UseConPty = UseConPty,
ShowTextCopied = ShowTextCopied
};
}
}
+2 -3
View File
@@ -7,8 +7,6 @@
PreviousTab,
NewTab,
NewWindow,
ConfigurableNewTab,
ConfigurableNewWindow,
NewSshTab,
NewSshWindow,
NewCustomCommandTab,
@@ -32,6 +30,7 @@
SwitchToTerm7,
SwitchToTerm8,
SwitchToTerm9,
DuplicateTab
DuplicateTab,
ReconnectTab
}
}
@@ -1,12 +0,0 @@
// ReSharper disable InconsistentNaming
namespace FluentTerminal.Models.Enums
{
public enum LineEndingStyle
{
DoNotModify = 0,
ToCR,
ToCRLF,
ToLF
}
}
+2 -1
View File
@@ -4,6 +4,7 @@
{
None,
ContextMenu,
Paste
Paste,
CopySelectionOrPaste
}
}
+2 -1
View File
@@ -20,6 +20,7 @@
GetCommandPathRequest = 15,
PauseTerminalOutputRequest = 16,
PauseTerminalOutputResponse = 17,
QuitApplicationRequest = 18
QuitApplicationRequest = 18,
ReadTextFileRequest = 19
}
}
@@ -0,0 +1,9 @@
namespace FluentTerminal.Models.Requests
{
public class ReadTextFileRequest : IMessage
{
public byte Identifier => (byte)MessageIdentifiers.ReadTextFileRequest;
public string Path { get; set; }
}
}
@@ -1,11 +1,7 @@
namespace FluentTerminal.Models.Responses
{
public class CommonResponse : IMessage
public class CommonResponse : TerminalResponse
{
public virtual byte Identifier => (byte) MessageIdentifiers.CommonResponse;
public bool Success { get; set; }
public string Error { get; set; }
public override byte Identifier => (byte) MessageIdentifiers.CommonResponse;
}
}
@@ -1,9 +1,9 @@
namespace FluentTerminal.Models.Responses
{
public class CreateTerminalResponse : TerminalResponse, IMessage
public class CreateTerminalResponse : TerminalResponse
{
public byte Identifier => (byte) MessageIdentifiers.CreateTerminalResponse;
public override byte Identifier => (byte) MessageIdentifiers.CreateTerminalResponse;
public string ShellExecutableName { get; set; }
public string Name { get; set; }
}
}
@@ -1,7 +1,7 @@
namespace FluentTerminal.Models.Responses
{
public class PauseTerminalOutputResponse : TerminalResponse, IMessage
public class PauseTerminalOutputResponse : TerminalResponse
{
public byte Identifier => (byte) MessageIdentifiers.PauseTerminalOutputResponse;
public override byte Identifier => (byte) MessageIdentifiers.PauseTerminalOutputResponse;
}
}
@@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FluentTerminal.Models.Responses
namespace FluentTerminal.Models.Responses
{
public class TerminalResponse
public abstract class TerminalResponse : IMessage
{
public abstract byte Identifier { get; }
public bool Success { get; set; }
public string Error { get; set; }
}
+10
View File
@@ -0,0 +1,10 @@
namespace FluentTerminal.Models
{
public class SearchRequest
{
public string Term { get; set; }
public bool MatchCase { get; set; }
public bool WholeWord { get; set; }
public bool Regex { get; set; }
}
}
+3 -20
View File
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using FluentTerminal.Models.Enums;
using System.Linq;
using Newtonsoft.Json;
@@ -30,8 +29,8 @@ namespace FluentTerminal.Models
WorkingDirectory = other.WorkingDirectory;
TabThemeId = other.TabThemeId;
TerminalThemeId = other.TerminalThemeId;
LineEndingTranslation = other.LineEndingTranslation;
UseConPty = other.UseConPty;
UseBuffer = other.UseBuffer;
KeyBindings = other.KeyBindings.Select(x => new KeyBinding(x)).ToList();
}
@@ -42,9 +41,9 @@ namespace FluentTerminal.Models
public string Location { get; set; }
public string WorkingDirectory { get; set; }
public int TabThemeId { get; set; }
public LineEndingStyle LineEndingTranslation { get; set; }
public Dictionary<string, string> EnvironmentVariables { get; set; } = new Dictionary<string, string>();
public bool UseConPty { get; set; }
public bool UseBuffer { get; set; } = true;
public int MigrationVersion { get; set; } = CurrentMigrationVersion;
@@ -54,22 +53,6 @@ namespace FluentTerminal.Models
[JsonIgnore]
public object Tag { get; set; }
public string TranslateLineEndings(string content)
{
switch (LineEndingTranslation)
{
case LineEndingStyle.ToCR:
return NewlinePattern.Replace(content, "\r");
case LineEndingStyle.ToCRLF:
return NewlinePattern.Replace(content, "\r\n");
case LineEndingStyle.ToLF:
return NewlinePattern.Replace(content, "\n");
case LineEndingStyle.DoNotModify:
default:
return content;
}
}
public Guid TerminalThemeId { get; set; }
public ICollection<KeyBinding> KeyBindings { get; set; } = new List<KeyBinding>();
@@ -93,8 +76,8 @@ namespace FluentTerminal.Models
&& other.WorkingDirectory.NullableEqualTo(WorkingDirectory)
&& other.TabThemeId.Equals(TabThemeId)
&& other.TerminalThemeId.Equals(TerminalThemeId)
&& other.LineEndingTranslation == LineEndingTranslation
&& other.UseConPty == UseConPty
&& other.UseBuffer == UseBuffer
&& other.KeyBindings.SequenceEqual(KeyBindings);
}
Loaded 100 of 230 files, more files were not shown because too many files have changed in this diff. Show more