Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e17cf894b8 | ||
|
|
dec492e39a | ||
|
|
20540937fe | ||
|
|
3dd29d7bb7 |
No files matched your search
@@ -20,4 +20,4 @@ jobs:
|
||||
uses: warrenbuckley/Setup-MSBuild@v1
|
||||
|
||||
- name: MSBuild
|
||||
run: msbuild FluentTerminal.sln -t:build -p:Configuration=Debug -p:Platform=x64 -m -restore
|
||||
run: msbuild FluentTerminal.sln -t:build -p:Configuration=Debug -p:Platform=x64 -p:AppxPackage=false -m -restore
|
||||
@@ -115,6 +115,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>
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace FluentTerminal.App.ViewModels
|
||||
Task ChangeKeyBindingsAsync();
|
||||
Task ChangeOptionsAsync(TerminalOptions options);
|
||||
Task InitializeAsync(TerminalViewModel viewModel);
|
||||
Task ReconnectAsync();
|
||||
void DisposalPrepare();
|
||||
Task FindNextAsync(SearchRequest request);
|
||||
Task FindPreviousAsync(SearchRequest request);
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace FluentTerminal.App.ViewModels
|
||||
_keyboardCommandService.RegisterCommandHandler(nameof(Command.ChangeTabTitle), async () => await SelectedTerminal.EditTitleAsync());
|
||||
_keyboardCommandService.RegisterCommandHandler(nameof(Command.CloseTab), CloseCurrentTab);
|
||||
_keyboardCommandService.RegisterCommandHandler(nameof(Command.DuplicateTab), async () => await AddTabAsync(SelectedTerminal.ShellProfile.Clone()));
|
||||
_keyboardCommandService.RegisterCommandHandler(nameof(Command.ReconnectTab), async () => { if (SelectedTerminal.ReconnectTabCommand.CanExecute()) await SelectedTerminal.ReconnectTabAsync(); });
|
||||
|
||||
// Add all of the commands for switching to a tab of a given ID, if there's one open there
|
||||
for (int i = 0; i < 9; i++)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -151,6 +151,7 @@ namespace FluentTerminal.App.ViewModels
|
||||
CloseSearchPanelCommand = new RelayCommand(CloseSearchPanel, 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));
|
||||
@@ -250,6 +251,8 @@ namespace FluentTerminal.App.ViewModels
|
||||
|
||||
public RelayCommand DuplicateTabCommand { get; }
|
||||
|
||||
public AsyncCommand ReconnectTabCommand { get; }
|
||||
|
||||
public ICommand CopyLinkCommand { get; private set; }
|
||||
|
||||
public ICommand CopyCommand { get; private set; }
|
||||
@@ -336,6 +339,7 @@ namespace FluentTerminal.App.ViewModels
|
||||
{
|
||||
HasNewOutput = false;
|
||||
}
|
||||
ReconnectTabCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +546,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;
|
||||
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -1089,4 +1089,10 @@ Type "أخرج من منفذ الأوامر " then type the name in th
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -1079,4 +1079,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1111,4 +1111,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -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 "{0}" tab?</value>
|
||||
<value>¿Estás seguro que quieres cerrar la pestaña "{0}"?</value>
|
||||
<comment>ViewModel</comment>
|
||||
</data>
|
||||
<data name="ConfirmCloseWindow" xml:space="preserve">
|
||||
@@ -831,240 +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'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. 'ssh username@host')</value>
|
||||
<value>Introduce un comando (p.e. 'ssh username@host')</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 "Quick Launch" dialog and starts session in a new tab.</value>
|
||||
<value>Abre el cuadro de diálogo "Inicio rápido" 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 "Quick Launch" dialog for starting a new terminal session.</value>
|
||||
<value>Abre un cuadro de diálogo "Inicio rápido" 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 "Open new terminals as" setting</value>
|
||||
<value>Plano, honrando la configuración "Abrir nuevos terminales como"</value>
|
||||
</data>
|
||||
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
|
||||
<value>"New Tab" / "New Window" cascading</value>
|
||||
<value>"Nueva pestaña" / "Nueva ventana" 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>Copy link</value>
|
||||
<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>Whole word</value>
|
||||
<value>Toda la palabra</value>
|
||||
</data>
|
||||
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Case sensitive</value>
|
||||
<value>Distingue mayúsculas y minúsculas</value>
|
||||
</data>
|
||||
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
|
||||
<value>Copy selection or paste</value>
|
||||
<value>Copiar selección o pegar</value>
|
||||
</data>
|
||||
<data name="UseBuffer" xml:space="preserve">
|
||||
<value>Use smart buffer</value>
|
||||
<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>
|
||||
@@ -1061,7 +1061,7 @@ Fuzzy</comment>
|
||||
<value>Application menu type</value>
|
||||
</data>
|
||||
<data name="AppMenuType_Flat.Content" xml:space="preserve">
|
||||
<value>Flat, honoring "Open new terminals as" setting</value>
|
||||
<value>Plat, honorant le paramètre "Ouvrir de nouveaux terminaux comme"</value>
|
||||
</data>
|
||||
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
|
||||
<value>"Nouvel onglet" / "Nouvelle fenêtre" en cascade.</value>
|
||||
@@ -1108,4 +1108,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1055,4 +1055,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -969,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 "Quick Launch" dialog and starts session in a new tab.</value>
|
||||
<value>Apre la schermata di "Avvio rapido" e avvia la sessione in una nuova scheda</value>
|
||||
</data>
|
||||
<data name="Settings_Description" xml:space="preserve">
|
||||
<value>Apre la finestra impostazioni</value>
|
||||
@@ -981,81 +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 "Quick Launch" dialog for starting a new terminal session.</value>
|
||||
<value>Apre la schermata di "Avvio rapido" 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 "Open new terminals as" setting</value>
|
||||
<value>Lineare, le azioni seguiranno l'impostazione "Apri i nuovi terminali come"</value>
|
||||
</data>
|
||||
<data name="AppMenuType_Cascading.Content" xml:space="preserve">
|
||||
<value>"New Tab" / "New Window" cascading</value>
|
||||
<value>Menù a cascata "Nuova Scheda" / "Nuova finestra"</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>Copy link</value>
|
||||
<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>Whole word</value>
|
||||
<value>Parola intera</value>
|
||||
</data>
|
||||
<data name="SearchCaseSensitive.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Case sensitive</value>
|
||||
<value>Sensibile a maiuscole/minuscole</value>
|
||||
</data>
|
||||
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
|
||||
<value>Copy selection or paste</value>
|
||||
<value>Copia selezione o incolla</value>
|
||||
</data>
|
||||
<data name="UseBuffer" xml:space="preserve">
|
||||
<value>Use smart buffer</value>
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -1055,4 +1055,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1110,4 +1110,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1047,4 +1047,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1047,4 +1047,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -1047,4 +1047,10 @@
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -386,7 +386,7 @@ Fuzzy</comment>
|
||||
<comment>ShellProfileSettings.xaml</comment>
|
||||
</data>
|
||||
<data name="LineEndingStyle.DoNotModify" xml:space="preserve">
|
||||
<value>不改变</value>
|
||||
<value>不改变结束行</value>
|
||||
<comment>ShellProfileSettings.xaml</comment>
|
||||
</data>
|
||||
<data name="EditAppBarButton.Label" xml:space="preserve">
|
||||
@@ -968,52 +968,52 @@ Fuzzy</comment>
|
||||
<value>单词分隔符</value>
|
||||
</data>
|
||||
<data name="Recent.Text" xml:space="preserve">
|
||||
<value>Recent</value>
|
||||
<value>最近</value>
|
||||
</data>
|
||||
<data name="NewTab_Description" xml:space="preserve">
|
||||
<value>Opens default profile in a new tab.</value>
|
||||
</data>
|
||||
<data name="NewSshTab_Description" xml:space="preserve">
|
||||
<value>Opens a new SSH or Mosh session in a new tab.</value>
|
||||
<value>从新标签页打开SSH或Mosh会话</value>
|
||||
</data>
|
||||
<data name="NewQuickTab_Description" xml:space="preserve">
|
||||
<value>Opens "Quick Launch" dialog and starts session in a new tab.</value>
|
||||
</data>
|
||||
<data name="Settings_Description" xml:space="preserve">
|
||||
<value>Opens settings window.</value>
|
||||
<value>打开设置页面</value>
|
||||
</data>
|
||||
<data name="About_Description" xml:space="preserve">
|
||||
<value>Basic info about the app.</value>
|
||||
<value>关于</value>
|
||||
</data>
|
||||
<data name="Recent_Description" xml:space="preserve">
|
||||
<value>Recently opened sessions.</value>
|
||||
<value>最近打开的会话</value>
|
||||
</data>
|
||||
<data name="MenuItem_DefaultProfile_Description" xml:space="preserve">
|
||||
<value>Starts new terminal session based on the default profile.</value>
|
||||
</data>
|
||||
<data name="MenuItem_Remote_Text" xml:space="preserve">
|
||||
<value>Remote Connect...</value>
|
||||
<value>远程连接</value>
|
||||
</data>
|
||||
<data name="MenuItem_Remote_Description" xml:space="preserve">
|
||||
<value>Opens a dialog for launching a new SSH or Mosh terminal session.</value>
|
||||
</data>
|
||||
<data name="MenuItem_QuickLaunch_Text" xml:space="preserve">
|
||||
<value>Quick Launch...</value>
|
||||
<value>快捷启动</value>
|
||||
</data>
|
||||
<data name="MenuItem_QuickLaunch_Description" xml:space="preserve">
|
||||
<value>Opens a "Quick Launch" dialog for starting a new terminal session.</value>
|
||||
</data>
|
||||
<data name="MenuItem_NewWindow_Text" xml:space="preserve">
|
||||
<value>New Window</value>
|
||||
<value>新建窗口</value>
|
||||
</data>
|
||||
<data name="MenuItem_NewTab_Text" xml:space="preserve">
|
||||
<value>New Tab</value>
|
||||
<value>新建标签页</value>
|
||||
</data>
|
||||
<data name="MenuItem_NewTab_Description" xml:space="preserve">
|
||||
<value>Launches a session in a new tab.</value>
|
||||
<value>从新标签页启动会话</value>
|
||||
</data>
|
||||
<data name="MenuItem_NewWindow_Description" xml:space="preserve">
|
||||
<value>Launches a session in a new window.</value>
|
||||
<value>从新窗口启动会话</value>
|
||||
</data>
|
||||
<data name="AppMenuType.Text" xml:space="preserve">
|
||||
<value>Application menu type</value>
|
||||
@@ -1025,16 +1025,16 @@ Fuzzy</comment>
|
||||
<value>"New Tab" / "New Window" cascading</value>
|
||||
</data>
|
||||
<data name="Quit.Text" xml:space="preserve">
|
||||
<value>Quit</value>
|
||||
<value>退出</value>
|
||||
</data>
|
||||
<data name="Quit.Description" xml:space="preserve">
|
||||
<value>Quit Fluent Terminal</value>
|
||||
<value>退出关于</value>
|
||||
</data>
|
||||
<data name="EnabledByPolicy" xml:space="preserve">
|
||||
<value>Enabled by policy.</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>
|
||||
@@ -1043,22 +1043,22 @@ Fuzzy</comment>
|
||||
<value>Are you sure you want to delete this background image?</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>Copy link</value>
|
||||
<value>复制链接</value>
|
||||
</data>
|
||||
<data name="SearchWithRegex.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Regex</value>
|
||||
<value>正则表达式</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>
|
||||
<value>大小写敏感</value>
|
||||
</data>
|
||||
<data name="MouseCopySelectionOrPaste.Content" xml:space="preserve">
|
||||
<value>Copy selection or paste</value>
|
||||
@@ -1066,4 +1066,10 @@ Fuzzy</comment>
|
||||
<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>
|
||||
@@ -1046,4 +1046,10 @@
|
||||
<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>
|
||||
@@ -124,5 +124,34 @@
|
||||
</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>
|
||||
@@ -224,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;
|
||||
@@ -255,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
|
||||
@@ -274,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;
|
||||
}
|
||||
|
||||
@@ -562,5 +561,25 @@ namespace FluentTerminal.App.Views
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
SwitchToTerm7,
|
||||
SwitchToTerm8,
|
||||
SwitchToTerm9,
|
||||
DuplicateTab
|
||||
DuplicateTab,
|
||||
ReconnectTab
|
||||
}
|
||||
}
|
||||
@@ -1,643 +0,0 @@
|
||||
#
|
||||
# Install.ps1 is a PowerShell script designed to sideload the Fluent Terminal
|
||||
# app. To run this script from Explorer, right-click on its icon and choose
|
||||
# "Run with PowerShell".
|
||||
#
|
||||
# It is heavily based on the Add-AppxDevPackage.ps1 script generated by
|
||||
# Visual Studio. Visual Studio supplies this script in the folder generated
|
||||
# with its "Prepare Package" command. The same folder will also contain the
|
||||
# app package (a .appx file), the signing certificate (a .cer file), and a
|
||||
# "Dependencies" subfolder containing all the framework packages used by the
|
||||
# app.
|
||||
#
|
||||
# This script simplifies installing these packages by automating the
|
||||
# following functions:
|
||||
# 1. Find the app package and signing certificate in the script directory
|
||||
# 2. Prompt the user to enable sideloading apps and to install the
|
||||
# certificate if necessary
|
||||
# 3. Find dependency packages that are applicable to the operating system's
|
||||
# CPU architecture
|
||||
# 4. Install the package along with all applicable dependencies
|
||||
#
|
||||
# All command line parameters are reserved for use internally by the script.
|
||||
# Users should launch this script from Explorer.
|
||||
#
|
||||
|
||||
# .Link
|
||||
# http://go.microsoft.com/fwlink/?LinkId=243053
|
||||
|
||||
param(
|
||||
[switch]$Force = $false,
|
||||
[switch]$ForceContextMenu = $false,
|
||||
[switch]$GetDeveloperLicense = $false,
|
||||
[string]$CertificatePath = $null
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# UI Strings
|
||||
class UiStrings
|
||||
{
|
||||
static [string] $PromptYesString = "&Yes"
|
||||
static [string] $PromptNoString = "&No"
|
||||
static [string] $BundleFound = "Found bundle: {0}"
|
||||
static [string] $PackageFound = "Found package: {0}"
|
||||
static [string] $CertificateFound = "Found certificate: {0}"
|
||||
static [string] $DependenciesFound = "Found dependency package(s):"
|
||||
static [string] $GettingDeveloperLicense = "Please select `"Sideload apps`" or `"Developer mode`" in the following window."
|
||||
static [string] $InstallingCertificate = "Installing certificate..."
|
||||
static [string] $InstallingPackage = "`nInstalling app..."
|
||||
static [string] $AcquireLicenseSuccessful = "Sideloading was successfully enabled."
|
||||
static [string] $InstallCertificateSuccessful = "The certificate was successfully installed."
|
||||
static [string] $PromptContextMenuInstall = "Fluent Terminal can be integrated into the Windows Explorer context menu, allowing you to quickly open the terminal to a directory.`n`nDo you want to enable this integration?`n`n"
|
||||
static [string] $Success = "`nSuccess: Your app was successfully installed."
|
||||
static [string] $WarningInstallCert = "`nYou are about to install a digital certificate to your computer's Trusted People certificate store. Doing so carries serious security risk and should only be done if you trust the originator of this digital certificate.`n`nWhen you are done using this app, you should manually remove the associated digital certificate. Instructions for doing so can be found here: http://go.microsoft.com/fwlink/?LinkId=243053`n`nAre you sure you wish to continue?`n`n"
|
||||
static [string] $ElevateActions = "`nBefore installing this app, you need to do the following:"
|
||||
static [string] $ElevateActionDevLicense = "`t- Enable sideloading apps"
|
||||
static [string] $ElevateActionCertificate = "`t- Install the signing certificate"
|
||||
static [string] $ElevateActionsContinue = "Administrator credentials are required to continue. Please accept the UAC prompt and provide your administrator password if asked."
|
||||
static [string] $ErrorForceElevate = "You must provide administrator credentials to proceed. Please run this script without the -Force parameter or from an elevated PowerShell window."
|
||||
static [string] $ErrorForceDeveloperLicense = "Enabling sideloading requires user interaction. Please rerun the script without the -Force parameter."
|
||||
static [string] $ErrorLaunchAdminFailed = "Error: Could not start a new process as administrator."
|
||||
static [string] $ErrorNoScriptPath = "Error: You must launch this script from a file."
|
||||
static [string] $ErrorNoPackageFound = "Error: No package or bundle found in the script directory. Please make sure the package or bundle you want to install is placed in the same directory as this script."
|
||||
static [string] $ErrorManyPackagesFound = "Error: More than one package or bundle found in the script directory. Please make sure only the package or bundle you want to install is placed in the same directory as this script."
|
||||
static [string] $ErrorPackageUnsigned = "Error: The package or bundle is not digitally signed or its signature is corrupted."
|
||||
static [string] $ErrorNoCertificateFound = "Error: No certificate found in the script directory. Please make sure the certificate used to sign the package or bundle you are installing is placed in the same directory as this script."
|
||||
static [string] $ErrorManyCertificatesFound = "Error: More than one certificate found in the script directory. Please make sure only the certificate used to sign the package or bundle you are installing is placed in the same directory as this script."
|
||||
static [string] $ErrorBadCertificate = "Error: The file `"{0}`" is not a valid digital certificate. CertUtil returned with error code {1}."
|
||||
static [string] $ErrorExpiredCertificate = "Error: The developer certificate `"{0}`" has expired. One possible cause is the system clock isn't set to the correct date and time. If the system settings are correct, contact the app owner to re-create a package or bundle with a valid certificate."
|
||||
static [string] $ErrorCertificateMismatch = "Error: The certificate does not match the one used to sign the package or bundle."
|
||||
static [string] $ErrorCertIsCA = "Error: The certificate can't be a certificate authority."
|
||||
static [string] $ErrorBannedKeyUsage = "Error: The certificate can't have the following key usage: {0}. Key usage must be unspecified or equal to `"DigitalSignature`"."
|
||||
static [string] $ErrorBannedEKU = "Error: The certificate can't have the following extended key usage: {0}. Only the Code Signing and Lifetime Signing EKUs are allowed."
|
||||
static [string] $ErrorNoBasicConstraints = "Error: The certificate is missing the basic constraints extension."
|
||||
static [string] $ErrorNoCodeSigningEku = "Error: The certificate is missing the extended key usage for Code Signing."
|
||||
static [string] $ErrorInstallCertificateCancelled = "Error: Installation of the certificate was cancelled."
|
||||
static [string] $ErrorCertUtilInstallFailed = "Error: Could not install the certificate. CertUtil returned with error code {0}."
|
||||
static [string] $ErrorGetDeveloperLicenseFailed = "Error: Sideloading is not enabled."
|
||||
static [string] $ErrorInstallCertificateFailed = "Error: Could not install the certificate. Status: {0}. For more information, see http://go.microsoft.com/fwlink/?LinkID=252740."
|
||||
static [string] $ErrorAddPackageFailed = "Error: Could not install the app."
|
||||
static [string] $ErrorAddPackageFailedWithCert = "Error: Could not install the app. To ensure security, please consider uninstalling the signing certificate until you can install the app. Instructions for doing so can be found here:`nhttp://go.microsoft.com/fwlink/?LinkId=243053}"
|
||||
}
|
||||
|
||||
$ScriptPath = $null
|
||||
try
|
||||
{
|
||||
$ScriptPath = (Get-Variable MyInvocation).Value.MyCommand.Path
|
||||
$ScriptDir = Split-Path -Parent $ScriptPath
|
||||
}
|
||||
catch {}
|
||||
|
||||
if (!$ScriptPath)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorNoScriptPath) $ErrorCodes.NoScriptPath
|
||||
}
|
||||
|
||||
$ErrorCodes = Data {
|
||||
ConvertFrom-StringData @'
|
||||
Success = 0
|
||||
NoScriptPath = 1
|
||||
NoPackageFound = 2
|
||||
ManyPackagesFound = 3
|
||||
NoCertificateFound = 4
|
||||
ManyCertificatesFound = 5
|
||||
BadCertificate = 6
|
||||
PackageUnsigned = 7
|
||||
CertificateMismatch = 8
|
||||
ForceElevate = 9
|
||||
LaunchAdminFailed = 10
|
||||
GetDeveloperLicenseFailed = 11
|
||||
InstallCertificateFailed = 12
|
||||
AddPackageFailed = 13
|
||||
ForceDeveloperLicense = 14
|
||||
CertUtilInstallFailed = 17
|
||||
CertIsCA = 18
|
||||
BannedEKU = 19
|
||||
NoBasicConstraints = 20
|
||||
NoCodeSigningEku = 21
|
||||
InstallCertificateCancelled = 22
|
||||
BannedKeyUsage = 23
|
||||
ExpiredCertificate = 24
|
||||
'@
|
||||
}
|
||||
|
||||
function PrintMessageAndExit($ErrorMessage, $ReturnCode)
|
||||
{
|
||||
Write-Host $ErrorMessage
|
||||
if (!$Force)
|
||||
{
|
||||
Pause
|
||||
}
|
||||
exit $ReturnCode
|
||||
}
|
||||
|
||||
#
|
||||
# Warns the user about installing certificates, and presents a Yes/No prompt
|
||||
# to confirm the action. The default is set to No.
|
||||
#
|
||||
function ConfirmCertificateInstall
|
||||
{
|
||||
$Answer = $host.UI.PromptForChoice(
|
||||
"",
|
||||
([UiStrings]::WarningInstallCert),
|
||||
[System.Management.Automation.Host.ChoiceDescription[]]@(([UiStrings]::PromptYesString), ([UiStrings]::PromptNoString)),
|
||||
1)
|
||||
|
||||
return $Answer -eq 0
|
||||
}
|
||||
|
||||
#
|
||||
# Asks the user whether they want to install context menu integration for Fluent Terminal,
|
||||
# and presents a Yes/No prompt to confirm the action. The default is set to No.
|
||||
#
|
||||
function ConfirmContextMenuInstall
|
||||
{
|
||||
$Answer = $host.UI.PromptForChoice(
|
||||
"",
|
||||
([UiStrings]::PromptContextMenuInstall),
|
||||
[System.Management.Automation.Host.ChoiceDescription[]]@(([UiStrings]::PromptYesString), ([UiStrings]::PromptNoString)),
|
||||
1)
|
||||
|
||||
return $Answer -eq 0
|
||||
}
|
||||
|
||||
#
|
||||
# Validates whether a file is a valid certificate using CertUtil.
|
||||
# This needs to be done before calling Get-PfxCertificate on the file, otherwise
|
||||
# the user will get a cryptic "Password: " prompt for invalid certs.
|
||||
#
|
||||
function ValidateCertificateFormat($FilePath)
|
||||
{
|
||||
# certutil -verify prints a lot of text that we don't need, so it's redirected to $null here
|
||||
certutil.exe -verify $FilePath > $null
|
||||
if ($LastExitCode -lt 0)
|
||||
{
|
||||
PrintMessageAndExit (([UiStrings]::ErrorBadCertificate) -f $FilePath, $LastExitCode) $ErrorCodes.BadCertificate
|
||||
}
|
||||
|
||||
# Check if certificate is expired
|
||||
$cert = Get-PfxCertificate $FilePath
|
||||
if (($cert.NotBefore -gt (Get-Date)) -or ($cert.NotAfter -lt (Get-Date)))
|
||||
{
|
||||
PrintMessageAndExit (([UiStrings]::ErrorExpiredCertificate) -f $FilePath) $ErrorCodes.ExpiredCertificate
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Verify that the developer certificate meets the following restrictions:
|
||||
# - The certificate must contain a Basic Constraints extension, and its
|
||||
# Certificate Authority (CA) property must be false.
|
||||
# - The certificate's Key Usage extension must be either absent, or set to
|
||||
# only DigitalSignature.
|
||||
# - The certificate must contain an Extended Key Usage (EKU) extension with
|
||||
# Code Signing usage.
|
||||
# - The certificate must NOT contain any other EKU except Code Signing and
|
||||
# Lifetime Signing.
|
||||
#
|
||||
# These restrictions are enforced to decrease security risks that arise from
|
||||
# trusting digital certificates.
|
||||
#
|
||||
function CheckCertificateRestrictions
|
||||
{
|
||||
Set-Variable -Name BasicConstraintsExtensionOid -Value "2.5.29.19" -Option Constant
|
||||
Set-Variable -Name KeyUsageExtensionOid -Value "2.5.29.15" -Option Constant
|
||||
Set-Variable -Name EkuExtensionOid -Value "2.5.29.37" -Option Constant
|
||||
Set-Variable -Name CodeSigningEkuOid -Value "1.3.6.1.5.5.7.3.3" -Option Constant
|
||||
Set-Variable -Name LifetimeSigningEkuOid -Value "1.3.6.1.4.1.311.10.3.13" -Option Constant
|
||||
|
||||
$CertificateExtensions = (Get-PfxCertificate $CertificatePath).Extensions
|
||||
$HasBasicConstraints = $false
|
||||
$HasCodeSigningEku = $false
|
||||
|
||||
foreach ($Extension in $CertificateExtensions)
|
||||
{
|
||||
# Certificate must contain the Basic Constraints extension
|
||||
if ($Extension.oid.value -eq $BasicConstraintsExtensionOid)
|
||||
{
|
||||
# CA property must be false
|
||||
if ($Extension.CertificateAuthority)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorCertIsCA) $ErrorCodes.CertIsCA
|
||||
}
|
||||
$HasBasicConstraints = $true
|
||||
}
|
||||
|
||||
# If key usage is present, it must be set to digital signature
|
||||
elseif ($Extension.oid.value -eq $KeyUsageExtensionOid)
|
||||
{
|
||||
if ($Extension.KeyUsages -ne "DigitalSignature")
|
||||
{
|
||||
PrintMessageAndExit (([UiStrings]::ErrorBannedKeyUsage) -f $Extension.KeyUsages) $ErrorCodes.BannedKeyUsage
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($Extension.oid.value -eq $EkuExtensionOid)
|
||||
{
|
||||
# Certificate must contain the Code Signing EKU
|
||||
$EKUs = $Extension.EnhancedKeyUsages.Value
|
||||
if ($EKUs -contains $CodeSigningEkuOid)
|
||||
{
|
||||
$HasCodeSigningEKU = $True
|
||||
}
|
||||
|
||||
# EKUs other than code signing and lifetime signing are not allowed
|
||||
foreach ($EKU in $EKUs)
|
||||
{
|
||||
if ($EKU -ne $CodeSigningEkuOid -and $EKU -ne $LifetimeSigningEkuOid)
|
||||
{
|
||||
PrintMessageAndExit (([UiStrings]::ErrorBannedEKU) -f $EKU) $ErrorCodes.BannedEKU
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$HasBasicConstraints)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorNoBasicConstraints) $ErrorCodes.NoBasicConstraints
|
||||
}
|
||||
if (!$HasCodeSigningEKU)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorNoCodeSigningEku) $ErrorCodes.NoCodeSigningEku
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Performs operations that require administrative privileges:
|
||||
# - Prompt the user to obtain a developer license
|
||||
# - Install the developer certificate (if -Force is not specified, also prompts the user to confirm)
|
||||
#
|
||||
function DoElevatedOperations
|
||||
{
|
||||
if ($GetDeveloperLicense)
|
||||
{
|
||||
if ($Force)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorForceDeveloperLicense) $ErrorCodes.ForceDeveloperLicense
|
||||
}
|
||||
|
||||
Write-Host ([UiStrings]::GettingDeveloperLicense)
|
||||
Pause
|
||||
|
||||
try
|
||||
{
|
||||
Show-WindowsDeveloperLicenseRegistration
|
||||
Pause
|
||||
}
|
||||
catch
|
||||
{
|
||||
$Error[0] # Dump details about the last error
|
||||
PrintMessageAndExit ([UiStrings]::ErrorGetDeveloperLicenseFailed) $ErrorCodes.GetDeveloperLicenseFailed
|
||||
}
|
||||
}
|
||||
|
||||
if ($CertificatePath)
|
||||
{
|
||||
Write-Host ([UiStrings]::InstallingCertificate)
|
||||
|
||||
# Make sure certificate format is valid and usage constraints are followed
|
||||
ValidateCertificateFormat $CertificatePath
|
||||
CheckCertificateRestrictions
|
||||
|
||||
# If -Force is not specified, warn the user and get consent
|
||||
if ($Force -or (ConfirmCertificateInstall))
|
||||
{
|
||||
# Add cert to store
|
||||
certutil.exe -addstore TrustedPeople $CertificatePath
|
||||
if ($LastExitCode -lt 0)
|
||||
{
|
||||
PrintMessageAndExit (([UiStrings]::ErrorCertUtilInstallFailed) -f $LastExitCode) $ErrorCodes.CertUtilInstallFailed
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorInstallCertificateCancelled) $ErrorCodes.InstallCertificateCancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Checks whether the machine has app sideloading enabled.
|
||||
#
|
||||
function CheckIfNeedToEnableSideloading
|
||||
{
|
||||
$RegistryPath = "hklm:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
||||
$ValueName = "AllowAllTrustedApps"
|
||||
|
||||
$Result = $true
|
||||
if (Test-Path $RegistryPath)
|
||||
{
|
||||
$SideloadingEnabledProperty = (Get-ItemProperty -Path $RegistryPath -Name $ValueName -ErrorAction SilentlyContinue)
|
||||
if ($null -ne $SideloadingEnabledProperty -and $SideloadingEnabledProperty.$ValueName -eq 1)
|
||||
{
|
||||
$Result = $false
|
||||
}
|
||||
}
|
||||
|
||||
return $Result
|
||||
}
|
||||
|
||||
#
|
||||
# Launches an elevated process running the current script to perform tasks
|
||||
# that require administrative privileges. This function waits until the
|
||||
# elevated process terminates, and checks whether those tasks were successful.
|
||||
#
|
||||
function LaunchElevated
|
||||
{
|
||||
# Set up command line arguments to the elevated process
|
||||
$RelaunchArgs = '-ExecutionPolicy Unrestricted -file "' + $ScriptPath + '"'
|
||||
|
||||
if ($Force)
|
||||
{
|
||||
$RelaunchArgs += ' -Force'
|
||||
}
|
||||
if ($NeedDeveloperLicense)
|
||||
{
|
||||
$RelaunchArgs += ' -GetDeveloperLicense'
|
||||
}
|
||||
if ($NeedInstallCertificate)
|
||||
{
|
||||
$RelaunchArgs += ' -CertificatePath "' + $DeveloperCertificatePath.FullName + '"'
|
||||
}
|
||||
|
||||
# Launch the process and wait for it to finish
|
||||
try
|
||||
{
|
||||
$AdminProcess = Start-Process "$PsHome\PowerShell.exe" -Verb RunAs -ArgumentList $RelaunchArgs -PassThru
|
||||
}
|
||||
catch
|
||||
{
|
||||
$Error[0] # Dump details about the last error
|
||||
PrintMessageAndExit ([UiStrings]::ErrorLaunchAdminFailed) $ErrorCodes.LaunchAdminFailed
|
||||
}
|
||||
|
||||
while (!($AdminProcess.HasExited))
|
||||
{
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
|
||||
# Check if all elevated operations were successful
|
||||
if ($NeedDeveloperLicense)
|
||||
{
|
||||
if (CheckIfNeedToEnableSideloading)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorGetDeveloperLicenseFailed) $ErrorCodes.GetDeveloperLicenseFailed
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host ([UiStrings]::AcquireLicenseSuccessful)
|
||||
}
|
||||
}
|
||||
if ($NeedInstallCertificate)
|
||||
{
|
||||
$Signature = Get-AuthenticodeSignature $DeveloperPackagePath -Verbose
|
||||
if ($Signature.Status -ne "Valid")
|
||||
{
|
||||
PrintMessageAndExit (([UiStrings]::ErrorInstallCertificateFailed) -f $Signature.Status) $ErrorCodes.InstallCertificateFailed
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host ([UiStrings]::InstallCertificateSuccessful)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Finds all applicable dependency packages according to OS architecture, and
|
||||
# installs the developer package with its dependencies. The expected layout
|
||||
# of dependencies is:
|
||||
#
|
||||
# <current dir>
|
||||
# \Dependencies
|
||||
# <Architecture neutral dependencies>.appx
|
||||
# \x86
|
||||
# <x86 dependencies>.appx
|
||||
# \x64
|
||||
# <x64 dependencies>.appx
|
||||
# \arm
|
||||
# <arm dependencies>.appx
|
||||
#
|
||||
function InstallPackageWithDependencies
|
||||
{
|
||||
$DependencyPackagesDir = (Join-Path $ScriptDir "Dependencies")
|
||||
$DependencyPackages = @()
|
||||
if (Test-Path $DependencyPackagesDir)
|
||||
{
|
||||
# Get architecture-neutral dependencies
|
||||
$DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
|
||||
|
||||
# Get architecture-specific dependencies
|
||||
if (($Env:Processor_Architecture -eq "x86" -or $Env:Processor_Architecture -eq "amd64") -and (Test-Path (Join-Path $DependencyPackagesDir "x86")))
|
||||
{
|
||||
$DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x86\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
|
||||
}
|
||||
if (($Env:Processor_Architecture -eq "amd64") -and (Test-Path (Join-Path $DependencyPackagesDir "x64")))
|
||||
{
|
||||
$DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x64\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
|
||||
}
|
||||
if (($Env:Processor_Architecture -eq "arm") -and (Test-Path (Join-Path $DependencyPackagesDir "arm")))
|
||||
{
|
||||
$DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
|
||||
}
|
||||
}
|
||||
Write-Host ([UiStrings]::InstallingPackage)
|
||||
|
||||
$AddPackageSucceeded = $False
|
||||
try
|
||||
{
|
||||
if ($DependencyPackages.FullName.Count -gt 0)
|
||||
{
|
||||
Write-Host ([UiStrings]::DependenciesFound)
|
||||
$DependencyPackages.FullName
|
||||
Add-AppxPackage -Path $DeveloperPackagePath.FullName -DependencyPath $DependencyPackages.FullName -ForceApplicationShutdown -ForceUpdateFromAnyVersion
|
||||
}
|
||||
else
|
||||
{
|
||||
Add-AppxPackage -Path $DeveloperPackagePath.FullName -ForceApplicationShutdown -ForceUpdateFromAnyVersion
|
||||
}
|
||||
$AddPackageSucceeded = $?
|
||||
}
|
||||
catch
|
||||
{
|
||||
$Error[0] # Dump details about the last error
|
||||
}
|
||||
|
||||
if (!$AddPackageSucceeded)
|
||||
{
|
||||
if ($NeedInstallCertificate)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorAddPackageFailedWithCert) $ErrorCodes.AddPackageFailed
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorAddPackageFailed) $ErrorCodes.AddPackageFailed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Adds a regkey with the specified value, creating any missing keys as needed.
|
||||
#
|
||||
function ForceAddRegKeyValue($RegistryPath, $Name, $Type, $Value)
|
||||
{
|
||||
if (!(Test-Path $RegistryPath))
|
||||
{
|
||||
New-Item -Path $RegistryPath -Force | Out-Null
|
||||
}
|
||||
|
||||
New-ItemProperty -Path $RegistryPath -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null
|
||||
}
|
||||
|
||||
#
|
||||
# Adds the needed regkeys to enable Explorer context menu integration.
|
||||
#
|
||||
function InstallContextMenuIntegration
|
||||
{
|
||||
ForceAddRegKeyValue `
|
||||
-RegistryPath "hkcu:\Software\Classes\Directory\shell\Open Fluent Terminal here\command"`
|
||||
-Name "(Default)"`
|
||||
-Type "ExpandString"`
|
||||
-Value "`"%LOCALAPPDATA%\Microsoft\WindowsApps\flute.exe`" new `"%1`""
|
||||
|
||||
ForceAddRegKeyValue `
|
||||
-RegistryPath "hkcu:\Software\Classes\Directory\Background\shell\Open Fluent Terminal here\command"`
|
||||
-Name "(Default)"`
|
||||
-Type "ExpandString"`
|
||||
-Value "`"%LOCALAPPDATA%\Microsoft\WindowsApps\flute.exe`" new `"%V`""
|
||||
|
||||
ForceAddRegKeyValue `
|
||||
-RegistryPath "hkcu:\Software\Classes\Directory\LibraryFolder\shell\Open Fluent Terminal here\command"`
|
||||
-Name "(Default)"`
|
||||
-Type "ExpandString"`
|
||||
-Value "`"%LOCALAPPDATA%\Microsoft\WindowsApps\flute.exe`" new `"%V`""
|
||||
}
|
||||
|
||||
#
|
||||
# Main script logic when the user launches the script without parameters.
|
||||
#
|
||||
function DoStandardOperations
|
||||
{
|
||||
# List all .appxbundle files in the script directory
|
||||
$BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.appxbundle") | Where-Object { $_.Mode -NotMatch "d" }
|
||||
$BundleCount = ($BundlePath | Measure-Object).Count
|
||||
|
||||
# There must be exactly one bundle
|
||||
if ($BundleCount -lt 1)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorNoPackageFound) $ErrorCodes.NoPackageFound
|
||||
}
|
||||
elseif ($BundleCount -gt 1)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorManyPackagesFound) $ErrorCodes.ManyPackagesFound
|
||||
}
|
||||
|
||||
# First attempt to install a bundle.
|
||||
if ($BundleCount -eq 1)
|
||||
{
|
||||
$DeveloperPackagePath = $BundlePath
|
||||
Write-Host (([UiStrings]::BundleFound) -f $DeveloperPackagePath.FullName)
|
||||
}
|
||||
|
||||
# The package must be signed
|
||||
$PackageSignature = Get-AuthenticodeSignature $DeveloperPackagePath
|
||||
$PackageCertificate = $PackageSignature.SignerCertificate
|
||||
if (!$PackageCertificate)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorPackageUnsigned) $ErrorCodes.PackageUnsigned
|
||||
}
|
||||
|
||||
# Test if the package signature is trusted. If not, the corresponding certificate
|
||||
# needs to be present in the current directory and needs to be installed.
|
||||
$NeedInstallCertificate = ($PackageSignature.Status -ne "Valid")
|
||||
|
||||
if ($NeedInstallCertificate)
|
||||
{
|
||||
# List all .cer files in the script directory
|
||||
$DeveloperCertificatePath = Get-ChildItem (Join-Path $ScriptDir "*.cer") | Where-Object { $_.Mode -NotMatch "d" }
|
||||
$DeveloperCertificateCount = ($DeveloperCertificatePath | Measure-Object).Count
|
||||
|
||||
# There must be exactly 1 certificate
|
||||
if ($DeveloperCertificateCount -lt 1)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorNoCertificateFound) $ErrorCodes.NoCertificateFound
|
||||
}
|
||||
elseif ($DeveloperCertificateCount -gt 1)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorManyCertificatesFound) $ErrorCodes.ManyCertificatesFound
|
||||
}
|
||||
|
||||
Write-Host (([UiStrings]::CertificateFound) -f $DeveloperCertificatePath.FullName)
|
||||
|
||||
# The .cer file must have the format of a valid certificate
|
||||
ValidateCertificateFormat $DeveloperCertificatePath
|
||||
|
||||
# The package signature must match the certificate file
|
||||
if ($PackageCertificate -ne (Get-PfxCertificate $DeveloperCertificatePath))
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorCertificateMismatch) $ErrorCodes.CertificateMismatch
|
||||
}
|
||||
}
|
||||
|
||||
$NeedDeveloperLicense = CheckIfNeedToEnableSideloading
|
||||
|
||||
# Relaunch the script elevated with the necessary parameters if needed
|
||||
if ($NeedDeveloperLicense -or $NeedInstallCertificate)
|
||||
{
|
||||
Write-Host ([UiStrings]::ElevateActions)
|
||||
if ($NeedDeveloperLicense)
|
||||
{
|
||||
Write-Host ([UiStrings]::ElevateActionDevLicense)
|
||||
}
|
||||
if ($NeedInstallCertificate)
|
||||
{
|
||||
Write-Host ([UiStrings]::ElevateActionCertificate)
|
||||
}
|
||||
|
||||
$IsAlreadyElevated = ([Security.Principal.WindowsIdentity]::GetCurrent().Groups.Value -contains "S-1-5-32-544")
|
||||
if ($IsAlreadyElevated)
|
||||
{
|
||||
if ($Force -and $NeedDeveloperLicense)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorForceDeveloperLicense) $ErrorCodes.ForceDeveloperLicense
|
||||
}
|
||||
if ($Force -and $NeedInstallCertificate)
|
||||
{
|
||||
Write-Warning ([UiStrings]::WarningInstallCert)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($Force)
|
||||
{
|
||||
PrintMessageAndExit ([UiStrings]::ErrorForceElevate) $ErrorCodes.ForceElevate
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host ([UiStrings]::ElevateActionsContinue)
|
||||
Pause
|
||||
}
|
||||
}
|
||||
|
||||
LaunchElevated
|
||||
}
|
||||
|
||||
InstallPackageWithDependencies
|
||||
|
||||
if ($ForceContextMenu -or (ConfirmContextMenuInstall))
|
||||
{
|
||||
InstallContextMenuIntegration
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Main script entry point
|
||||
#
|
||||
if ($GetDeveloperLicense -or $CertificatePath)
|
||||
{
|
||||
DoElevatedOperations
|
||||
}
|
||||
else
|
||||
{
|
||||
DoStandardOperations
|
||||
PrintMessageAndExit ([UiStrings]::Success) $ErrorCodes.Success
|
||||
}
|
||||
@@ -28,35 +28,35 @@ A Terminal Emulator based on UWP and web technologies.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Languages
|
||||
- English
|
||||
- German
|
||||
- Spanish
|
||||
- French
|
||||
- Simplified Chinese
|
||||
- Hindi
|
||||
- Italian
|
||||
- Arabic
|
||||
- Arabic (Iraq)
|
||||
- Azerbaijani
|
||||
- Chinese (Simplified)
|
||||
- Chinese (Traditional)
|
||||
- Dutch
|
||||
- English
|
||||
- French
|
||||
- German
|
||||
- Hebrew
|
||||
- Hindi
|
||||
- Indonesian
|
||||
- Italian
|
||||
- Japanese
|
||||
- Korean
|
||||
- Polish
|
||||
- Portuguese (Brazilian)
|
||||
- Romanian
|
||||
- Russians
|
||||
- Hebrew
|
||||
- Russian
|
||||
- Spanish
|
||||
- Ukrainian
|
||||
|
||||
|
||||
Sign up to [POEditor](https://poeditor.com/join/project/TfKNIt826z) to help with existing translations or add a new language
|
||||
|
||||
|
||||
|
||||
## Up Next
|
||||
|
||||
- ~~Launch shell profile with a custom defined keybinding~~
|
||||
- Copy & Paste options
|
||||
- Improved tabs
|
||||
- Split screen support
|
||||
|
||||
## How to install (as an end-user)
|
||||
|
||||
### Prerequisite
|
||||
@@ -78,27 +78,10 @@ Sign up to [POEditor](https://poeditor.com/join/project/TfKNIt826z) to help with
|
||||
scoop install fluent-terminal-np
|
||||
```
|
||||
|
||||
### Bundled install script
|
||||
### Manual
|
||||
|
||||
- Download and extract the latest [release](https://github.com/felixse/FluentTerminal/releases).
|
||||
- If not already present, download [`Install.ps1`](Install.ps1) to the extracted directory.
|
||||
- Right-click on `Install.ps1`, and choose "Run with Powershell".
|
||||
- The installer script will walk you through the rest of the process.
|
||||
|
||||
### Manual install
|
||||
|
||||
- Download the latest [release](https://github.com/felixse/FluentTerminal/releases)
|
||||
- [Enable sideloading apps](https://www.windowscentral.com/how-enable-windows-10-sideload-apps-outside-store)
|
||||
- Alternatively, [enable developer mode](https://docs.microsoft.com/en-US/windows/uwp/get-started/enable-your-device-for-development) if you plan to do UWP app development. **For most users that do not intend to do UWP app development, developer mode will not be necessary.**
|
||||
- Install the *.cer file into `Local Machine` -> `Trusted Root Certification Authorities`
|
||||
- This will require administrator elevation. If you installed the certificate and did not have to elevate, you likely installed it into an incorrect certificate store.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- double click the *.appxbundle
|
||||
- **Optional:** Install Context menu integration from [here](https://github.com/felixse/FluentTerminal/tree/master/Explorer%20Context%20Menu%20Integration)
|
||||
- Double click the *.appxbundle file.
|
||||
|
||||
## How to set up a development environment
|
||||
Please refer to [this Wiki page](https://github.com/felixse/FluentTerminal/wiki/How-to-set-up-a-development-environment)
|
||||
|
Before Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 277 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 385 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 201 KiB |