From fcac52a84417a4b7f6cb42dc8589ab0351f4873c Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Sat, 15 Jul 2023 12:17:47 +0200 Subject: [PATCH] fixed #5862 - configurable Backspace behaviour --- tabby-serial/src/api.ts | 4 +- .../serialProfileSettings.component.pug | 5 +++ tabby-serial/src/profiles.ts | 1 + tabby-ssh/src/api/interfaces.ts | 3 +- .../sshProfileSettings.component.pug | 5 +++ tabby-ssh/src/profiles.ts | 1 + tabby-ssh/src/session/shell.ts | 3 +- .../telnetProfileSettings.component.pug | 5 +++ tabby-telnet/src/profiles.ts | 1 + tabby-telnet/src/session.ts | 4 +- .../inputProcessingSettings.component.pug | 9 +++++ .../inputProcessingSettings.component.ts | 40 +++++++++++++++++++ tabby-terminal/src/index.ts | 4 ++ .../src/middleware/inputProcessing.ts | 28 +++++++++++++ .../src/middleware/loginScriptProcessing.ts | 5 --- 15 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 tabby-terminal/src/components/inputProcessingSettings.component.pug create mode 100644 tabby-terminal/src/components/inputProcessingSettings.component.ts create mode 100644 tabby-terminal/src/middleware/inputProcessing.ts diff --git a/tabby-serial/src/api.ts b/tabby-serial/src/api.ts index ccd4c89bf3..64d46e681d 100644 --- a/tabby-serial/src/api.ts +++ b/tabby-serial/src/api.ts @@ -3,7 +3,7 @@ import { SerialPortStream } from '@serialport/stream' import { LogService, NotificationsService } from 'tabby-core' import { Subject, Observable } from 'rxjs' import { Injector, NgZone } from '@angular/core' -import { BaseSession, BaseTerminalProfile, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor, UTF8SplitterMiddleware } from 'tabby-terminal' +import { BaseSession, BaseTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor, UTF8SplitterMiddleware } from 'tabby-terminal' import { SerialService } from './services/serial.service' export interface SerialProfile extends BaseTerminalProfile { @@ -21,6 +21,7 @@ export interface SerialProfileOptions extends StreamProcessingOptions, LoginScri xoff?: boolean xany?: boolean slowSend?: boolean + input: InputProcessingOptions, } export const BAUD_RATES = [ @@ -65,6 +66,7 @@ export class SerialSession extends BaseSession { } this.middleware.push(new UTF8SplitterMiddleware()) + this.middleware.push(new InputProcessor(profile.options.input)) this.setLoginScriptsOptions(profile.options) } diff --git a/tabby-serial/src/components/serialProfileSettings.component.pug b/tabby-serial/src/components/serialProfileSettings.component.pug index ea92fb2d7d..9e3c4cde7d 100644 --- a/tabby-serial/src/components/serialProfileSettings.component.pug +++ b/tabby-serial/src/components/serialProfileSettings.component.pug @@ -92,4 +92,9 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ng-template(ngbNavContent) login-scripts-settings([options]='profile.options') + li(ngbNavItem) + a(ngbNavLink, translate) Input + ng-template(ngbNavContent) + input-processing-settings([options]='profile.options.input') + div([ngbNavOutlet]='nav') diff --git a/tabby-serial/src/profiles.ts b/tabby-serial/src/profiles.ts index 06f4f22881..c6c5d5bfbe 100644 --- a/tabby-serial/src/profiles.ts +++ b/tabby-serial/src/profiles.ts @@ -30,6 +30,7 @@ export class SerialProfilesService extends ProfileProvider { outputNewlines: null, scripts: [], slowSend: false, + input: { backspace: 'backspace' }, }, } diff --git a/tabby-ssh/src/api/interfaces.ts b/tabby-ssh/src/api/interfaces.ts index 1f00b49e25..901d5dd11f 100644 --- a/tabby-ssh/src/api/interfaces.ts +++ b/tabby-ssh/src/api/interfaces.ts @@ -1,4 +1,4 @@ -import { BaseTerminalProfile, LoginScriptsOptions } from 'tabby-terminal' +import { BaseTerminalProfile, InputProcessingOptions, LoginScriptsOptions } from 'tabby-terminal' export enum SSHAlgorithmType { HMAC = 'hmac', @@ -34,6 +34,7 @@ export interface SSHProfileOptions extends LoginScriptsOptions { httpProxyHost?: string httpProxyPort?: number reuseSession?: boolean + input: InputProcessingOptions, } export enum PortForwardType { diff --git a/tabby-ssh/src/components/sshProfileSettings.component.pug b/tabby-ssh/src/components/sshProfileSettings.component.pug index c0f4b19fc1..4580ccc648 100644 --- a/tabby-ssh/src/components/sshProfileSettings.component.pug +++ b/tabby-ssh/src/components/sshProfileSettings.component.pug @@ -294,4 +294,9 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ng-template(ngbNavContent) login-scripts-settings([options]='profile.options', #loginScriptsSettings) + li(ngbNavItem) + a(ngbNavLink, translate) Input + ng-template(ngbNavContent) + input-processing-settings([options]='profile.options.input') + div([ngbNavOutlet]='nav') diff --git a/tabby-ssh/src/profiles.ts b/tabby-ssh/src/profiles.ts index d4b84299cf..0952e713c5 100644 --- a/tabby-ssh/src/profiles.ts +++ b/tabby-ssh/src/profiles.ts @@ -43,6 +43,7 @@ export class SSHProfilesService extends ProfileProvider { httpProxyHost: null, httpProxyPort: null, reuseSession: true, + input: { backspace: 'backspace' }, }, } diff --git a/tabby-ssh/src/session/shell.ts b/tabby-ssh/src/session/shell.ts index 29534f7835..5b942cad31 100644 --- a/tabby-ssh/src/session/shell.ts +++ b/tabby-ssh/src/session/shell.ts @@ -3,7 +3,7 @@ import stripAnsi from 'strip-ansi' import { ClientChannel } from 'ssh2' import { Injector } from '@angular/core' import { LogService } from 'tabby-core' -import { BaseSession, UTF8SplitterMiddleware } from 'tabby-terminal' +import { BaseSession, UTF8SplitterMiddleware, InputProcessor } from 'tabby-terminal' import { SSHSession } from './ssh' import { SSHProfile } from '../api' @@ -24,6 +24,7 @@ export class SSHShellSession extends BaseSession { this.setLoginScriptsOptions(this.profile.options) this.ssh.serviceMessage$.subscribe(m => this.serviceMessage.next(m)) this.middleware.push(new UTF8SplitterMiddleware()) + this.middleware.push(new InputProcessor(profile.options.input)) } async start (): Promise { diff --git a/tabby-telnet/src/components/telnetProfileSettings.component.pug b/tabby-telnet/src/components/telnetProfileSettings.component.pug index ad1ed1519a..b89137a421 100644 --- a/tabby-telnet/src/components/telnetProfileSettings.component.pug +++ b/tabby-telnet/src/components/telnetProfileSettings.component.pug @@ -24,4 +24,9 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') ng-template(ngbNavContent) login-scripts-settings([options]='profile.options') + li(ngbNavItem) + a(ngbNavLink, translate) Input + ng-template(ngbNavContent) + input-processing-settings([options]='profile.options.input') + div([ngbNavOutlet]='nav') diff --git a/tabby-telnet/src/profiles.ts b/tabby-telnet/src/profiles.ts index 772fe66855..6530771e3e 100644 --- a/tabby-telnet/src/profiles.ts +++ b/tabby-telnet/src/profiles.ts @@ -19,6 +19,7 @@ export class TelnetProfilesService extends ProfileProvider { inputNewlines: null, outputNewlines: 'crlf', scripts: [], + input: { backspace: 'backspace' }, }, } diff --git a/tabby-telnet/src/session.ts b/tabby-telnet/src/session.ts index e094032a29..27c2cc27ac 100644 --- a/tabby-telnet/src/session.ts +++ b/tabby-telnet/src/session.ts @@ -3,7 +3,7 @@ import colors from 'ansi-colors' import stripAnsi from 'strip-ansi' import { Injector } from '@angular/core' import { LogService } from 'tabby-core' -import { BaseSession, BaseTerminalProfile, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal' +import { BaseSession, BaseTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal' import { Subject, Observable } from 'rxjs' @@ -14,6 +14,7 @@ export interface TelnetProfile extends BaseTerminalProfile { export interface TelnetProfileOptions extends StreamProcessingOptions, LoginScriptsOptions { host: string port?: number + input: InputProcessingOptions, } enum TelnetCommands { @@ -75,6 +76,7 @@ export class TelnetSession extends BaseSession { super(injector.get(LogService).create(`telnet-${profile.options.host}-${profile.options.port}`)) this.streamProcessor = new TerminalStreamProcessor(profile.options) this.middleware.push(this.streamProcessor) + this.middleware.push(new InputProcessor(profile.options.input)) this.setLoginScriptsOptions(profile.options) } diff --git a/tabby-terminal/src/components/inputProcessingSettings.component.pug b/tabby-terminal/src/components/inputProcessingSettings.component.pug new file mode 100644 index 0000000000..e22373c93b --- /dev/null +++ b/tabby-terminal/src/components/inputProcessingSettings.component.pug @@ -0,0 +1,9 @@ +.form-line + .header + .title(translate) Backspace key mode + + select.form-control([(ngModel)]='options.backspace') + option( + *ngFor='let mode of backspaceModes', + [value]='mode.key', + ) {{mode.name|translate}} diff --git a/tabby-terminal/src/components/inputProcessingSettings.component.ts b/tabby-terminal/src/components/inputProcessingSettings.component.ts new file mode 100644 index 0000000000..c6f2451dcd --- /dev/null +++ b/tabby-terminal/src/components/inputProcessingSettings.component.ts @@ -0,0 +1,40 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' +import { Component, Input } from '@angular/core' +import { InputProcessingOptions } from '../middleware/inputProcessing' + +/** @hidden */ +@Component({ + selector: 'input-processing-settings', + templateUrl: './inputProcessingSettings.component.pug', +}) +export class InputProcessingSettingsComponent { + @Input() options: InputProcessingOptions + + backspaceModes = [ + { + key: 'backspace', + name: _('Pass-through'), + }, + { + key: 'ctrl-h', + name: 'Ctrl-H', + }, + { + key: 'ctrl-?', + name: 'Ctrl-?', + }, + { + key: 'delete', + name: 'Delete (CSI 3~)', + }, + ] + + getBackspaceModeName (key) { + return this.backspaceModes.find(x => x.key === key)?.name + } + + setBackspaceMode (mode) { + this.options.backspace = mode + } +} diff --git a/tabby-terminal/src/index.ts b/tabby-terminal/src/index.ts index 77cd82ed50..2ae09431b7 100644 --- a/tabby-terminal/src/index.ts +++ b/tabby-terminal/src/index.ts @@ -18,6 +18,7 @@ import { StreamProcessingSettingsComponent } from './components/streamProcessing import { LoginScriptsSettingsComponent } from './components/loginScriptsSettings.component' import { TerminalToolbarComponent } from './components/terminalToolbar.component' import { ColorSchemeSelectorComponent } from './components/colorSchemeSelector.component' +import { InputProcessingSettingsComponent } from './components/inputProcessingSettings.component' import { TerminalDecorator } from './api/decorator' import { TerminalContextMenuItemProvider } from './api/contextMenuProvider' @@ -76,6 +77,7 @@ import { DefaultColorSchemes } from './colorSchemes' StreamProcessingSettingsComponent, LoginScriptsSettingsComponent, TerminalToolbarComponent, + InputProcessingSettingsComponent, ], exports: [ ColorPickerComponent, @@ -84,6 +86,7 @@ import { DefaultColorSchemes } from './colorSchemes' StreamProcessingSettingsComponent, LoginScriptsSettingsComponent, TerminalToolbarComponent, + InputProcessingSettingsComponent, ], }) export default class TerminalModule { } // eslint-disable-line @typescript-eslint/no-extraneous-class @@ -97,6 +100,7 @@ export * from './middleware/streamProcessing' export * from './middleware/loginScriptProcessing' export * from './middleware/oscProcessing' export * from './middleware/utf8Splitter' +export * from './middleware/inputProcessing' export * from './api/middleware' export * from './session' export { LoginScriptsSettingsComponent, StreamProcessingSettingsComponent } diff --git a/tabby-terminal/src/middleware/inputProcessing.ts b/tabby-terminal/src/middleware/inputProcessing.ts new file mode 100644 index 0000000000..529af88722 --- /dev/null +++ b/tabby-terminal/src/middleware/inputProcessing.ts @@ -0,0 +1,28 @@ +import { SessionMiddleware } from '../api/middleware' + +export interface InputProcessingOptions { + backspace: 'ctrl-h'|'ctrl-?'|'delete'|'backspace' +} + +export class InputProcessor extends SessionMiddleware { + constructor ( + private options: InputProcessingOptions, + ) { + super() + } + + feedFromTerminal (data: Buffer): void { + if (data.length === 1 && data[0] === 0x7f) { + if (this.options.backspace === 'ctrl-h') { + data = Buffer.from('\x08') + } else if (this.options.backspace === 'ctrl-?') { + data = Buffer.from('\x7f') + } else if (this.options.backspace === 'delete') { + data = Buffer.from('\x1b[3~') + } else { + data = Buffer.from('\x7f') + } + } + this.outputToSession.next(data) + } +} diff --git a/tabby-terminal/src/middleware/loginScriptProcessing.ts b/tabby-terminal/src/middleware/loginScriptProcessing.ts index 27db681850..549129eb6f 100644 --- a/tabby-terminal/src/middleware/loginScriptProcessing.ts +++ b/tabby-terminal/src/middleware/loginScriptProcessing.ts @@ -73,11 +73,6 @@ export class LoginScriptProcessor extends SessionMiddleware { super.feedFromSession(data) } - close (): void { - this.outputToSession.complete() - super.close() - } - executeUnconditionalScripts (): void { for (const script of this.remainingScripts) { if (!script.expect) {