This commit is contained in:
Eugene Pankov 2017-04-16 20:06:29 +02:00
parent b7c523b0c7
commit 8385161417
21 changed files with 117 additions and 34 deletions

View file

@ -19,6 +19,7 @@
"webpack": "^2.3.3", "webpack": "^2.3.3",
"bootstrap": "4.0.0-alpha.6", "bootstrap": "4.0.0-alpha.6",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"ngx-perfect-scrollbar": "^4.0.0",
"style-loader": "^0.13.1", "style-loader": "^0.13.1",
"to-string-loader": "^1.1.5", "to-string-loader": "^1.1.5",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",

View file

@ -38,7 +38,7 @@ title-bar(*ngIf='!config.store.appearance.useNativeFrame && config.store.appeara
*ngFor='let tab of app.tabs; trackBy: tab?.id', *ngFor='let tab of app.tabs; trackBy: tab?.id',
[active]='tab == app.activeTab', [active]='tab == app.activeTab',
[tab]='tab', [tab]='tab',
[class.scrollable]='tab.scrollable', [scrollable]='tab.scrollable',
) )
toaster-container([toasterconfig]="toasterconfig") toaster-container([toasterconfig]="toasterconfig")

View file

@ -92,7 +92,6 @@ export class AppRootComponent {
this.docking.dock() this.docking.dock()
}) })
this.hotkeys.registerHotkeys()
this.hostApp.secondInstance.subscribe(() => { this.hostApp.secondInstance.subscribe(() => {
this.onGlobalHotkey() this.onGlobalHotkey()
}) })

View file

@ -2,13 +2,21 @@ import { Component, Input, ViewChild, HostBinding, ViewContainerRef } from '@ang
import { BaseTabComponent } from '../components/baseTab' import { BaseTabComponent } from '../components/baseTab'
@Component({ @Component({
selector: 'tab-body', selector: 'tab-body',
template: '<ng-template #placeholder></ng-template>', template: `
styles: [require('./tabBody.scss')], <perfect-scrollbar [config]="{ suppressScrollX: true, suppressScrollY: !scrollable}">
<ng-template #placeholder></ng-template>
</perfect-scrollbar>
`,
styles: [
require('./tabBody.component.scss'),
require('./tabBody.deep.component.css'),
],
}) })
export class TabBodyComponent { export class TabBodyComponent {
@Input() @HostBinding('class.active') active: boolean @Input() @HostBinding('class.active') active: boolean
@Input() tab: BaseTabComponent @Input() tab: BaseTabComponent
@Input() scrollable: boolean
@ViewChild('placeholder', {read: ViewContainerRef}) placeholder: ViewContainerRef @ViewChild('placeholder', {read: ViewContainerRef}) placeholder: ViewContainerRef
ngAfterViewInit () { ngAfterViewInit () {

View file

@ -0,0 +1,4 @@
:host /deep/ .ps-content {
flex: auto;
display: flex;
}

View file

@ -6,6 +6,8 @@ appearance:
theme: 'Standard' theme: 'Standard'
useNativeFrame: false useNativeFrame: false
hotkeys: hotkeys:
toggle-window:
- 'Ctrl+Space'
close-tab: close-tab:
- 'Ctrl-Shift-W' - 'Ctrl-Shift-W'
- ['Ctrl-A', 'K'] - ['Ctrl-A', 'K']

View file

@ -4,6 +4,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { ToasterModule } from 'angular2-toaster' import { ToasterModule } from 'angular2-toaster'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar'
import { AppService } from './services/app' import { AppService } from './services/app'
import { ConfigService } from './services/config' import { ConfigService } from './services/config'
@ -19,7 +20,7 @@ import { TabRecoveryService } from './services/tabRecovery'
import { ThemesService } from './services/themes' import { ThemesService } from './services/themes'
import { AppRootComponent } from './components/appRoot' import { AppRootComponent } from './components/appRoot'
import { TabBodyComponent } from './components/tabBody' import { TabBodyComponent } from './components/tabBody.component'
import { StartPageComponent } from './components/startPage' import { StartPageComponent } from './components/startPage'
import { TabHeaderComponent } from './components/tabHeader' import { TabHeaderComponent } from './components/tabHeader'
import { TitleBarComponent } from './components/titleBar' import { TitleBarComponent } from './components/titleBar'
@ -29,6 +30,7 @@ import { Theme } from './api/theme'
import { StandardTheme } from './theme' import { StandardTheme } from './theme'
import 'perfect-scrollbar/dist/css/perfect-scrollbar.css'
const PROVIDERS = [ const PROVIDERS = [
AppService, AppService,
@ -55,6 +57,9 @@ const PROVIDERS = [
FormsModule, FormsModule,
ToasterModule, ToasterModule,
NgbModule, NgbModule,
PerfectScrollbarModule.forRoot({
suppressScrollX: true,
}),
], ],
declarations: [ declarations: [
AppRootComponent, AppRootComponent,

View file

@ -12,7 +12,8 @@ export class ConfigProxy {
if ( if (
defaults[key] instanceof Object && defaults[key] instanceof Object &&
!(defaults[key] instanceof Array) && !(defaults[key] instanceof Array) &&
Object.keys(defaults[key]).length > 0 Object.keys(defaults[key]).length > 0 &&
!defaults[key].__nonStructural
) { ) {
if (!real[key]) { if (!real[key]) {
real[key] = {} real[key] = {}

View file

@ -44,6 +44,10 @@ export class HotkeysService {
}) })
}) })
this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b)) this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b))
this.config.change.subscribe(() => {
this.registerGlobalHotkey()
})
this.registerGlobalHotkey()
} }
pushKeystroke (name, nativeEvent) { pushKeystroke (name, nativeEvent) {
@ -79,11 +83,18 @@ export class HotkeysService {
return stringifyKeySequence(this.currentKeystrokes.map((x) => x.event)) return stringifyKeySequence(this.currentKeystrokes.map((x) => x.event))
} }
registerHotkeys () { registerGlobalHotkey () {
this.electron.globalShortcut.unregisterAll() this.electron.globalShortcut.unregisterAll()
// TODO let value = this.config.store.hotkeys['toggle-window']
this.electron.globalShortcut.register('Ctrl+Space', () => { if (typeof value == 'string') {
this.globalHotkey.emit() value = [value]
}
value.forEach(item => {
item = (typeof item == 'string') ? [item] : item
this.electron.globalShortcut.register(item[0].replace(/-/g, '+'), () => {
this.globalHotkey.emit()
})
}) })
} }
@ -163,6 +174,10 @@ export class HotkeysService {
@Injectable() @Injectable()
export class AppHotkeyProvider extends HotkeyProvider { export class AppHotkeyProvider extends HotkeyProvider {
hotkeys: IHotkeyDescription[] = [ hotkeys: IHotkeyDescription[] = [
{
id: 'toggle-window',
name: 'Toggle terminal window',
},
{ {
id: 'new-tab', id: 'new-tab',
name: 'New tab', name: 'New tab',

View file

@ -42,23 +42,34 @@ $input-bg: #111;
$input-bg-disabled: #333; $input-bg-disabled: #333;
$input-color: $body-color; $input-color: $body-color;
//$input-border-color: rgba($black,.15); $input-color-placeholder: #333;
$input-border-color: #344;
//$input-box-shadow: inset 0 1px 1px rgba($black,.075); //$input-box-shadow: inset 0 1px 1px rgba($black,.075);
$input-border-radius: 0; $input-border-radius: 0;
$input-bg-focus: $input-bg; $input-bg-focus: $input-bg;
//$input-border-focus: lighten($brand-primary, 25%); //$input-border-focus: lighten($brand-primary, 25%);
//$input-box-shadow-focus: $input-box-shadow, rgba($input-border-focus, .6); //$input-box-shadow-focus: $input-box-shadow, rgba($input-border-focus, .6);
$input-color-focus: $input-color; $input-color-focus: $input-color;
$input-group-addon-bg: $input-bg;
$input-group-addon-border-color: $input-border-color;
$modal-content-bg: $body-bg; $modal-content-bg: $body-bg;
$modal-content-border-color: $body-bg2; $modal-content-border-color: $body-bg2;
$modal-header-border-color: $body-bg2; $modal-header-border-color: transparent;
$modal-footer-border-color: $body-bg2; $modal-footer-border-color: transparent;
$popover-bg: $body-bg2; $popover-bg: $body-bg2;
$dropdown-bg: $body-bg2;
$dropdown-link-color: $body-color;
$dropdown-link-hover-color: #333;
$dropdown-link-hover-bg: $body-bg3;
//$dropdown-link-active-color: $component-active-color;
//$dropdown-link-active-bg: $component-active-bg;
$dropdown-link-disabled-color: #333;
$dropdown-header-color: #333;
@import '~bootstrap/scss/bootstrap.scss'; @import '~bootstrap/scss/bootstrap.scss';
@ -300,3 +311,7 @@ ngb-tabset .tab-content {
margin-left: 5px; margin-left: 5px;
} }
} }
.input-group-addon + .form-control {
border-left: none;
}

View file

@ -31,6 +31,8 @@ module.exports = {
}, },
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] }, { test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] }, { test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
{ test: /\.css$/, use: ['to-string-loader', 'css-loader'], include: /component\.css/ },
{ test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /component\.css/ },
{ test: /\.yaml$/, use: ['json-loader', 'yaml-loader'] }, { test: /\.yaml$/, use: ['json-loader', 'yaml-loader'] },
] ]
}, },

View file

@ -16,6 +16,7 @@
"@types/webpack-env": "1.13.0", "@types/webpack-env": "1.13.0",
"awesome-typescript-loader": "3.1.2", "awesome-typescript-loader": "3.1.2",
"css-loader": "^0.28.0", "css-loader": "^0.28.0",
"ng2-filter-pipe": "^0.1.7",
"node-sass": "^4.5.2", "node-sass": "^4.5.2",
"pug": "^2.0.0-beta3", "pug": "^2.0.0-beta3",
"pug-loader": "^2.3.0", "pug-loader": "^2.3.0",

View file

@ -143,16 +143,21 @@ ngb-tabset.vertical(type='tabs')
template(ngbTabTitle) template(ngbTabTitle)
| Hotkeys | Hotkeys
template(ngbTabContent) template(ngbTabContent)
input.form-control(type='search', placeholder='Search hotkeys', [(ngModel)]='hotkeyFilter.name')
.form-group .form-group
table table.hotkeys-table
tr tr
th Toggle terminal window th Name
th ID
th Hotkey
tr(*ngFor='let hotkey of hotkeyDescriptions|filterBy:hotkeyFilter')
td {{hotkey.name}}
td {{hotkey.id}}
td td
hotkey-input('[(model)]'='globalHotkey') multi-hotkey-input(
tr(*ngFor='let hotkey of hotkeyDescriptions') '[(model)]'='config.store.hotkeys[hotkey.id]'
th {{hotkey.name}} '(modelChange)'='config.save(); docking.dock()'
td )
multi-hotkey-input('[(model)]'='config.store.hotkeys[hotkey.id]')
ngb-tab(*ngFor='let provider of settingsProviders') ngb-tab(*ngFor='let provider of settingsProviders')
template(ngbTabTitle) template(ngbTabTitle)

View file

@ -9,7 +9,11 @@
flex: none; flex: none;
} }
>.modal-body { .hotkeys-table {
padding: 0 0 20px !important; margin-top: 30px;
td, th {
padding: 5px 10px;
}
} }
} }

View file

@ -13,7 +13,7 @@ import { SettingsTabProvider } from '../api'
], ],
}) })
export class SettingsTabComponent extends BaseTabComponent { export class SettingsTabComponent extends BaseTabComponent {
globalHotkey = ['Ctrl+Shift+G'] hotkeyFilter = { name: null }
private hotkeyDescriptions: IHotkeyDescription[] private hotkeyDescriptions: IHotkeyDescription[]
constructor( constructor(

View file

@ -2,6 +2,8 @@ import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { Ng2FilterPipeModule } from 'ng2-filter-pipe'
import { ToolbarButtonProvider, TabRecoveryProvider } from 'terminus-core' import { ToolbarButtonProvider, TabRecoveryProvider } from 'terminus-core'
import { HotkeyInputComponent } from './components/hotkeyInput' import { HotkeyInputComponent } from './components/hotkeyInput'
@ -20,6 +22,7 @@ import { RecoveryProvider } from './recoveryProvider'
BrowserModule, BrowserModule,
FormsModule, FormsModule,
NgbModule, NgbModule,
Ng2FilterPipeModule,
], ],
providers: [ providers: [
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true }, { provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },

View file

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, HostAppService, Platform } from 'terminus-core' import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService } from 'terminus-core'
import { SessionsService } from './services/sessions' import { SessionsService } from './services/sessions'
import { TerminalTabComponent } from './components/terminalTab' import { TerminalTabComponent } from './components/terminalTab'
@ -10,7 +10,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
constructor ( constructor (
private app: AppService, private app: AppService,
private sessions: SessionsService, private sessions: SessionsService,
private hostApp: HostAppService, private config: ConfigService,
hotkeys: HotkeysService, hotkeys: HotkeysService,
) { ) {
super() super()
@ -26,11 +26,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
if (this.app.activeTab instanceof TerminalTabComponent) { if (this.app.activeTab instanceof TerminalTabComponent) {
cwd = await this.app.activeTab.session.getWorkingDirectory() cwd = await this.app.activeTab.session.getWorkingDirectory()
} }
let command = { let command = this.config.store.terminal.shell
[Platform.macOS]: 'zsh',
[Platform.Linux]: 'zsh',
[Platform.Windows]: 'cmd.exe',
}[this.hostApp.platform]
this.app.openNewTab( this.app.openNewTab(
TerminalTabComponent, TerminalTabComponent,
{ session: await this.sessions.createNewSession({ command, cwd }) } { session: await this.sessions.createNewSession({ command, cwd }) }

View file

@ -195,6 +195,15 @@
) )
| From the terminal colors | From the terminal colors
.form-group
label Shell
input.form-control(
type='text',
[ngbTypeahead]='shellAutocomplete',
'[(ngModel)]'='config.store.terminal.shell',
(ngModelChange)='config.save()',
)
.form-group .form-group
label Terminal bell label Terminal bell
br br

View file

@ -2,13 +2,14 @@ import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/map' import 'rxjs/add/operator/map'
import 'rxjs/add/operator/debounceTime' import 'rxjs/add/operator/debounceTime'
import 'rxjs/add/operator/distinctUntilChanged' import 'rxjs/add/operator/distinctUntilChanged'
import * as fs from 'fs-promise'
const fontManager = require('font-manager') const fontManager = require('font-manager')
const equal = require('deep-equal') const equal = require('deep-equal')
const { exec } = require('child-process-promise')
import { Component, Inject } from '@angular/core' import { Component, Inject } from '@angular/core'
import { ConfigService, HostAppService, Platform } from 'terminus-core' import { ConfigService, HostAppService, Platform } from 'terminus-core'
import { TerminalColorSchemeProvider, ITerminalColorScheme } from '../api' import { TerminalColorSchemeProvider, ITerminalColorScheme } from '../api'
const { exec } = require('child-process-promise')
@Component({ @Component({
@ -17,6 +18,7 @@ const { exec } = require('child-process-promise')
}) })
export class TerminalSettingsTabComponent { export class TerminalSettingsTabComponent {
fonts: string[] = [] fonts: string[] = []
shells: string[] = []
colorSchemes: ITerminalColorScheme[] = [] colorSchemes: ITerminalColorScheme[] = []
equalComparator = equal equalComparator = equal
editingColorScheme: ITerminalColorScheme editingColorScheme: ITerminalColorScheme
@ -43,6 +45,11 @@ export class TerminalSettingsTabComponent {
.map(x => x.split(',')[0].trim()) .map(x => x.split(',')[0].trim())
this.fonts.sort() this.fonts.sort()
}) })
this.shells = (await fs.readFile('/etc/shells', 'utf-8'))
.split('\n')
.map(x => x.trim())
.filter(x => x && !x.startsWith('#'))
} }
this.colorSchemes = (await Promise.all(this.colorSchemeProviders.map(x => x.getSchemes()))).reduce((a, b) => a.concat(b)) this.colorSchemes = (await Promise.all(this.colorSchemeProviders.map(x => x.getSchemes()))).reduce((a, b) => a.concat(b))
} }
@ -55,6 +62,10 @@ export class TerminalSettingsTabComponent {
.map(list => Array.from(new Set(list))) .map(list => Array.from(new Set(list)))
} }
shellAutocomplete = (text$: Observable<string>) => {
return text$.map(_ => ['auto'].concat(this.shells))
}
editScheme (scheme: ITerminalColorScheme) { editScheme (scheme: ITerminalColorScheme) {
this.editingColorScheme = scheme this.editingColorScheme = scheme
this.schemeChanged = false this.schemeChanged = false

View file

@ -9,7 +9,9 @@ export class TerminalConfigProvider extends ConfigProvider {
bell: 'off', bell: 'off',
bracketedPaste: true, bracketedPaste: true,
background: 'theme', background: 'theme',
shell: 'auto',
colorScheme: { colorScheme: {
__nonStructural: true,
foreground: null, foreground: null,
background: null, background: null,
cursor: null, cursor: null,