diff --git a/terminus-terminal/src/api.ts b/terminus-terminal/src/api.ts index 3762fb26..d45a4751 100644 --- a/terminus-terminal/src/api.ts +++ b/terminus-terminal/src/api.ts @@ -1,7 +1,5 @@ import { Observable } from 'rxjs' import { TerminalTabComponent } from './components/terminalTab.component' -export { TerminalTabComponent } -export { IChildProcess } from './services/sessions.service' export abstract class TerminalDecorator { // tslint:disable-next-line no-empty diff --git a/terminus-terminal/src/components/appearanceSettingsTab.component.pug b/terminus-terminal/src/components/appearanceSettingsTab.component.pug new file mode 100644 index 00000000..481d32d8 --- /dev/null +++ b/terminus-terminal/src/components/appearanceSettingsTab.component.pug @@ -0,0 +1,243 @@ +h3.mb-3 Appearance +.row + .col-md-6 + .form-line + .header + .title Frontend + .description Switches terminal frontend implementation (experimental) + + select.form-control( + [(ngModel)]='config.store.terminal.frontend', + (ngModelChange)='config.save()', + ) + option(value='hterm') hterm + option(value='xterm') xterm + + .form-line + .header + .title Font + + .d-flex.w-75 + input.form-control.w-75( + type='text', + [ngbTypeahead]='fontAutocomplete', + [(ngModel)]='config.store.terminal.font', + (ngModelChange)='config.save()', + ) + input.form-control.w-25( + type='number', + [(ngModel)]='config.store.terminal.fontSize', + (ngModelChange)='config.save()', + ) + + .form-line + .header + .title Enable font ligatures + toggle( + [(ngModel)]='config.store.terminal.ligatures', + (ngModelChange)='config.save()', + ) + + .form-line(*ngIf='!editingColorScheme') + .header + .title Color scheme + + .input-group.w-50 + select.form-control( + [compareWith]='equalComparator', + [(ngModel)]='config.store.terminal.colorScheme', + (ngModelChange)='config.save()', + ) + option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}} + option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}} + .input-group-btn + button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)') Edit + .input-group-btn + button.btn.btn-outline-danger( + (click)='deleteScheme(config.store.terminal.colorScheme)', + *ngIf='isCustomScheme(config.store.terminal.colorScheme)' + ) + i.fa.fa-trash-o + + .form-group(*ngIf='editingColorScheme') + label Editing + .input-group + input.form-control(type='text', [(ngModel)]='editingColorScheme.name') + .input-group-btn + button.btn.btn-secondary((click)='saveScheme()') Save + .input-group-btn + button.btn.btn-secondary((click)='cancelEditing()') Cancel + + .form-group(*ngIf='editingColorScheme') + color-picker( + [(model)]='editingColorScheme.foreground', + (modelChange)='config.save(); schemeChanged = true', + title='FG', + ) + color-picker( + [(model)]='editingColorScheme.background', + (modelChange)='config.save(); schemeChanged = true', + title='BG', + ) + color-picker( + [(model)]='editingColorScheme.cursor', + (modelChange)='config.save(); schemeChanged = true', + title='CU', + ) + color-picker( + *ngFor='let _ of editingColorScheme.colors; let idx = index; trackBy: colorsTrackBy', + [(model)]='editingColorScheme.colors[idx]', + (modelChange)='config.save(); schemeChanged = true', + [title]='idx', + ) + + .col-md-6 + .form-group + .appearance-preview( + [style.font-family]='config.store.terminal.font', + [style.font-size]='config.store.terminal.fontSize + "px"', + [style.background-color]='(config.store.terminal.background == "theme") ? null : config.store.terminal.colorScheme.background', + [style.color]='config.store.terminal.colorScheme.foreground', + [style.font-feature-settings]='\'"liga" \' + config.store.terminal.ligatures ? 1 : 0', + [style.font-variant-ligatures]='config.store.terminal.ligatures ? "initial" : "none"', + ) + div + span([style.background-color]='config.store.terminal.colorScheme.colors[0]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[1]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[2]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[3]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[4]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[5]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[6]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[7]')   + span    + span([style.color]='config.store.terminal.colorScheme.colors[0]') B + span   + span([style.color]='config.store.terminal.colorScheme.colors[1]') R + span   + span([style.color]='config.store.terminal.colorScheme.colors[2]') G + span   + span([style.color]='config.store.terminal.colorScheme.colors[3]') Y + span   + span([style.color]='config.store.terminal.colorScheme.colors[4]') B + span   + span([style.color]='config.store.terminal.colorScheme.colors[5]') M + span   + span([style.color]='config.store.terminal.colorScheme.colors[6]') T + span   + span([style.color]='config.store.terminal.colorScheme.colors[7]') W + div + span([style.background-color]='config.store.terminal.colorScheme.colors[8]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[9]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[10]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[11]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[12]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[13]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[14]')   + span([style.background-color]='config.store.terminal.colorScheme.colors[15]')   + span    + span([style.color]='config.store.terminal.colorScheme.colors[8]') B + span   + span([style.color]='config.store.terminal.colorScheme.colors[9]') R + span   + span([style.color]='config.store.terminal.colorScheme.colors[10]') G + span   + span([style.color]='config.store.terminal.colorScheme.colors[11]') Y + span   + span([style.color]='config.store.terminal.colorScheme.colors[12]') B + span   + span([style.color]='config.store.terminal.colorScheme.colors[13]') M + span   + span([style.color]='config.store.terminal.colorScheme.colors[14]') T + span   + span([style.color]='config.store.terminal.colorScheme.colors[15]') W + div + span   + div + span john@doe-pc + span([style.color]='config.store.terminal.colorScheme.colors[1]') $ + span ls -l + div + span drwxr-xr-x 1 root + span([style.color]='config.store.terminal.colorScheme.colors[4]') directory + div + span -rw-r--r-- 1 root file + div + span -rwxr-xr-x 1 root + span([style.color]='config.store.terminal.colorScheme.colors[2]') executable + div + span -rwxr-xr-x 1 root + span([style.color]='config.store.terminal.colorScheme.colors[6]') sym + span -> + span([style.color]='config.store.terminal.colorScheme.colors[1]') link + div + span   + div + span john@doe-pc + span([style.color]='config.store.terminal.colorScheme.colors[1]') $ + span rm -rf / + span([style.background-color]='config.store.terminal.colorScheme.cursor')   + +.form-line + .header + .title Terminal background + + .btn-group( + [(ngModel)]='config.store.terminal.background', + (ngModelChange)='config.save()', + ngbRadioGroup + ) + label.btn.btn-secondary(ngbButtonLabel) + input( + type='radio', + ngbButton, + [value]='"theme"' + ) + | From theme + label.btn.btn-secondary(ngbButtonLabel) + input( + type='radio', + ngbButton, + [value]='"colorScheme"' + ) + | From color scheme + +.form-line + .header + .title Cursor shape + + .btn-group( + [(ngModel)]='config.store.terminal.cursor', + (ngModelChange)='config.save()', + ngbRadioGroup + ) + label.btn.btn-secondary(ngbButtonLabel) + input( + type='radio', + ngbButton, + [value]='"block"' + ) + | █ + label.btn.btn-secondary(ngbButtonLabel) + input( + type='radio', + ngbButton, + [value]='"beam"' + ) + | | + label.btn.btn-secondary(ngbButtonLabel) + input( + type='radio', + ngbButton, + [value]='"underline"' + ) + | ▁ + +.form-line + .header + .title Blink cursor + + toggle( + [(ngModel)]='config.store.terminal.cursorBlink', + (ngModelChange)='config.save()', + ) diff --git a/terminus-terminal/src/components/terminalSettingsTab.component.scss b/terminus-terminal/src/components/appearanceSettingsTab.component.scss similarity index 70% rename from terminus-terminal/src/components/terminalSettingsTab.component.scss rename to terminus-terminal/src/components/appearanceSettingsTab.component.scss index 5eb28100..da32df4f 100644 --- a/terminus-terminal/src/components/terminalSettingsTab.component.scss +++ b/terminus-terminal/src/components/appearanceSettingsTab.component.scss @@ -1,7 +1,7 @@ .appearance-preview { padding: 10px 0; - margin-left: 30px; - margin: 0 0 10px; + margin-left: 20px; + padding: 10px; overflow: hidden; span { white-space: pre; diff --git a/terminus-terminal/src/components/appearanceSettingsTab.component.ts b/terminus-terminal/src/components/appearanceSettingsTab.component.ts new file mode 100644 index 00000000..e798a659 --- /dev/null +++ b/terminus-terminal/src/components/appearanceSettingsTab.component.ts @@ -0,0 +1,90 @@ +import { Observable } from 'rxjs' +import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators' +import { exec } from 'mz/child_process' +import deepEqual = require('deep-equal') +const fontManager = require('font-manager') + +import { Component, Inject } from '@angular/core' +import { ConfigService, HostAppService, Platform } from 'terminus-core' +import { TerminalColorSchemeProvider, ITerminalColorScheme } from '../api' + +@Component({ + template: require('./appearanceSettingsTab.component.pug'), + styles: [require('./appearanceSettingsTab.component.scss')], +}) +export class AppearanceSettingsTabComponent { + fonts: string[] = [] + colorSchemes: ITerminalColorScheme[] = [] + equalComparator = deepEqual + editingColorScheme: ITerminalColorScheme + schemeChanged = false + + constructor ( + @Inject(TerminalColorSchemeProvider) private colorSchemeProviders: TerminalColorSchemeProvider[], + private hostApp: HostAppService, + public config: ConfigService, + ) { } + + async ngOnInit () { + if (this.hostApp.platform === Platform.Windows || this.hostApp.platform === Platform.macOS) { + let fonts = await new Promise((resolve) => fontManager.findFonts({ monospace: true }, resolve)) + this.fonts = fonts.map(x => x.family) + this.fonts.sort() + } + if (this.hostApp.platform === Platform.Linux) { + exec('fc-list :spacing=mono').then(([stdout, _]) => { + this.fonts = stdout.toString() + .split('\n') + .filter(x => !!x) + .map(x => x.split(':')[1].trim()) + .map(x => x.split(',')[0].trim()) + this.fonts.sort() + }) + } + this.colorSchemes = (await Promise.all(this.config.enabledServices(this.colorSchemeProviders).map(x => x.getSchemes()))).reduce((a, b) => a.concat(b)) + } + + fontAutocomplete = (text$: Observable) => { + return text$.pipe( + debounceTime(200), + distinctUntilChanged(), + map(query => this.fonts.filter(v => new RegExp(query, 'gi').test(v))), + map(list => Array.from(new Set(list))), + ) + } + + editScheme (scheme: ITerminalColorScheme) { + this.editingColorScheme = scheme + this.schemeChanged = false + } + + saveScheme () { + let schemes = this.config.store.terminal.customColorSchemes + schemes = schemes.filter(x => x !== this.editingColorScheme && x.name !== this.editingColorScheme.name) + schemes.push(this.editingColorScheme) + this.config.store.terminal.customColorSchemes = schemes + this.config.save() + this.cancelEditing() + } + + cancelEditing () { + this.editingColorScheme = null + } + + deleteScheme (scheme: ITerminalColorScheme) { + if (confirm(`Delete "${scheme.name}"?`)) { + let schemes = this.config.store.terminal.customColorSchemes + schemes = schemes.filter(x => x !== scheme) + this.config.store.terminal.customColorSchemes = schemes + this.config.save() + } + } + + isCustomScheme (scheme: ITerminalColorScheme) { + return this.config.store.terminal.customColorSchemes.some(x => deepEqual(x, scheme)) + } + + colorsTrackBy (index) { + return index + } +} diff --git a/terminus-terminal/src/components/shellSettingsTab.component.pug b/terminus-terminal/src/components/shellSettingsTab.component.pug new file mode 100644 index 00000000..1de2b77d --- /dev/null +++ b/terminus-terminal/src/components/shellSettingsTab.component.pug @@ -0,0 +1,49 @@ +h3.mb-3 Shell + +.form-line + .header + .title Shell + .description Default shell for new tabs + + select.form-control( + [(ngModel)]='config.store.terminal.shell', + (ngModelChange)='config.save()', + ) + option( + *ngFor='let shell of shells', + [ngValue]='shell.id' + ) {{shell.name}} + +.form-line(*ngIf='config.store.terminal.shell == "custom"') + .header + .title Custom shell + + input.form-control( + type='text', + [(ngModel)]='config.store.terminal.customShell', + (ngModelChange)='config.save()', + ) + +.form-line(*ngIf='persistenceProviders.length > 0') + .header + .title Session persistence + .description Restores tabs when Terminus is restarted + select.form-control( + [(ngModel)]='config.store.terminal.persistence', + (ngModelChange)='config.save()', + ) + option([ngValue]='null') Off + option( + *ngFor='let provider of persistenceProviders', + [ngValue]='provider.id' + ) {{provider.displayName}} + +.form-line + .header + .title Working directory + input.form-control( + type='text', + placeholder='Home directory', + [(ngModel)]='config.store.terminal.workingDirectory', + (ngModelChange)='config.save()', + ) diff --git a/terminus-terminal/src/components/shellSettingsTab.component.ts b/terminus-terminal/src/components/shellSettingsTab.component.ts new file mode 100644 index 00000000..1116aea6 --- /dev/null +++ b/terminus-terminal/src/components/shellSettingsTab.component.ts @@ -0,0 +1,23 @@ +import { Component, Inject } from '@angular/core' +import { ConfigService } from 'terminus-core' +import { IShell, ShellProvider, SessionPersistenceProvider } from '../api' + +@Component({ + template: require('./shellSettingsTab.component.pug'), +}) +export class ShellSettingsTabComponent { + shells: IShell[] = [] + persistenceProviders: SessionPersistenceProvider[] + + constructor ( + public config: ConfigService, + @Inject(ShellProvider) private shellProviders: ShellProvider[], + @Inject(SessionPersistenceProvider) persistenceProviders: SessionPersistenceProvider[], + ) { + this.persistenceProviders = this.config.enabledServices(persistenceProviders).filter(x => x.isAvailable()) + } + + async ngOnInit () { + this.shells = (await Promise.all(this.config.enabledServices(this.shellProviders).map(x => x.provide()))).reduce((a, b) => a.concat(b)) + } +} diff --git a/terminus-terminal/src/components/terminalSettingsTab.component.pug b/terminus-terminal/src/components/terminalSettingsTab.component.pug index f116063e..6b61ddc2 100644 --- a/terminus-terminal/src/components/terminalSettingsTab.component.pug +++ b/terminus-terminal/src/components/terminalSettingsTab.component.pug @@ -1,298 +1,4 @@ -h3.mb-3 Appearance -.row - .col-md-6 - .form-line - .header - .title Frontend - .description Switches terminal frontend implementation (experimental) - - select.form-control( - [(ngModel)]='config.store.terminal.frontend', - (ngModelChange)='config.save()', - ) - option(value='hterm') hterm - option(value='xterm') xterm - - .form-line - .header - .title Font - - .d-flex.w-75 - input.form-control.w-75( - type='text', - [ngbTypeahead]='fontAutocomplete', - [(ngModel)]='config.store.terminal.font', - (ngModelChange)='config.save()', - ) - input.form-control.w-25( - type='number', - [(ngModel)]='config.store.terminal.fontSize', - (ngModelChange)='config.save()', - ) - - .form-line - .header - .title Enable font ligatures - toggle( - [(ngModel)]='config.store.terminal.ligatures', - (ngModelChange)='config.save()', - ) - - .form-line(*ngIf='!editingColorScheme') - .header - .title Color scheme - - .input-group.w-50 - select.form-control( - [compareWith]='equalComparator', - [(ngModel)]='config.store.terminal.colorScheme', - (ngModelChange)='config.save()', - ) - option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}} - option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}} - .input-group-btn - button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)') Edit - .input-group-btn - button.btn.btn-outline-danger( - (click)='deleteScheme(config.store.terminal.colorScheme)', - *ngIf='isCustomScheme(config.store.terminal.colorScheme)' - ) - i.fa.fa-trash-o - - .form-group(*ngIf='editingColorScheme') - label Editing - .input-group - input.form-control(type='text', [(ngModel)]='editingColorScheme.name') - .input-group-btn - button.btn.btn-secondary((click)='saveScheme()') Save - .input-group-btn - button.btn.btn-secondary((click)='cancelEditing()') Cancel - - .form-group(*ngIf='editingColorScheme') - color-picker( - [(model)]='editingColorScheme.foreground', - (modelChange)='config.save(); schemeChanged = true', - title='FG', - ) - color-picker( - [(model)]='editingColorScheme.background', - (modelChange)='config.save(); schemeChanged = true', - title='BG', - ) - color-picker( - [(model)]='editingColorScheme.cursor', - (modelChange)='config.save(); schemeChanged = true', - title='CU', - ) - color-picker( - *ngFor='let _ of editingColorScheme.colors; let idx = index; trackBy: colorsTrackBy', - [(model)]='editingColorScheme.colors[idx]', - (modelChange)='config.save(); schemeChanged = true', - [title]='idx', - ) - - .form-line - .header - .title Terminal background - - .btn-group( - [(ngModel)]='config.store.terminal.background', - (ngModelChange)='config.save()', - ngbRadioGroup - ) - label.btn.btn-secondary(ngbButtonLabel) - input( - type='radio', - ngbButton, - [value]='"theme"' - ) - | From theme - label.btn.btn-secondary(ngbButtonLabel) - input( - type='radio', - ngbButton, - [value]='"colorScheme"' - ) - | From colors - - .col-md-6 - .form-group - .appearance-preview( - [style.font-family]='config.store.terminal.font', - [style.font-size]='config.store.terminal.fontSize + "px"', - [style.background-color]='(config.store.terminal.background == "theme") ? null : config.store.terminal.colorScheme.background', - [style.color]='config.store.terminal.colorScheme.foreground', - [style.font-feature-settings]='\'"liga" \' + config.store.terminal.ligatures ? 1 : 0', - [style.font-variant-ligatures]='config.store.terminal.ligatures ? "initial" : "none"', - ) - div - span([style.background-color]='config.store.terminal.colorScheme.colors[0]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[1]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[2]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[3]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[4]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[5]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[6]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[7]')   - span    - span([style.color]='config.store.terminal.colorScheme.colors[0]') B - span   - span([style.color]='config.store.terminal.colorScheme.colors[1]') R - span   - span([style.color]='config.store.terminal.colorScheme.colors[2]') G - span   - span([style.color]='config.store.terminal.colorScheme.colors[3]') Y - span   - span([style.color]='config.store.terminal.colorScheme.colors[4]') B - span   - span([style.color]='config.store.terminal.colorScheme.colors[5]') M - span   - span([style.color]='config.store.terminal.colorScheme.colors[6]') T - span   - span([style.color]='config.store.terminal.colorScheme.colors[7]') W - div - span([style.background-color]='config.store.terminal.colorScheme.colors[8]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[9]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[10]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[11]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[12]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[13]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[14]')   - span([style.background-color]='config.store.terminal.colorScheme.colors[15]')   - span    - span([style.color]='config.store.terminal.colorScheme.colors[8]') B - span   - span([style.color]='config.store.terminal.colorScheme.colors[9]') R - span   - span([style.color]='config.store.terminal.colorScheme.colors[10]') G - span   - span([style.color]='config.store.terminal.colorScheme.colors[11]') Y - span   - span([style.color]='config.store.terminal.colorScheme.colors[12]') B - span   - span([style.color]='config.store.terminal.colorScheme.colors[13]') M - span   - span([style.color]='config.store.terminal.colorScheme.colors[14]') T - span   - span([style.color]='config.store.terminal.colorScheme.colors[15]') W - div - span   - div - span john@doe-pc - span([style.color]='config.store.terminal.colorScheme.colors[1]') $ - span ls -l - div - span drwxr-xr-x 1 root - span([style.color]='config.store.terminal.colorScheme.colors[4]') directory - div - span -rw-r--r-- 1 root file - div - span -rwxr-xr-x 1 root - span([style.color]='config.store.terminal.colorScheme.colors[2]') executable - div - span -rwxr-xr-x 1 root - span([style.color]='config.store.terminal.colorScheme.colors[6]') sym - span -> - span([style.color]='config.store.terminal.colorScheme.colors[1]') link - div - span   - div - span john@doe-pc - span([style.color]='config.store.terminal.colorScheme.colors[1]') $ - span rm -rf / - span([style.background-color]='config.store.terminal.colorScheme.cursor')   - -.form-line - .header - .title Cursor shape - - .btn-group( - [(ngModel)]='config.store.terminal.cursor', - (ngModelChange)='config.save()', - ngbRadioGroup - ) - label.btn.btn-secondary(ngbButtonLabel) - input( - type='radio', - ngbButton, - [value]='"block"' - ) - | █ - label.btn.btn-secondary(ngbButtonLabel) - input( - type='radio', - ngbButton, - [value]='"beam"' - ) - | | - label.btn.btn-secondary(ngbButtonLabel) - input( - type='radio', - ngbButton, - [value]='"underline"' - ) - | ▁ - -.form-line - .header - .title Blink cursor - - toggle( - [(ngModel)]='config.store.terminal.cursorBlink', - (ngModelChange)='config.save()', - ) - -h3.mt-3.mb-3 Shell - -.form-line - .header - .title Shell - .description Default shell for new tabs - - select.form-control( - [(ngModel)]='config.store.terminal.shell', - (ngModelChange)='config.save()', - ) - option( - *ngFor='let shell of shells', - [ngValue]='shell.id' - ) {{shell.name}} - -.form-line(*ngIf='config.store.terminal.shell == "custom"') - .header - .title Custom shell - - input.form-control( - type='text', - [(ngModel)]='config.store.terminal.customShell', - (ngModelChange)='config.save()', - ) - -.form-line(*ngIf='persistenceProviders.length > 0') - .header - .title Session persistence - .description Restores tabs when Terminus is restarted - select.form-control( - [(ngModel)]='config.store.terminal.persistence', - (ngModelChange)='config.save()', - ) - option([ngValue]='null') Off - option( - *ngFor='let provider of persistenceProviders', - [ngValue]='provider.id' - ) {{provider.displayName}} - -.form-line - .header - .title Working directory - input.form-control( - type='text', - placeholder='Home directory', - [(ngModel)]='config.store.terminal.workingDirectory', - (ngModelChange)='config.save()', - ) - -h3.mt-3.mb-3 Behaviour +h3.mt-3.mb-3 Terminal .form-line .header diff --git a/terminus-terminal/src/components/terminalSettingsTab.component.ts b/terminus-terminal/src/components/terminalSettingsTab.component.ts index 4e5f498d..ef95b942 100644 --- a/terminus-terminal/src/components/terminalSettingsTab.component.ts +++ b/terminus-terminal/src/components/terminalSettingsTab.component.ts @@ -1,97 +1,11 @@ -import { Observable } from 'rxjs' -import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators' -import { exec } from 'mz/child_process' -import deepEqual = require('deep-equal') -const fontManager = require('font-manager') - -import { Component, Inject } from '@angular/core' -import { ConfigService, HostAppService, Platform } from 'terminus-core' -import { TerminalColorSchemeProvider, ITerminalColorScheme, IShell, ShellProvider, SessionPersistenceProvider } from '../api' +import { Component } from '@angular/core' +import { ConfigService } from 'terminus-core' @Component({ template: require('./terminalSettingsTab.component.pug'), - styles: [require('./terminalSettingsTab.component.scss')], }) export class TerminalSettingsTabComponent { - fonts: string[] = [] - shells: IShell[] = [] - persistenceProviders: SessionPersistenceProvider[] - colorSchemes: ITerminalColorScheme[] = [] - equalComparator = deepEqual - editingColorScheme: ITerminalColorScheme - schemeChanged = false - constructor ( public config: ConfigService, - private hostApp: HostAppService, - @Inject(ShellProvider) private shellProviders: ShellProvider[], - @Inject(TerminalColorSchemeProvider) private colorSchemeProviders: TerminalColorSchemeProvider[], - @Inject(SessionPersistenceProvider) persistenceProviders: SessionPersistenceProvider[], - ) { - this.persistenceProviders = this.config.enabledServices(persistenceProviders).filter(x => x.isAvailable()) - } - - async ngOnInit () { - if (this.hostApp.platform === Platform.Windows || this.hostApp.platform === Platform.macOS) { - let fonts = await new Promise((resolve) => fontManager.findFonts({ monospace: true }, resolve)) - this.fonts = fonts.map(x => x.family) - this.fonts.sort() - } - if (this.hostApp.platform === Platform.Linux) { - exec('fc-list :spacing=mono').then(([stdout, _]) => { - this.fonts = stdout.toString() - .split('\n') - .filter(x => !!x) - .map(x => x.split(':')[1].trim()) - .map(x => x.split(',')[0].trim()) - this.fonts.sort() - }) - } - this.colorSchemes = (await Promise.all(this.config.enabledServices(this.colorSchemeProviders).map(x => x.getSchemes()))).reduce((a, b) => a.concat(b)) - this.shells = (await Promise.all(this.config.enabledServices(this.shellProviders).map(x => x.provide()))).reduce((a, b) => a.concat(b)) - } - - fontAutocomplete = (text$: Observable) => { - return text$.pipe( - debounceTime(200), - distinctUntilChanged(), - map(query => this.fonts.filter(v => new RegExp(query, 'gi').test(v))), - map(list => Array.from(new Set(list))), - ) - } - - editScheme (scheme: ITerminalColorScheme) { - this.editingColorScheme = scheme - this.schemeChanged = false - } - - saveScheme () { - let schemes = this.config.store.terminal.customColorSchemes - schemes = schemes.filter(x => x !== this.editingColorScheme && x.name !== this.editingColorScheme.name) - schemes.push(this.editingColorScheme) - this.config.store.terminal.customColorSchemes = schemes - this.config.save() - this.cancelEditing() - } - - cancelEditing () { - this.editingColorScheme = null - } - - deleteScheme (scheme: ITerminalColorScheme) { - if (confirm(`Delete "${scheme.name}"?`)) { - let schemes = this.config.store.terminal.customColorSchemes - schemes = schemes.filter(x => x !== scheme) - this.config.store.terminal.customColorSchemes = schemes - this.config.save() - } - } - - isCustomScheme (scheme: ITerminalColorScheme) { - return this.config.store.terminal.customColorSchemes.some(x => deepEqual(x, scheme)) - } - - colorsTrackBy (index) { - return index - } + ) { } } diff --git a/terminus-terminal/src/index.ts b/terminus-terminal/src/index.ts index a71c815d..34979e77 100644 --- a/terminus-terminal/src/index.ts +++ b/terminus-terminal/src/index.ts @@ -11,6 +11,8 @@ import { HostAppService } from 'terminus-core' import { ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, AppService, ConfigService } from 'terminus-core' import { SettingsTabProvider } from 'terminus-settings' +import { AppearanceSettingsTabComponent } from './components/appearanceSettingsTab.component' +import { ShellSettingsTabComponent } from './components/shellSettingsTab.component' import { TerminalTabComponent } from './components/terminalTab.component' import { TerminalSettingsTabComponent } from './components/terminalSettingsTab.component' import { ColorPickerComponent } from './components/colorPicker.component' @@ -24,7 +26,7 @@ import { TMuxPersistenceProvider } from './persistence/tmux' import { ButtonProvider } from './buttonProvider' import { RecoveryProvider } from './recoveryProvider' import { SessionPersistenceProvider, TerminalColorSchemeProvider, TerminalDecorator, ShellProvider } from './api' -import { TerminalSettingsTabProvider } from './settings' +import { TerminalSettingsTabProvider, AppearanceSettingsTabProvider, ShellSettingsTabProvider } from './settings' import { PathDropDecorator } from './pathDrop' import { TerminalConfigProvider } from './config' import { TerminalHotkeyProvider } from './hotkeys' @@ -58,9 +60,12 @@ import { hterm } from './hterm' TerminalFrontendService, TerminalService, + { provide: SettingsTabProvider, useClass: AppearanceSettingsTabProvider, multi: true }, + { provide: SettingsTabProvider, useClass: ShellSettingsTabProvider, multi: true }, + { provide: SettingsTabProvider, useClass: TerminalSettingsTabProvider, multi: true }, + { provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true }, { provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true }, - { provide: SettingsTabProvider, useClass: TerminalSettingsTabProvider, multi: true }, { provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true }, { provide: HotkeyProvider, useClass: TerminalHotkeyProvider, multi: true }, { provide: TerminalColorSchemeProvider, useClass: HyperColorSchemes, multi: true }, @@ -89,11 +94,15 @@ import { hterm } from './hterm' ], entryComponents: [ TerminalTabComponent, + AppearanceSettingsTabComponent, + ShellSettingsTabComponent, TerminalSettingsTabComponent, ], declarations: [ ColorPickerComponent, TerminalTabComponent, + AppearanceSettingsTabComponent, + ShellSettingsTabComponent, TerminalSettingsTabComponent, ], }) diff --git a/terminus-terminal/src/settings.ts b/terminus-terminal/src/settings.ts index 6f52bee6..3ce0606a 100644 --- a/terminus-terminal/src/settings.ts +++ b/terminus-terminal/src/settings.ts @@ -1,8 +1,30 @@ import { Injectable } from '@angular/core' import { SettingsTabProvider } from 'terminus-settings' +import { AppearanceSettingsTabComponent } from './components/appearanceSettingsTab.component' +import { ShellSettingsTabComponent } from './components/shellSettingsTab.component' import { TerminalSettingsTabComponent } from './components/terminalSettingsTab.component' +@Injectable() +export class AppearanceSettingsTabProvider extends SettingsTabProvider { + id = 'terminal-appearance' + title = 'Appearance' + + getComponentType (): any { + return AppearanceSettingsTabComponent + } +} + +@Injectable() +export class ShellSettingsTabProvider extends SettingsTabProvider { + id = 'terminal-shell' + title = 'Shell' + + getComponentType (): any { + return ShellSettingsTabComponent + } +} + @Injectable() export class TerminalSettingsTabProvider extends SettingsTabProvider { id = 'terminal'