diff --git a/app/lib/pty.ts b/app/lib/pty.ts index c671d512..6aab8eda 100644 --- a/app/lib/pty.ts +++ b/app/lib/pty.ts @@ -4,6 +4,7 @@ import { ipcMain } from 'electron' import { Application } from './app' import { UTF8Splitter } from './utfSplitter' import { Subject, debounceTime } from 'rxjs' +import { StringDecoder } from './stringDecoder' class PTYDataQueue { private buffers: Buffer[] = [] @@ -90,6 +91,7 @@ class PTYDataQueue { export class PTY { private pty: nodePTY.IPty private outputQueue: PTYDataQueue + private decoder = new StringDecoder() exited = false constructor (private id: string, private app: Application, ...args: any[]) { @@ -99,7 +101,7 @@ export class PTY { } this.outputQueue = new PTYDataQueue(this.pty, data => { - setImmediate(() => this.emit('data', data)) + setImmediate(() => this.emit('data', this.decoder.write(data))) }) this.pty.onData(data => this.outputQueue.push(Buffer.from(data))) diff --git a/app/package.json b/app/package.json index 6f1b7001..7fdf3112 100644 --- a/app/package.json +++ b/app/package.json @@ -15,7 +15,7 @@ "watch": "webpack --progress --color --watch" }, "dependencies": { - "@electron/remote": "2.0.5", + "@electron/remote": "2.0.8", "@tabby-gang/node-pty": "^0.11.0-beta.200", "any-promise": "^1.3.0", "electron-config": "2.0.0", @@ -29,7 +29,7 @@ "mz": "^2.7.0", "native-process-working-directory": "^1.0.2", "npm": "6", - "rxjs": "^7.5.1", + "rxjs": "^7.5.5", "source-map-support": "^0.5.20", "v8-compile-cache": "^2.3.0", "yargs": "^17.3.1" diff --git a/app/yarn.lock b/app/yarn.lock index 3f43c631..98206a14 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@electron/remote@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-2.0.5.tgz#d38bcd2ad2825cca42c5ea4c92efafa99720c52a" - integrity sha512-Ot8VsYCwAJ+9DgqRuYCiAobS8TVKvnXJMncR14/28ORso1iWFG0X6geyk3hc13N48Oc/WJnPYlYI3o7g5Ja2Qg== +"@electron/remote@2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-2.0.8.tgz#85ff321f0490222993207106e2f720273bb1a5c3" + integrity sha512-P10v3+iFCIvEPeYzTWWGwwHmqWnjoh8RYnbtZAb3RlQefy4guagzIwcWtfftABIfm6JJTNQf4WPSKWZOpLmHXw== "@iarna/cli@^1.2.0": version "1.2.0" @@ -3196,10 +3196,10 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^7.5.1: - version "7.5.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.1.tgz#af73df343cbcab37628197f43ea0c8256f54b157" - integrity sha512-KExVEeZWxMZnZhUZtsJcFwz8IvPvgu4G2Z2QyqjZQzUGr32KDYuSxrEYO4w3tFFNbfLozcrKUTvTPi+E9ywJkQ== +rxjs@^7.5.5: + version "7.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" + integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== dependencies: tslib "^2.1.0" diff --git a/extras/UAC.exe b/extras/UAC.exe index 42b74bbf..31bd16ec 100644 Binary files a/extras/UAC.exe and b/extras/UAC.exe differ diff --git a/package.json b/package.json index 12a251bc..aeb0c79c 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", "apply-loader": "2.0.0", - "axios": "^0.26.0", + "axios": "^0.26.1", "browserify-sign": "^4.2.1", "clone-deep": "^4.0.1", "compare-versions": "^4", @@ -34,7 +34,7 @@ "cross-env": "7.0.3", "css-loader": "^6.7.1", "deep-equal": "2.0.5", - "electron": "17.1.1", + "electron": "17.1.2", "electron-builder": "^22.14.13", "electron-download": "^4.1.1", "electron-installer-snap": "^5.1.0", @@ -46,6 +46,7 @@ "graceful-fs": "^4.2.9", "html-loader": "3.1.0", "json-loader": "^0.5.7", + "thenby": "^1.3.4", "lru-cache": "^6.0.0", "macos-release": "^3.0.1", "ngx-sortablejs": "^11.1.0", @@ -74,9 +75,9 @@ "ssh2": "^1.7.0", "style-loader": "^3.3.1", "svg-inline-loader": "^0.8.2", - "ts-loader": "^9.2.7", + "ts-loader": "^9.2.8", "tslib": "^2.3.1", - "typedoc": "^0.22.12", + "typedoc": "^0.22.13", "typescript": "^4.3.5", "utils-decorators": "^1.10.4", "val-loader": "4.0.0", @@ -84,7 +85,7 @@ "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.9.2", "yaml-loader": "0.6.0", - "zone.js": "^0.11.4" + "zone.js": "^0.11.5" }, "resolutions": { "*/pug": "^3", diff --git a/tabby-core/src/api/selector.ts b/tabby-core/src/api/selector.ts index 12c69020..2b5d5412 100644 --- a/tabby-core/src/api/selector.ts +++ b/tabby-core/src/api/selector.ts @@ -6,5 +6,6 @@ export interface SelectorOption { icon?: string freeInputPattern?: string color?: string + weight?: number callback?: (string?) => void } diff --git a/tabby-core/src/components/profileIcon.component.pug b/tabby-core/src/components/profileIcon.component.pug new file mode 100644 index 00000000..6e5ec137 --- /dev/null +++ b/tabby-core/src/components/profileIcon.component.pug @@ -0,0 +1,9 @@ +i.icon( + class='fa-fw {{icon}}', + [style.color]='color', + *ngIf='!isHTML' +) +.icon( + [fastHtmlBind]='icon', + *ngIf='isHTML' +) diff --git a/tabby-core/src/components/profileIcon.component.scss b/tabby-core/src/components/profileIcon.component.scss new file mode 100644 index 00000000..c44c405d --- /dev/null +++ b/tabby-core/src/components/profileIcon.component.scss @@ -0,0 +1,15 @@ +:host { + display: flex; + align-items: center; + max-width: 1.25rem; +} + +::ng-deep img { + max-width: 100%; + max-height: 100%; +} + +::ng-deep svg { + width: 100%; + height: 100%; +} diff --git a/tabby-core/src/components/profileIcon.component.ts b/tabby-core/src/components/profileIcon.component.ts new file mode 100644 index 00000000..c7bf0649 --- /dev/null +++ b/tabby-core/src/components/profileIcon.component.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { Component, Input } from '@angular/core' +import { BaseComponent } from './base.component' + +/** @hidden */ +@Component({ + selector: 'profile-icon', + template: require('./profileIcon.component.pug'), + styles: [require('./profileIcon.component.scss')], +}) +export class ProfileIconComponent extends BaseComponent { + @Input() icon?: string + @Input() color?: string + + get isHTML (): boolean { + return this.icon?.startsWith('<') ?? false + } +} diff --git a/tabby-core/src/components/selectorModal.component.pug b/tabby-core/src/components/selectorModal.component.pug index 20d292b0..e4d359c8 100644 --- a/tabby-core/src/components/selectorModal.component.pug +++ b/tabby-core/src/components/selectorModal.component.pug @@ -17,15 +17,9 @@ (click)='selectOption(option)', [class.active]='selectedIndex == i' ) - i.icon( - class='fa-fw {{option.icon}}', - style='color: {{option.color}}', - *ngIf='!iconIsSVG(option.icon)' - ) - .icon( - [fastHtmlBind]='option.icon', - style='color: {{option.color}}', - *ngIf='iconIsSVG(option.icon)' + profile-icon( + [icon]='option.icon', + [color]='option.color' ) .title.mr-2 {{getOptionText(option)}} .description.no-wrap.text-muted {{option.description}} diff --git a/tabby-core/src/components/selectorModal.component.ts b/tabby-core/src/components/selectorModal.component.ts index 02da460a..4a614099 100644 --- a/tabby-core/src/components/selectorModal.component.ts +++ b/tabby-core/src/components/selectorModal.component.ts @@ -1,3 +1,4 @@ +import { firstBy } from 'thenby' import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core' // eslint-disable-line @typescript-eslint/no-unused-vars import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { SelectorOption } from '../api/selector' @@ -52,8 +53,11 @@ export class SelectorModalComponent { onFilterChange (): void { const f = this.filter.trim().toLowerCase() if (!f) { - this.filteredOptions = this.options.slice() - .sort((a, b) => a.group?.localeCompare(b.group ?? '') ?? 0) + this.filteredOptions = this.options.slice().sort( + firstBy, number>(x => x.weight ?? 0) + .thenBy, string>(x => x.group ?? '') + .thenBy, string>(x => x.name) + ) .filter(x => !x.freeInputPattern) } else { const terms = f.split(' ') @@ -84,8 +88,4 @@ export class SelectorModalComponent { close (): void { this.modalInstance.dismiss() } - - iconIsSVG (icon?: string): boolean { - return icon?.startsWith('<') ?? false - } } diff --git a/tabby-core/src/components/tabHeader.component.pug b/tabby-core/src/components/tabHeader.component.pug index d71f85f6..9a6a91dc 100644 --- a/tabby-core/src/components/tabHeader.component.pug +++ b/tabby-core/src/components/tabHeader.component.pug @@ -5,10 +5,10 @@ .index(*ngIf='!config.store.terminal.hideTabIndex && hostApp.platform === Platform.macOS', cdkDragHandle) {{index + 1}} .index(*ngIf='!config.store.terminal.hideTabIndex && hostApp.platform !== Platform.macOS') {{index + 1}} -.icon( +profile-icon( *ngIf='config.store.terminal.showTabProfileIcon && tab.icon', - [ngClass]='tab.icon', - [style.color]='tab.color' + [icon]='tab.icon', + [color]='tab.color' ) .name( diff --git a/tabby-core/src/components/tabHeader.component.scss b/tabby-core/src/components/tabHeader.component.scss index bc664d98..f09eff52 100644 --- a/tabby-core/src/components/tabHeader.component.scss +++ b/tabby-core/src/components/tabHeader.component.scss @@ -26,8 +26,7 @@ $tabs-height: 38px; height: $tabs-height; } - .index, - .icon { + .index { flex: none; font-weight: bold; -webkit-app-region: no-drag; @@ -41,7 +40,7 @@ $tabs-height: 38px; margin-top: 1px; } - .icon { + profile-icon { font-size: 13px; margin: 1px 4px 0 0; } diff --git a/tabby-core/src/index.ts b/tabby-core/src/index.ts index 252e3b48..d5092b5b 100644 --- a/tabby-core/src/index.ts +++ b/tabby-core/src/index.ts @@ -29,6 +29,7 @@ import { SplitTabPaneLabelComponent } from './components/splitTabPaneLabel.compo import { UnlockVaultModalComponent } from './components/unlockVaultModal.component' import { WelcomeTabComponent } from './components/welcomeTab.component' import { TransfersMenuComponent } from './components/transfersMenu.component' +import { ProfileIconComponent } from './components/profileIcon.component' import { AutofocusDirective } from './directives/autofocus.directive' import { AlwaysVisibleTypeaheadDirective } from './directives/alwaysVisibleTypeahead.directive' @@ -128,6 +129,7 @@ const PROVIDERS = [ TransfersMenuComponent, DropZoneDirective, CdkAutoDropGroup, + ProfileIconComponent, ], entryComponents: [ PromptModalComponent, @@ -150,6 +152,7 @@ const PROVIDERS = [ DragDropModule, TranslateModule, CdkAutoDropGroup, + ProfileIconComponent, ], }) export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class diff --git a/tabby-core/src/services/profiles.service.ts b/tabby-core/src/services/profiles.service.ts index 7c287038..055e011e 100644 --- a/tabby-core/src/services/profiles.service.ts +++ b/tabby-core/src/services/profiles.service.ts @@ -112,6 +112,7 @@ export class ProfilesService { group: this.translate.instant('Recent'), icon: 'fas fa-history', color: p.color, + weight: -1, callback: async () => { if (p.id) { p = (await this.getProfiles()).find(x => x.id === p.id) ?? p @@ -124,6 +125,7 @@ export class ProfilesService { name: this.translate.instant('Clear recent profiles'), group: this.translate.instant('Recent'), icon: 'fas fa-eraser', + weight: -1, callback: async () => { window.localStorage.removeItem('recentProfiles') this.config.save() @@ -142,6 +144,7 @@ export class ProfilesService { options = [...options, ...profiles.map((p): SelectorOption => ({ ...this.selectorOptionForProfile(p), + weight: p.isBuiltin ? 2 : 1, callback: () => resolve(p), }))] @@ -150,6 +153,7 @@ export class ProfilesService { options.push({ name: this.translate.instant('Manage profiles'), icon: 'fas fa-window-restore', + weight: 10, callback: () => { this.app.openNewTabRaw({ type: SettingsTabComponent, diff --git a/tabby-core/src/theme.scss b/tabby-core/src/theme.scss index 56a0fbc6..685b0756 100644 --- a/tabby-core/src/theme.scss +++ b/tabby-core/src/theme.scss @@ -393,3 +393,15 @@ hr { .dropdown-menu { box-shadow: $dropdown-box-shadow; } + +ngx-colors-panel .opened { + background: $body-bg !important; + + button { + color: $body-color; + } + + .button svg { + fill: white; + } +} diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index ea308de0..2f49ebee 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -3,6 +3,7 @@ import * as fs from 'fs/promises' import * as gracefulFS from 'graceful-fs' import * as fsSync from 'fs' import * as os from 'os' +import { v4 as uuidv4 } from 'uuid' import { promisify } from 'util' import promiseIpc, { RendererProcessType } from 'electron-promise-ipc' import { execFile } from 'mz/child_process' @@ -119,7 +120,7 @@ export class ElectronPlatformService extends PlatformService { } async _saveConfigInternal (content: string): Promise { - const tempPath = this.configPath + '.new.' + Date.now().toString() + const tempPath = this.configPath + '.new.' + uuidv4().toString() await fs.writeFile(tempPath, content, 'utf8') await fs.writeFile(this.configPath + '.backup', content, 'utf8') await promisify(gracefulFS.rename)(tempPath, this.configPath) diff --git a/tabby-local/src/session.ts b/tabby-local/src/session.ts index da4ec3e6..bba57f75 100644 --- a/tabby-local/src/session.ts +++ b/tabby-local/src/session.ts @@ -140,6 +140,7 @@ export class Session extends BaseSession { let env = mergeEnv( process.env, { + COLORTERM: 'truecolor', TERM: 'xterm-256color', TERM_PROGRAM: 'Tabby', }, diff --git a/tabby-settings/src/components/editProfileModal.component.pug b/tabby-settings/src/components/editProfileModal.component.pug index 5e19c22e..a81a5d28 100644 --- a/tabby-settings/src/components/editProfileModal.component.pug +++ b/tabby-settings/src/components/editProfileModal.component.pug @@ -40,7 +40,10 @@ ) .input-group-append .input-group-text - i([class]='"fa-fw " + profile.icon') + profile-icon( + [icon]='profile.icon', + [color]='profile.color' + ) ng-template(#rt,let-r='result',let-t='term') i([class]='"fa-fw " + r') diff --git a/tabby-settings/src/components/profilesSettingsTab.component.pug b/tabby-settings/src/components/profilesSettingsTab.component.pug index 705f111a..6062a050 100644 --- a/tabby-settings/src/components/profilesSettingsTab.component.pug +++ b/tabby-settings/src/components/profilesSettingsTab.component.pug @@ -58,14 +58,9 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') [class.list-group-item-action]='!profile.isBuiltin', (click)='profile.isBuiltin ? null : editProfile(profile)' ) - i.icon( - class='fa-fw {{profile.icon}}', - [style.color]='profile.color', - *ngIf='!iconIsSVG(profile.icon)' - ) - .icon( - [fastHtmlBind]='profile.icon', - *ngIf='iconIsSVG(profile.icon)' + profile-icon( + [icon]='profile.icon', + [color]='profile.color' ) .no-wrap {{profile.name}} diff --git a/tabby-settings/src/components/profilesSettingsTab.component.scss b/tabby-settings/src/components/profilesSettingsTab.component.scss index ec1f9eaa..ed7f7623 100644 --- a/tabby-settings/src/components/profilesSettingsTab.component.scss +++ b/tabby-settings/src/components/profilesSettingsTab.component.scss @@ -1,8 +1,8 @@ -.icon { +profile-icon { width: 1.25rem; margin-right: 0.25rem; } -.icon + * { +profile-icon + * { margin-left: 10px; } diff --git a/tabby-settings/src/components/profilesSettingsTab.component.ts b/tabby-settings/src/components/profilesSettingsTab.component.ts index 9174d24d..33405328 100644 --- a/tabby-settings/src/components/profilesSettingsTab.component.ts +++ b/tabby-settings/src/components/profilesSettingsTab.component.ts @@ -225,10 +225,6 @@ export class ProfilesSettingsTabComponent extends BaseComponent { return !this.filter || (profile.name + '$' + (this.getDescription(profile) ?? '')).toLowerCase().includes(this.filter.toLowerCase()) } - iconIsSVG (icon?: string): boolean { - return icon?.startsWith('<') ?? false - } - getDescription (profile: PartialProfile): string|null { return this.profilesService.getDescription(profile) } diff --git a/tabby-ssh/src/components/sshProfileSettings.component.pug b/tabby-ssh/src/components/sshProfileSettings.component.pug index 57aa248a..6c630a9d 100644 --- a/tabby-ssh/src/components/sshProfileSettings.component.pug +++ b/tabby-ssh/src/components/sshProfileSettings.component.pug @@ -61,7 +61,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav') label(translate) Jump host select.form-control([(ngModel)]='profile.options.jumpHost') option([ngValue]='null', translate) Select - option([ngValue]='x.id', *ngFor='let x of jumpHosts') {{x.name}} + option([ngValue]='x.id', *ngFor='let x of jumpHosts') {{getJumpHostLabel(x)}} .d-flex.w-100(*ngIf='connectionMode === "socksProxy"') diff --git a/tabby-ssh/src/components/sshProfileSettings.component.ts b/tabby-ssh/src/components/sshProfileSettings.component.ts index 5d3dc35e..659e98e5 100644 --- a/tabby-ssh/src/components/sshProfileSettings.component.ts +++ b/tabby-ssh/src/components/sshProfileSettings.component.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Component, ViewChild } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { firstBy } from 'thenby' import { ConfigService, FileProvidersService, Platform, HostAppService, PromptModalComponent, PartialProfile } from 'tabby-core' import { LoginScriptsSettingsComponent } from 'tabby-terminal' @@ -34,6 +35,8 @@ export class SSHProfileSettingsComponent { async ngOnInit () { this.jumpHosts = this.config.store.profiles.filter(x => x.type === 'ssh' && x !== this.profile) + this.jumpHosts.sort(firstBy(x => this.getJumpHostLabel(x))) + for (const k of Object.values(SSHAlgorithmType)) { this.algorithms[k] = {} for (const alg of this.profile.options.algorithms?.[k] ?? []) { @@ -63,6 +66,10 @@ export class SSHProfileSettingsComponent { } } + getJumpHostLabel (p: PartialProfile) { + return p.group ? `${p.group} / ${p.name}` : p.name + } + async setPassword () { const modal = this.ngbModal.open(PromptModalComponent) modal.componentInstance.prompt = `Password for ${this.profile.options.user}@${this.profile.options.host}` diff --git a/tabby-ssh/src/session/ssh.ts b/tabby-ssh/src/session/ssh.ts index 26a2c13b..f0da8f13 100644 --- a/tabby-ssh/src/session/ssh.ts +++ b/tabby-ssh/src/session/ssh.ts @@ -16,9 +16,10 @@ import { PasswordStorageService } from '../services/passwordStorage.service' import { SSHKnownHostsService } from '../services/sshKnownHosts.service' import { promisify } from 'util' import { SFTPSession } from './sftp' -import { ALGORITHM_BLACKLIST, SSHAlgorithmType, PortForwardType, SSHProfile, SSHProxyStream, AutoPrivateKeyLocator } from '../api' +import { SSHAlgorithmType, PortForwardType, SSHProfile, SSHProxyStream, AutoPrivateKeyLocator } from '../api' import { ForwardedPort } from './forwards' import { X11Socket } from './x11' +import { supportedAlgorithms } from '../algorithms' const WINDOWS_OPENSSH_AGENT_PIPE = '\\\\.\\pipe\\openssh-ssh-agent' @@ -201,7 +202,7 @@ export class SSHSession { let connected = false const algorithms = {} for (const key of Object.values(SSHAlgorithmType)) { - algorithms[key] = this.profile.options.algorithms![key].filter(x => !ALGORITHM_BLACKLIST.includes(x)) + algorithms[key] = this.profile.options.algorithms![key].filter(x => supportedAlgorithms[key].includes(x)) } const hostVerifiedPromise: Promise = new Promise((resolve, reject) => { diff --git a/tabby-terminal/package.json b/tabby-terminal/package.json index b8c83891..0b5aded8 100644 --- a/tabby-terminal/package.json +++ b/tabby-terminal/package.json @@ -23,9 +23,10 @@ "cli-spinner": "^0.2.10", "dataurl": "0.1.0", "hexer": "^1.5.0", + "ngx-colors": "^3.0.4", "ps-node": "^0.1.6", "runes": "^0.4.2", - "xterm": "npm:@tabby-gang/xterm@^4.17.1-beta.1", + "xterm": "npm:@tabby-gang/xterm@^4.17.1-beta.2", "xterm-addon-fit": "^0.5.0", "xterm-addon-ligatures": "^0.5.0", "xterm-addon-search": "^0.8.2", diff --git a/tabby-terminal/src/components/colorPicker.component.pug b/tabby-terminal/src/components/colorPicker.component.pug index 33ccec31..e29757fb 100644 --- a/tabby-terminal/src/components/colorPicker.component.pug +++ b/tabby-terminal/src/components/colorPicker.component.pug @@ -1,16 +1,7 @@ -ng-template(#content) - .preview( - [style.width]='"100%"', - [style.background]='model', - ) - input.form-control(type='text', [(ngModel)]='model', (ngModelChange)='onChange()', #input) - div( - [ngbPopover]='content', [style.background]='model', - (click)='open()', - autoClose='outside', - container='body', - #popover='ngbPopover', - [title]='hint' + ngx-colors-trigger, + [(ngModel)]='model', + (ngModelChange)='onChange($event)', + [ngbTooltip]='hint' ) {{ title }} diff --git a/tabby-terminal/src/components/colorPicker.component.ts b/tabby-terminal/src/components/colorPicker.component.ts index 6ea7eb1e..db6bcff0 100644 --- a/tabby-terminal/src/components/colorPicker.component.ts +++ b/tabby-terminal/src/components/colorPicker.component.ts @@ -1,5 +1,4 @@ -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core' -import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' +import { Component, Input, Output, EventEmitter } from '@angular/core' /** @hidden */ @Component({ @@ -12,16 +11,10 @@ export class ColorPickerComponent { @Input() title: string @Input() hint: string @Output() modelChange = new EventEmitter() - @ViewChild('popover') popover: NgbPopover - open (): void { - setImmediate(() => { - this.popover.open() - this.popover['_windowRef'].location.nativeElement.querySelector('input').focus() - }) - } - - onChange (): void { - this.modelChange.emit(this.model) + onChange (value: string): void { + if (value !== this.model) { + this.modelChange.emit(value) + } } } diff --git a/tabby-terminal/src/features/zmodem.ts b/tabby-terminal/src/features/zmodem.ts index cd5d660b..3b9ca5ba 100644 --- a/tabby-terminal/src/features/zmodem.ts +++ b/tabby-terminal/src/features/zmodem.ts @@ -26,9 +26,10 @@ export class ZModemDecorator extends TerminalDecorator { } attach (terminal: BaseTerminalTabComponent): void { + let isActive = false const sentry = new ZModem.Sentry({ to_terminal: data => { - if (!terminal.enablePassthrough) { + if (isActive) { terminal.write(data) } }, @@ -36,9 +37,11 @@ export class ZModemDecorator extends TerminalDecorator { on_detect: async detection => { try { terminal.enablePassthrough = false + isActive = true await this.process(terminal, detection) } finally { terminal.enablePassthrough = true + isActive = false } }, on_retract: () => { diff --git a/tabby-terminal/src/frontends/xtermFrontend.ts b/tabby-terminal/src/frontends/xtermFrontend.ts index 99eac0a3..66d243c9 100644 --- a/tabby-terminal/src/frontends/xtermFrontend.ts +++ b/tabby-terminal/src/frontends/xtermFrontend.ts @@ -138,9 +138,12 @@ export class XTermFrontend extends Frontend { } } + const oldKeyUp = this.xtermCore._keyUp.bind(this.xtermCore) this.xtermCore._keyUp = (e: KeyboardEvent) => { this.xtermCore.updateCursorStyle(e) - keyboardEventHandler('keyup', e) + if (keyboardEventHandler('keyup', e)) { + oldKeyUp(e) + } } this.xterm.buffer.onBufferChange(() => { diff --git a/tabby-terminal/src/index.ts b/tabby-terminal/src/index.ts index 6de3d67c..eaf6ee58 100644 --- a/tabby-terminal/src/index.ts +++ b/tabby-terminal/src/index.ts @@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser' import { FormsModule } from '@angular/forms' import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { ToastrModule } from 'ngx-toastr' +import { NgxColorsModule } from 'ngx-colors' import TabbyCorePlugin, { ConfigProvider, HotkeyProvider, TabContextMenuItemProvider, CLIHandler } from 'tabby-core' import { SettingsTabProvider } from 'tabby-settings' @@ -40,6 +41,7 @@ import { TerminalCLIHandler } from './cli' NgbModule, ToastrModule, TabbyCorePlugin, + NgxColorsModule, ], providers: [ { provide: SettingsTabProvider, useClass: AppearanceSettingsTabProvider, multi: true }, diff --git a/tabby-terminal/src/middleware/oscProcessing.ts b/tabby-terminal/src/middleware/oscProcessing.ts index 85c61633..2b68048f 100644 --- a/tabby-terminal/src/middleware/oscProcessing.ts +++ b/tabby-terminal/src/middleware/oscProcessing.ts @@ -35,7 +35,7 @@ export class OSCProcessor extends SessionMiddleware { console.debug('Unsupported OSC 1337 parameter:', paramString) } } else if (oscCode === 52) { - if (oscParams[0] === 'c') { + if (oscParams[0] === 'c' || oscParams[0] === '') { const content = Buffer.from(oscParams[1], 'base64') this.copyRequested.next(content.toString()) } diff --git a/tabby-terminal/yarn.lock b/tabby-terminal/yarn.lock index 1a4b275d..10e7b98b 100644 --- a/tabby-terminal/yarn.lock +++ b/tabby-terminal/yarn.lock @@ -94,6 +94,13 @@ minimist@^1.1.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +ngx-colors@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/ngx-colors/-/ngx-colors-3.0.4.tgz#69b760760e6e1e92fda5da51fa9b4bea7e555d40" + integrity sha512-peNvVpYkm8pe3nP8/TbaFFqo/RxZevGljKrzFa2g1hPPacdx+WdfwAN4uJfcGk7qTYbqlV64SSfb3Pnx8qjzDA== + dependencies: + tslib "^2.0.0" + opentype.js@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/opentype.js/-/opentype.js-0.8.0.tgz#acabcfa1642fbe894a3e4d759e43ba694e02bd35" @@ -140,6 +147,11 @@ tiny-inflate@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== +tslib@^2.0.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -178,10 +190,10 @@ xterm-addon-webgl@^0.12.0-beta.24: resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.24.tgz#5c17256933991856554c95c9bd1eaab42e9727a0" integrity sha512-+wZxKReEOlfN9JRHyikoffA6Do61/THR7QY35ajkQo0lLutKr6hTd/TLTuZh0PhFVelgTgudpXqlP++Lc0WFIA== -"xterm@npm:@tabby-gang/xterm@^4.17.1-beta.1": - version "4.17.1-beta.1" - resolved "https://registry.yarnpkg.com/@tabby-gang/xterm/-/xterm-4.17.1-beta.1.tgz#c24d507362c052491ca7ef1cb26445b9b1417942" - integrity sha512-nQNMhU7rBZTDv/0V+9UHxCjCCuEZNGftg+2/FiWrZxa1Tl5cWYFvlpMAB+O4drBJPTpkKJUKmDDdKKnbqlxnRg== +"xterm@npm:@tabby-gang/xterm@^4.17.1-beta.2": + version "4.17.1-beta.2" + resolved "https://registry.yarnpkg.com/@tabby-gang/xterm/-/xterm-4.17.1-beta.2.tgz#3b4b542297609f082c12b0877582cdf1398a84b5" + integrity sha512-tKePw6VBFVGvnKaxtfuS7qKbeX8bIT0+7asXSP70RA/78h8xeq3YoRHaV/cZEHaicNHMchlYFbXl3VpHXwusDw== yallist@^4.0.0: version "4.0.0" diff --git a/tabby-uac/UAC/UAC.vcxproj b/tabby-uac/UAC/UAC.vcxproj index 34be090c..3b2264a2 100644 --- a/tabby-uac/UAC/UAC.vcxproj +++ b/tabby-uac/UAC/UAC.vcxproj @@ -23,7 +23,7 @@ {DCE3B955-DB20-4334-B11B-F6C040825A59} Win32Proj UAC - 10.0.18298.0 + 10.0.17763.0 diff --git a/yarn.lock b/yarn.lock index 833845a4..ed381e22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1256,10 +1256,10 @@ aws4@^1.2.1, aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928" - integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og== +axios@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== dependencies: follow-redirects "^1.14.8" @@ -1422,6 +1422,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -2743,10 +2750,10 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz#f632d900a1f788dab22fec9c62ec5c9c8f0c4052" integrity sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig== -electron@17.1.1: - version "17.1.1" - resolved "https://registry.yarnpkg.com/electron/-/electron-17.1.1.tgz#a936907faf68a0a4ae24e8f79c8b22995661c54b" - integrity sha512-S+PIsCOfxB+9DkPsbnWpbLQx6+3P5FGedCeVQ/vhZEX8zD4Wj2F118HGFX6ShEfsaTYE623ESK/f+b2ueHpEpQ== +electron@17.1.2: + version "17.1.2" + resolved "https://registry.yarnpkg.com/electron/-/electron-17.1.2.tgz#b4e4a0df883d9a9854cf865efa2bb00b12d55b1d" + integrity sha512-hqKQaUIRWX5Y2eAD8FZINWD/e5TKdpkbBYbkcZmJS4Bd1PKQsaDVc9h5xoA8zZQkPymE9rss+swjRpAFurOPGQ== dependencies: "@electron/get" "^1.13.0" "@types/node" "^14.6.2" @@ -2818,15 +2825,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^5.0.0: - version "5.8.3" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" - integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enhanced-resolve@^5.9.2: +enhanced-resolve@^5.0.0, enhanced-resolve@^5.9.2: version "5.9.2" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== @@ -5176,10 +5175,10 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== -marked@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.10.tgz#423e295385cc0c3a70fa495e0df68b007b879423" - integrity sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw== +marked@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.12.tgz#2262a4e6fd1afd2f13557726238b69a48b982f7d" + integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ== matcher@^3.0.0: version "3.0.0" @@ -5312,6 +5311,13 @@ minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -7474,10 +7480,10 @@ shelljs@0.8.5: interpret "^1.0.0" rechoir "^0.6.2" -shiki@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.0.tgz#85f21ecfa95b377ff64db6c71442c22c220e9540" - integrity sha512-iczxaIYeBFHTFrQPb9DVy2SKgYxC4Wo7Iucm7C17cCh2Ge/refnvHscUOxM85u57MfLoNOtjoEFUWt9gBexblA== +shiki@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" + integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng== dependencies: jsonc-parser "^3.0.0" vscode-oniguruma "^1.6.1" @@ -8143,6 +8149,11 @@ text-table@^0.2.0, text-table@~0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +thenby@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/thenby/-/thenby-1.3.4.tgz#81581f6e1bb324c6dedeae9bfc28e59b1a2201cc" + integrity sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ== + throttleit@0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz" @@ -8302,10 +8313,10 @@ truncate-utf8-bytes@^1.0.0: dependencies: utf8-byte-length "^1.0.1" -ts-loader@^9.2.7: - version "9.2.7" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.7.tgz#948654099ca96992b62ec47bd9cee5632006e101" - integrity sha512-Fxh44mKli9QezgbdCXkEJWxnedQ0ead7DXTH+lfXEPedu+Y9EtMJ2aQ9G3Dj1j7Q612E8931rww8NDZha4Tibg== +ts-loader@^9.2.8: + version "9.2.8" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.8.tgz#e89aa32fa829c5cad0a1d023d6b3adecd51d5a48" + integrity sha512-gxSak7IHUuRtwKf3FIPSW1VpZcqF9+MBrHOvBp9cjHh+525SjtCIJKVGjRKIAfxBwDGDGCFF00rTfzB1quxdSw== dependencies: chalk "^4.1.0" enhanced-resolve "^5.0.0" @@ -8317,7 +8328,7 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.1: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -8390,16 +8401,16 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typedoc@^0.22.12: - version "0.22.12" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.12.tgz#52a8bb0e77458dcbab35fb89e24b80160ba6558d" - integrity sha512-FcyC+YuaOpr3rB9QwA1IHOi9KnU2m50sPJW5vcNRPCIdecp+3bFkh7Rq5hBU1Fyn29UR2h4h/H7twZHWDhL0sw== +typedoc@^0.22.13: + version "0.22.13" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.13.tgz#d061f8f0fb7c9d686e48814f245bddeea4564e66" + integrity sha512-NHNI7Dr6JHa/I3+c62gdRNXBIyX7P33O9TafGLd07ur3MqzcKgwTvpg18EtvCLHJyfeSthAtCLpM7WkStUmDuQ== dependencies: glob "^7.2.0" lunr "^2.3.9" - marked "^4.0.10" - minimatch "^3.0.4" - shiki "^0.10.0" + marked "^4.0.12" + minimatch "^5.0.1" + shiki "^0.10.1" "typescript@2 - 4", typescript@^4.3.5: version "4.5.5" @@ -9082,9 +9093,9 @@ yocto-queue@^0.1.0: resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zone.js@^0.11.4: - version "0.11.4" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.11.4.tgz#0f70dcf6aba80f698af5735cbb257969396e8025" - integrity sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw== +zone.js@^0.11.5: + version "0.11.5" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.11.5.tgz#ab0b449e91fadb5ebb2db189ffe1b7b6048dc8b1" + integrity sha512-D1/7VxEuQ7xk6z/kAROe4SUbd9CzxY4zOwVGnGHerd/SgLIVU5f4esDzQUsOCeArn933BZfWMKydH7l7dPEp0g== dependencies: - tslib "^2.0.0" + tslib "^2.3.0"