This commit is contained in:
Eugene Pankov 2017-05-01 13:35:26 +02:00
parent 8837173b1c
commit 889a60ba3b
62 changed files with 251 additions and 384 deletions

View file

@ -29,39 +29,6 @@ build-mac:
echo :: Building application
./node_modules/.bin/build --dir --mac --em.version=$(FULL_VERSION)
build-linux:
echo :: Building application
mkdir builtin-plugins || true
echo '{}' > builtin-plugins/package.json
cd builtin-plugins && for dir in $(builtin_plugins) ; do \
npm install ../$$dir; \
done
cd builtin-plugins && npm dedupe
./node_modules/.bin/electron-rebuild -f -m builtin-plugins -w node-pty,font-manager
./node_modules/.bin/build --linux --em.version=$(FULL_VERSION)
rm -r builtin-plugins || true
package-windows-app:
echo :: Building app MSI $(SHORT_VERSION)
heat dir dist/win-unpacked/ -cg Files -gg -scom -sreg -sfrag -srd -dr INSTALLDIR -var var.SourceDir -out build/files.wxs
candle -dSourceDir=dist\\win-unpacked -dProductVersion=$(SHORT_VERSION) -arch x64 -o dist/ build/files.wxs build/windows/elements.wxs
light -o dist/elements-app.msi dist/files.wixobj dist/elements.wixobj
build/windows/signtool.exe sign /f "build\\certificates\\Code Signing.p12" dist/elements-app.msi
package-windows-bundle:
echo :: Building installer
candle -dVersion=$(SHORT_VERSION) -ext WixBalExtension -arch x64 -o dist/build.wixobj build/windows/build.wxs
light -ext WixBalExtension -o bundle.exe dist/build.wixobj
insignia -ib bundle.exe -o engine.exe
build/windows/signtool.exe sign /f "build\\certificates\\Code Signing.p12" engine.exe
insignia -ab engine.exe bundle.exe -o dist/Elements-Electron.exe
build/windows/signtool.exe sign /f "build\\certificates\\Code Signing.p12" dist/Elements-Electron.exe
rm engine.exe bundle.exe || true
package-windows: build-windows package-windows-app package-windows-bundle
package-mac: driver-mac build-mac
rm -rf $(MAC_WS) || true

View file

@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
export async function getRootModule(plugins: any[]): Promise<any> {
export async function getRootModule (plugins: any[]): Promise<any> {
let imports = [
BrowserModule,
...(plugins.map(x => x.default.forRoot ? x.default.forRoot() : x.default)),
@ -12,7 +12,7 @@ export async function getRootModule(plugins: any[]): Promise<any> {
...(plugins.filter(x => x.bootstrap).map(x => x.bootstrap)),
]
if (bootstrap.length == 0) {
if (bootstrap.length === 0) {
throw new Error('Did not find any bootstrap components. Are there any plugins installed?')
}

View file

@ -1,5 +1,3 @@
(<any>console).timeStamp('entry point')
import 'core-js'
import 'zone.js/dist/zone.js'
import 'core-js/es7/reflect'
@ -14,7 +12,7 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { getRootModule } from './app.module'
import { findPlugins, loadPlugins } from './plugins'
if ((<any>global).require('electron-is-dev')) {
if (require('electron-is-dev')) {
console.warn('Running in debug mode')
} else {
enableProdMode()
@ -22,7 +20,7 @@ if ((<any>global).require('electron-is-dev')) {
findPlugins().then(async plugins => {
let pluginsModules = await loadPlugins(plugins, (current, total) => {
(<HTMLElement>document.querySelector('.progress .bar')).style.width = 100 * current / total + '%'
(document.querySelector('.progress .bar') as HTMLElement).style.width = 100 * current / total + '%'
})
let module = await getRootModule(pluginsModules)
platformBrowserDynamic().bootstrapModule(module)

View file

@ -1,6 +1,7 @@
import * as fs from 'fs-promise'
import * as path from 'path'
const nodeModule = (<any>global).require('module')
const nodeModule = require('module')
const nodeRequire = (global as any).require
function normalizePath (path: string): string {
const cygwinPrefix = '/cygdrive/'
@ -9,9 +10,9 @@ function normalizePath (path: string): string {
path = path[0] + ':' + path.substring(1)
}
return path
};
}
(<any>global).require.main.paths.map(x => nodeModule.globalPaths.push(normalizePath(x)))
nodeRequire.main.paths.map(x => nodeModule.globalPaths.push(normalizePath(x)))
if (process.env.DEV) {
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
@ -80,10 +81,10 @@ export async function loadPlugins (foundPlugins: IPluginEntry[], progress: Progr
progress(0, 1)
let index = 0
for (let foundPlugin of foundPlugins) {
console.info(`Loading ${foundPlugin.name}: ${(<any>global).require.resolve(foundPlugin.path)}`)
console.info(`Loading ${foundPlugin.name}: ${nodeRequire.resolve(foundPlugin.path)}`)
progress(index, foundPlugins.length)
try {
let pluginModule = (<any>global).require(foundPlugin.path)
let pluginModule = nodeRequire(foundPlugin.path)
plugins.push(pluginModule)
} catch (error) {
console.error(`Could not load ${foundPlugin.name}:`, error)

View file

@ -1,6 +1,5 @@
import { Component } from '@angular/core'
@Component({
template: '<app-root></app-root>'
})

View file

@ -27,12 +27,5 @@
"*/node_modules",
"terminus*",
"platforms"
],
"filesGlob" : [
"app/src/*.ts",
"app/src/**/*.ts",
"!node_modules/**",
"!app/node_modules/**",
"!*/node_modules/**"
]
}

View file

@ -57,6 +57,7 @@ module.exports = {
'@ng-bootstrap/ng-bootstrap': 'commonjs @ng-bootstrap/ng-bootstrap',
'fs-promise': 'commonjs fs-promise',
'electron': 'commonjs electron',
'electron-is-dev': 'commonjs electron-is-dev',
'module': 'commonjs module',
'path': 'commonjs path',
'rxjs': 'commonjs rxjs',

View file

@ -31,12 +31,12 @@
"source-sans-pro": "^2.0.10",
"style-loader": "^0.13.1",
"to-string-loader": "^1.1.5",
"tslint": "5.0.0",
"tslint-eslint-rules": "4.0.0",
"tslint": "^5.1.0",
"tslint-config-standard": "^5.0.2",
"tslint-eslint-rules": "^4.0.0",
"typescript": "~2.1.0",
"url-loader": "^0.5.7",
"val-loader": "^0.5.0",
"vrsource-tslint-rules": "^4.0.1",
"webpack": "2.4.1"
},
"build": {
@ -47,7 +47,6 @@
"builtin-plugins"
],
"win": {
"target": "zip",
"icon": "./app/assets/img/shortcut.ico"
},
"mac": {
@ -56,17 +55,15 @@
"identity": "Syslink GmbH"
},
"linux": {
"category": "Network",
"target": "AppImage",
"icon": "./app/assets/img/icon.png"
"category": "Utilities",
"icon": "./build/icons"
}
},
"scripts": {
"build": "webpack --progress --color",
"watch": "webpack --progress --color --watch",
"start": "cross-env DEV=1 electron app --debug",
"pack": "build --dir",
"postinstall": "install-app-deps",
"dist": "build"
"lint": "tslint -c tslint.json -t stylish terminus-*/src/**/*.ts terminus-*/src/*.ts app/src/*.ts",
"postinstall": "install-app-deps"
}
}

11
scripts/build-linux.js Executable file
View file

@ -0,0 +1,11 @@
#!/usr/bin/env node
const builder = require('electron-builder').build
const vars = require('./vars')
builder({
dir: true,
linux: ['appimage'],
extraMetadata: {
version: vars.version,
},
})

0
scripts/build-native.js Normal file → Executable file
View file

0
scripts/build-windows.js Normal file → Executable file
View file

0
scripts/install-deps.js Normal file → Executable file
View file

0
scripts/prepackage-plugins.js Normal file → Executable file
View file

0
scripts/vars.js Normal file → Executable file
View file

View file

@ -3,7 +3,6 @@ import { TerminalDecorator, TerminalTabComponent } from 'terminus-terminal'
import { LinkHandler } from './api'
@Injectable()
export class LinkHighlighterDecorator extends TerminalDecorator {
constructor (@Inject(LinkHandler) private handlers: LinkHandler[]) {
@ -21,17 +20,17 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
insertLinks (screen) {
if ('#text' === screen.cursorNode_.nodeName) {
// replace text node to element
const cursorNode = document.createElement('span');
cursorNode.textContent = screen.cursorNode_.textContent;
screen.cursorRowNode_.replaceChild(cursorNode, screen.cursorNode_);
screen.cursorNode_ = cursorNode;
const cursorNode = document.createElement('span')
cursorNode.textContent = screen.cursorNode_.textContent
screen.cursorRowNode_.replaceChild(cursorNode, screen.cursorNode_)
screen.cursorNode_ = cursorNode
}
const traverse = (parentNode: Node) => {
Array.from(parentNode.childNodes).forEach((node) => {
if (node.nodeName == '#text') {
if (node.nodeName === '#text') {
parentNode.replaceChild(this.urlizeNode(node), node)
} else if (node.nodeName != 'A') {
} else if (node.nodeName !== 'A') {
traverse(node)
}
})
@ -44,11 +43,14 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
let matches = []
this.handlers.forEach((handler) => {
let regex = new RegExp(handler.regex, 'gi')
let match
while (match = regex.exec(node.textContent)) {
while (true) {
let match = regex.exec(node.textContent)
if (!match) {
break
}
let uri = handler.convert(match[0])
if (!handler.verify(uri)) {
continue;
continue
}
matches.push({
start: regex.lastIndex - match[0].length,
@ -60,7 +62,7 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
}
})
if (matches.length == 0) {
if (matches.length === 0) {
return node
}

View file

@ -5,7 +5,6 @@ import { ElectronService } from 'terminus-core'
import { LinkHandler } from './api'
@Injectable()
export class URLHandler extends LinkHandler {
regex = 'http(s)?://[^\\s;\'"]+[^,;\\s]'

View file

@ -10,7 +10,6 @@ import { LinkHandler } from './api'
import { FileHandler, URLHandler } from './handlers'
import { LinkHighlighterDecorator } from './decorator'
@NgModule({
providers: [
{ provide: LinkHandler, useClass: FileHandler, multi: true },

View file

@ -3,14 +3,13 @@ import { TerminalColorSchemeProvider, ITerminalColorScheme } from 'terminus-term
const schemeContents = require.context('../schemes/', true, /.*/)
@Injectable()
export class ColorSchemes extends TerminalColorSchemeProvider {
async getSchemes (): Promise<ITerminalColorScheme[]> {
let schemes: ITerminalColorScheme[] = []
schemeContents.keys().forEach(schemeFile => {
let lines = (<string>schemeContents(schemeFile)).split('\n')
let lines = (schemeContents(schemeFile) as string).split('\n')
let values: any = {}
lines
.filter(x => x.startsWith('*.'))

View file

@ -3,7 +3,6 @@ import { TerminalColorSchemeProvider } from 'terminus-terminal'
import { ColorSchemes } from './colorSchemes'
@NgModule({
providers: [
{ provide: TerminalColorSchemeProvider, useClass: ColorSchemes, multi: true },

View file

@ -14,7 +14,6 @@ import { ThemesService } from '../services/themes.service'
import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
@Component({
selector: 'app-root',
template: require('./appRoot.component.pug'),
@ -46,7 +45,7 @@ export class AppRootComponent {
Platform = Platform
private logger: Logger
constructor(
constructor (
private docking: DockingService,
private electron: ElectronService,
private tabRecovery: TabRecoveryService,
@ -76,16 +75,16 @@ export class AppRootComponent {
}
}
if (this.app.activeTab) {
if (hotkey == 'close-tab') {
if (hotkey === 'close-tab') {
this.app.closeTab(this.app.activeTab)
}
if (hotkey == 'toggle-last-tab') {
if (hotkey === 'toggle-last-tab') {
this.app.toggleLastTab()
}
if (hotkey == 'next-tab') {
if (hotkey === 'next-tab') {
this.app.nextTab()
}
if (hotkey == 'previous-tab') {
if (hotkey === 'previous-tab') {
this.app.previousTab()
}
}
@ -113,7 +112,7 @@ export class AppRootComponent {
// unfocused, invisible
this.electron.app.window.show()
} else {
if (this.config.store.appearance.dock == 'off') {
if (this.config.store.appearance.dock === 'off') {
// not docked, visible
setTimeout(() => {
this.electron.app.window.focus()
@ -134,7 +133,7 @@ export class AppRootComponent {
await this.tabRecovery.recoverTabs()
this.tabRecovery.saveTabs(this.app.tabs)
if (this.app.tabs.length == 0) {
if (this.app.tabs.length === 0) {
this.app.openDefaultTab()
}
}

View file

@ -1,8 +1,8 @@
import { Subject, BehaviorSubject } from 'rxjs'
import { ViewRef } from '@angular/core'
export abstract class BaseTabComponent {
private static lastTabID = 0
id: number
title$ = new BehaviorSubject<string>(null)
scrollable: boolean
@ -11,7 +11,6 @@ export abstract class BaseTabComponent {
blurred$ = new Subject<void>()
hasFocus = false
hostView: ViewRef
private static lastTabID = 0
constructor () {
this.id = BaseTabComponent.lastTabID++

View file

@ -3,12 +3,12 @@ import { ElectronService } from '../services/electron.service'
import { IToolbarButton, ToolbarButtonProvider } from '../api'
@Component({
selector: 'start-page',
template: require('./startPage.component.pug'),
styles: [require('./startPage.component.scss')],
selector: 'start-page',
template: require('./startPage.component.pug'),
styles: [require('./startPage.component.scss')],
})
export class StartPageComponent {
constructor(
constructor (
private electron: ElectronService,
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
) { }

View file

@ -2,9 +2,9 @@ import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/co
import { BaseTabComponent } from '../components/baseTab.component'
@Component({
selector: 'tab-header',
template: require('./tabHeader.component.pug'),
styles: [require('./tabHeader.component.scss')],
selector: 'tab-header',
template: require('./tabHeader.component.pug'),
styles: [require('./tabHeader.component.scss')],
})
export class TabHeaderComponent {
@Input() index: number

View file

@ -1,9 +1,8 @@
import { Component } from '@angular/core'
@Component({
selector: 'title-bar',
template: require('./titleBar.component.pug'),
styles: [require('./titleBar.component.scss')],
selector: 'title-bar',
template: require('./titleBar.component.pug'),
styles: [require('./titleBar.component.scss')],
})
export class TitleBarComponent {
}
export class TitleBarComponent { }

View file

@ -1,7 +1,6 @@
import { ConfigProvider } from './api/configProvider'
import { Platform } from './services/hostApp.service'
export class CoreConfigProvider extends ConfigProvider {
platformDefaults = {
[Platform.macOS]: require('./configDefaults.macos.yaml'),

View file

@ -13,7 +13,6 @@ import { HostAppService } from './services/hostApp.service'
import { LogService } from './services/log.service'
import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
import { NotifyService } from './services/notify.service'
import { PluginsService } from './services/plugins.service'
import { QuitterService } from './services/quitter.service'
import { DockingService } from './services/docking.service'
import { TabRecoveryService } from './services/tabRecovery.service'
@ -43,7 +42,6 @@ const PROVIDERS = [
HotkeysService,
LogService,
NotifyService,
PluginsService,
TabRecoveryService,
ThemesService,
QuitterService,
@ -52,7 +50,6 @@ const PROVIDERS = [
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
]
@NgModule({
imports: [
BrowserModule,
@ -73,7 +70,7 @@ const PROVIDERS = [
],
})
export default class AppModule {
static forRoot(): ModuleWithProviders {
static forRoot (): ModuleWithProviders {
return {
ngModule: AppModule,
providers: PROVIDERS,

View file

@ -6,7 +6,6 @@ import { Logger, LogService } from '../services/log.service'
export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
@Injectable()
export class AppService {
tabs: BaseTabComponent[] = []
@ -44,7 +43,7 @@ export class AppService {
}
selectTab (tab: BaseTabComponent) {
if (this.activeTab == tab) {
if (this.activeTab === tab) {
return
}
if (this.tabs.includes(this.activeTab)) {
@ -85,12 +84,9 @@ export class AppService {
closeTab (tab: BaseTabComponent) {
tab.destroy()
/* if (tab.session) {
this.sessions.destroySession(tab.session)
} */
let newIndex = Math.max(0, this.tabs.indexOf(tab) - 1)
this.tabs = this.tabs.filter((x) => x != tab)
if (tab == this.activeTab) {
this.tabs = this.tabs.filter((x) => x !== tab)
if (tab === this.activeTab) {
this.selectTab(this.tabs[newIndex])
}
this.tabsChanged$.next()

View file

@ -6,6 +6,7 @@ import { ConfigProvider } from '../api/configProvider'
import { ElectronService } from './electron.service'
import { HostAppService } from './hostApp.service'
const configMerge = (a, b) => require('deepmerge')(a, b, { arrayMerge: (_d, s) => s })
export class ConfigProxy {
constructor (real: any, defaults: any) {
@ -47,10 +48,6 @@ export class ConfigProxy {
}
}
const configMerge = (a, b) => require('deepmerge')(a, b, { arrayMerge: (_d, s) => s })
@Injectable()
export class ConfigService {
store: any

View file

@ -3,7 +3,6 @@ import { ConfigService } from '../services/config.service'
import { ElectronService } from '../services/electron.service'
import { HostAppService } from '../services/hostApp.service'
export interface IScreen {
id: string
name: string
@ -11,7 +10,7 @@ export interface IScreen {
@Injectable()
export class DockingService {
constructor(
constructor (
private electron: ElectronService,
private config: ConfigService,
private hostApp: HostAppService,
@ -19,7 +18,7 @@ export class DockingService {
dock () {
let display = this.electron.screen.getAllDisplays()
.filter((x) => x.id == this.config.store.appearance.dockScreen)[0]
.filter((x) => x.id === this.config.store.appearance.dockScreen)[0]
if (!display) {
display = this.getCurrentScreen()
}
@ -28,31 +27,30 @@ export class DockingService {
let newBounds: Electron.Rectangle = { x: 0, y: 0, width: 0, height: 0 }
let fill = this.config.store.appearance.dockFill
if (dockSide == 'off') {
if (dockSide === 'off') {
this.hostApp.setAlwaysOnTop(false)
return
}
if (dockSide == 'left' || dockSide == 'right') {
if (dockSide === 'left' || dockSide === 'right') {
newBounds.width = Math.round(fill * display.bounds.width)
newBounds.height = display.bounds.height
}
if (dockSide == 'top' || dockSide == 'bottom') {
if (dockSide === 'top' || dockSide === 'bottom') {
newBounds.width = display.bounds.width
newBounds.height = Math.round(fill * display.bounds.height)
}
if (dockSide == 'right') {
if (dockSide === 'right') {
newBounds.x = display.bounds.x + display.bounds.width * (1.0 - fill)
} else {
newBounds.x = display.bounds.x
}
if (dockSide == 'bottom') {
if (dockSide === 'bottom') {
newBounds.y = display.bounds.y + display.bounds.height * (1.0 - fill)
} else {
newBounds.y = display.bounds.y
}
this.hostApp.setAlwaysOnTop(true)
//this.hostApp.unmaximize()
setImmediate(() => {
this.hostApp.setBounds(newBounds)
})

View file

@ -2,15 +2,17 @@ import { Injectable } from '@angular/core'
@Injectable()
export class ElectronService {
constructor() {
if (process.env.TEST_ENV) {
this.initTest()
} else {
this.init()
}
}
app: any
ipcRenderer: any
shell: any
dialog: any
clipboard: any
globalShortcut: any
screen: any
private electron: any
private remoteElectron: any
init() {
constructor () {
this.electron = require('electron')
this.remoteElectron = this.remoteRequire('electron')
this.app = this.remoteElectron.app
@ -22,21 +24,7 @@ export class ElectronService {
this.globalShortcut = this.remoteElectron.globalShortcut
}
initTest() {
;
}
remoteRequire(name: string): any {
remoteRequire (name: string): any {
return this.electron.remote.require(name)
}
app: any
ipcRenderer: any
shell: any
dialog: any
clipboard: any
globalShortcut: any
screen: any
private electron: any
private remoteElectron: any
}

View file

@ -6,13 +6,18 @@ export enum Platform {
Linux, macOS, Windows,
}
@Injectable()
export class HostAppService {
platform: Platform
nodePlatform: string
quitRequested = new EventEmitter<any>()
ready = new EventEmitter<any>()
shown = new EventEmitter<any>()
secondInstance = new EventEmitter<any>()
constructor(
private logger: Logger
constructor (
private zone: NgZone,
private electron: ElectronService,
log: LogService,
@ -27,7 +32,7 @@ export class HostAppService {
electron.ipcRenderer.on('host:quit-request', () => this.zone.run(() => this.quitRequested.emit()))
electron.ipcRenderer.on('uncaughtException', function(err) {
electron.ipcRenderer.on('uncaughtException', (err) => {
this.logger.error('Unhandled exception:', err)
})
@ -44,13 +49,6 @@ export class HostAppService {
})
}
quitRequested = new EventEmitter<any>()
ready = new EventEmitter<any>()
shown = new EventEmitter<any>()
secondInstance = new EventEmitter<any>()
private logger: Logger;
getWindow () {
return this.electron.app.window
}
@ -63,23 +61,23 @@ export class HostAppService {
return this.electron.app.getAppPath()
}
getPath(type: string) {
getPath (type: string) {
return this.electron.app.getPath(type)
}
openDevTools() {
openDevTools () {
this.getWindow().webContents.openDevTools()
}
setCloseable(flag: boolean) {
setCloseable (flag: boolean) {
this.electron.ipcRenderer.send('window-set-closeable', flag)
}
focusWindow() {
focusWindow () {
this.electron.ipcRenderer.send('window-focus')
}
toggleWindow() {
toggleWindow () {
this.electron.ipcRenderer.send('window-toggle-focus')
}

View file

@ -4,7 +4,6 @@ import { NativeKeyEvent, stringifyKeySequence } from './hotkeys.util'
import { ConfigService } from '../services/config.service'
import { ElectronService } from '../services/electron.service'
export interface PartialHotkeyMatch {
id: string,
strokes: string[],
@ -27,7 +26,7 @@ export class HotkeysService {
private disabledLevel = 0
private hotkeyDescriptions: IHotkeyDescription[]
constructor(
constructor (
private zone: NgZone,
private electron: ElectronService,
private config: ConfigService,
@ -36,7 +35,7 @@ export class HotkeysService {
let events = ['keydown', 'keyup']
events.forEach((event) => {
document.addEventListener(event, (nativeEvent) => {
if (document.querySelectorAll('input:focus').length == 0) {
if (document.querySelectorAll('input:focus').length === 0) {
this.pushKeystroke(event, nativeEvent)
this.processKeystrokes()
this.emitKeyEvent(nativeEvent)
@ -78,7 +77,7 @@ export class HotkeysService {
this.currentKeystrokes = []
}
getCurrentKeystrokes () : string[] {
getCurrentKeystrokes (): string[] {
this.currentKeystrokes = this.currentKeystrokes.filter((x) => performance.now() - x.time < KEY_TIMEOUT )
return stringifyKeySequence(this.currentKeystrokes.map((x) => x.event))
}
@ -86,11 +85,11 @@ export class HotkeysService {
registerGlobalHotkey () {
this.electron.globalShortcut.unregisterAll()
let value = this.config.store.hotkeys['toggle-window']
if (typeof value == 'string') {
if (typeof value === 'string') {
value = [value]
}
value.forEach(item => {
item = (typeof item == 'string') ? [item] : item
item = (typeof item === 'string') ? [item] : item
this.electron.globalShortcut.register(item[0].replace(/-/g, '+'), () => {
this.globalHotkey.emit()
@ -102,16 +101,16 @@ export class HotkeysService {
let keys = {}
for (let key in this.config.store.hotkeys) {
let value = this.config.store.hotkeys[key]
if (typeof value == 'string') {
if (typeof value === 'string') {
value = [value]
}
value = value.map((item) => (typeof item == 'string') ? [item] : item)
value = value.map((item) => (typeof item === 'string') ? [item] : item)
keys[key] = value
}
return keys
}
getCurrentFullyMatchedHotkey () : string {
getCurrentFullyMatchedHotkey (): string {
for (let id in this.getHotkeysConfig()) {
for (let sequence of this.getHotkeysConfig()[id]) {
let currentStrokes = this.getCurrentKeystrokes()
@ -119,7 +118,7 @@ export class HotkeysService {
break
}
if (sequence.every((x, index) => {
return x.toLowerCase() == currentStrokes[currentStrokes.length - sequence.length + index].toLowerCase()
return x.toLowerCase() === currentStrokes[currentStrokes.length - sequence.length + index].toLowerCase()
})) {
return id
}
@ -128,16 +127,15 @@ export class HotkeysService {
return null
}
getCurrentPartiallyMatchedHotkeys () : PartialHotkeyMatch[] {
getCurrentPartiallyMatchedHotkeys (): PartialHotkeyMatch[] {
let result = []
for (let id in this.getHotkeysConfig()) {
for (let sequence of this.getHotkeysConfig()[id]) {
let currentStrokes = this.getCurrentKeystrokes()
for (let matchLength = Math.min(currentStrokes.length, sequence.length); matchLength > 0; matchLength--) {
//console.log(sequence, currentStrokes.slice(currentStrokes.length - sequence.length))
if (sequence.slice(0, matchLength).every((x, index) => {
return x.toLowerCase() == currentStrokes[currentStrokes.length - matchLength + index].toLowerCase()
return x.toLowerCase() === currentStrokes[currentStrokes.length - matchLength + index].toLowerCase()
})) {
result.push({
matchedLength: matchLength,
@ -152,8 +150,8 @@ export class HotkeysService {
return result
}
getHotkeyDescription (id: string) : IHotkeyDescription {
return this.hotkeyDescriptions.filter((x) => x.id == id)[0]
getHotkeyDescription (id: string): IHotkeyDescription {
return this.hotkeyDescriptions.filter((x) => x.id === id)[0]
}
enable () {
@ -165,12 +163,10 @@ export class HotkeysService {
}
isEnabled () {
return this.disabledLevel == 0
return this.disabledLevel === 0
}
}
@Injectable()
export class AppHotkeyProvider extends HotkeyProvider {
hotkeys: IHotkeyDescription[] = [

View file

@ -1,18 +1,14 @@
import * as os from 'os'
export const metaKeyName = {
darwin: '⌘',
win32: 'Win',
linux: 'Super',
}[os.platform()]
}[process.platform]
export const altKeyName = {
darwin: 'Option',
win32: 'Alt',
linux: 'Alt',
}[os.platform()]
}[process.platform]
export interface NativeKeyEvent {
event?: string,
@ -24,14 +20,13 @@ export interface NativeKeyEvent {
keyCode: string,
}
export function stringifyKeySequence(events: NativeKeyEvent[]): string[] {
export function stringifyKeySequence (events: NativeKeyEvent[]): string[] {
let items: string[] = []
events = events.slice()
while (events.length > 0) {
let event = events.shift()
if (event.event == 'keydown') {
if (event.event === 'keydown') {
let itemKeys: string[] = []
if (event.ctrlKey) {
itemKeys.push('Ctrl')
@ -50,7 +45,7 @@ export function stringifyKeySequence(events: NativeKeyEvent[]): string[] {
// TODO make this optional?
continue
}
if (event.key.length == 1) {
if (event.key.length === 1) {
itemKeys.push(event.key.toUpperCase())
} else {
itemKeys.push(event.key)

View file

@ -1,8 +1,7 @@
import { Injectable } from '@angular/core'
export class Logger {
constructor(
constructor (
private name: string,
) {}
@ -10,10 +9,10 @@ export class Logger {
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
}
debug(...args: any[]) { this.log('debug', ...args) }
info(...args: any[]) { this.log('info', ...args) }
warn(...args: any[]) { this.log('warn', ...args) }
error(...args: any[]) { this.log('error', ...args) }
debug (...args: any[]) { this.log('debug', ...args) }
info (...args: any[]) { this.log('info', ...args) }
warn (...args: any[]) { this.log('warn', ...args) }
error (...args: any[]) { this.log('error', ...args) }
}
@Injectable()

View file

@ -1,18 +1,17 @@
import { Injectable } from '@angular/core'
import { ToasterService } from 'angular2-toaster'
@Injectable()
export class NotifyService {
constructor(
constructor (
private toaster: ToasterService,
) {}
pop(options) {
pop (options) {
this.toaster.pop(options)
}
info(title: string, body: string = null) {
info (title: string, body: string = null) {
return this.pop({
type: 'info',
title, body,
@ -20,7 +19,7 @@ export class NotifyService {
})
}
success(title: string, body: string = null) {
success (title: string, body: string = null) {
return this.pop({
type: 'success',
title, body,
@ -28,7 +27,7 @@ export class NotifyService {
})
}
warning(title: string, body: string = null) {
warning (title: string, body: string = null) {
return this.pop({
type: 'warning',
title, body,
@ -36,7 +35,7 @@ export class NotifyService {
})
}
error(title: string, body: string = null) {
error (title: string, body: string = null) {
return this.pop({
type: 'error',
title, body,

View file

@ -1,21 +0,0 @@
import { Injectable } from '@angular/core'
class Plugin {
ngModule: any
name: string
}
@Injectable()
export class PluginsService {
plugins: Plugin[] = []
register (plugin: Plugin): void {
this.plugins.push(plugin)
}
getModules (): any[] {
return this.plugins.map((plugin) => plugin.ngModule)
}
}

View file

@ -1,10 +1,9 @@
import { Injectable } from '@angular/core'
import { HostAppService } from '../services/hostApp.service'
@Injectable()
export class QuitterService {
constructor(
constructor (
private hostApp: HostAppService,
) {
hostApp.quitRequested.subscribe(() => {
@ -12,7 +11,7 @@ export class QuitterService {
})
}
quit() {
quit () {
this.hostApp.setCloseable(true)
this.hostApp.quit()
}

View file

@ -4,12 +4,11 @@ import { BaseTabComponent } from '../components/baseTab.component'
import { Logger, LogService } from '../services/log.service'
import { AppService } from '../services/app.service'
@Injectable()
export class TabRecoveryService {
logger: Logger
constructor(
constructor (
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
app: AppService,
log: LogService

View file

@ -2,7 +2,6 @@ import { Inject, Injectable } from '@angular/core'
import { ConfigService } from '../services/config.service'
import { Theme } from '../api/theme'
@Injectable()
export class ThemesService {
private styleElement: HTMLElement = null

View file

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core'
import { Theme } from './api'
@Injectable()
export class StandardTheme extends Theme {
name = 'Standard'

View file

@ -3,7 +3,6 @@ import { ToolbarButtonProvider, IToolbarButton, AppService } from 'terminus-core
import { SettingsTabComponent } from './components/settingsTab.component'
@Injectable()
export class ButtonProvider extends ToolbarButtonProvider {
constructor (

View file

@ -5,45 +5,44 @@ import { HotkeysService } from 'terminus-core'
const INPUT_TIMEOUT = 1000
@Component({
selector: 'hotkey-input-modal',
template: require('./hotkeyInputModal.component.pug'),
styles: [require('./hotkeyInputModal.component.scss')],
animations: [
trigger('animateKey', [
transition(':enter', [
style({
transform: 'translateX(25px)',
opacity: '0',
}),
animate('250ms ease-out', style({
transform: 'translateX(0)',
opacity: '1',
}))
]),
transition(':leave', [
style({
transform: 'translateX(0)',
opacity: '1',
}),
animate('250ms ease-in', style({
transform: 'translateX(25px)',
opacity: '0',
}))
])
])
]
selector: 'hotkey-input-modal',
template: require('./hotkeyInputModal.component.pug'),
styles: [require('./hotkeyInputModal.component.scss')],
animations: [
trigger('animateKey', [
transition(':enter', [
style({
transform: 'translateX(25px)',
opacity: '0',
}),
animate('250ms ease-out', style({
transform: 'translateX(0)',
opacity: '1',
}))
]),
transition(':leave', [
style({
transform: 'translateX(0)',
opacity: '1',
}),
animate('250ms ease-in', style({
transform: 'translateX(25px)',
opacity: '0',
}))
])
])
]
})
export class HotkeyInputModalComponent {
@Input() value: string[] = []
@Input() timeoutProgress = 0
private keySubscription: Subscription
private lastKeyEvent: number
private keyTimeoutInterval: number = null
@Input() value: string[] = []
@Input() timeoutProgress = 0
constructor(
constructor (
private modalInstance: NgbActiveModal,
public hotkeys: HotkeysService,
) {
@ -66,7 +65,7 @@ export class HotkeyInputModalComponent {
return
}
this.timeoutProgress = Math.min(100, (performance.now() - this.lastKeyEvent) * 100 / INPUT_TIMEOUT)
if (this.timeoutProgress == 100) {
if (this.timeoutProgress === 100) {
this.modalInstance.close(this.value)
}
}, 25)
@ -78,7 +77,7 @@ export class HotkeyInputModalComponent {
clearInterval(this.keyTimeoutInterval)
}
close() {
close () {
this.modalInstance.dismiss()
}
}

View file

@ -2,14 +2,16 @@ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
@Component({
selector: 'multi-hotkey-input',
template: require('./multiHotkeyInput.component.pug'),
styles: [require('./multiHotkeyInput.component.scss')],
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'multi-hotkey-input',
template: require('./multiHotkeyInput.component.pug'),
styles: [require('./multiHotkeyInput.component.scss')],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MultiHotkeyInputComponent {
@Input() model: string[][]
@Output() modelChange = new EventEmitter()
constructor (
private ngbModal: NgbModal,
) { }
@ -18,10 +20,10 @@ export class MultiHotkeyInputComponent {
if (!this.model) {
this.model = []
}
if (typeof this.model == 'string') {
if (typeof this.model === 'string') {
this.model = [this.model]
}
this.model = this.model.map(item => (typeof item == 'string') ? [item] : item)
this.model = this.model.map(item => (typeof item === 'string') ? [item] : item)
}
editItem (item) {
@ -43,7 +45,4 @@ export class MultiHotkeyInputComponent {
this.model = this.model.filter(x => x !== item)
this.modelChange.emit(this.model)
}
@Input() model: string[][]
@Output() modelChange = new EventEmitter()
}

View file

@ -3,20 +3,19 @@ import { ElectronService, DockingService, ConfigService, IHotkeyDescription, Hot
import { SettingsTabProvider } from '../api'
@Component({
selector: 'settings-tab',
template: require('./settingsTab.component.pug'),
styles: [
require('./settingsTab.component.scss'),
require('./settingsTab.deep.component.css'),
],
selector: 'settings-tab',
template: require('./settingsTab.component.pug'),
styles: [
require('./settingsTab.component.scss'),
require('./settingsTab.deep.component.css'),
],
})
export class SettingsTabComponent extends BaseTabComponent {
hotkeyFilter = { name: null }
private hotkeyDescriptions: IHotkeyDescription[]
constructor(
constructor (
public config: ConfigService,
private electron: ElectronService,
public docking: DockingService,

View file

@ -1,10 +1,9 @@
import { Component, Input, ViewContainerRef, ViewChild, ComponentFactoryResolver, ComponentRef } from '@angular/core'
import { SettingsTabProvider } from '../api'
@Component({
selector: 'settings-tab-body',
template: '<ng-template #placeholder></ng-template>',
selector: 'settings-tab-body',
template: '<ng-template #placeholder></ng-template>',
})
export class SettingsTabBodyComponent {
@Input() provider: SettingsTabProvider

View file

@ -14,7 +14,6 @@ import { SettingsTabBodyComponent } from './components/settingsTabBody.component
import { ButtonProvider } from './buttonProvider'
import { RecoveryProvider } from './recoveryProvider'
@NgModule({
imports: [
BrowserModule,

View file

@ -3,17 +3,16 @@ import { TabRecoveryProvider, AppService } from 'terminus-core'
import { SettingsTabComponent } from './components/settingsTab.component'
@Injectable()
export class RecoveryProvider extends TabRecoveryProvider {
constructor(
constructor (
private app: AppService
) {
super()
}
async recover (recoveryToken: any): Promise<void> {
if (recoveryToken.type == 'app:settings') {
if (recoveryToken.type === 'app:settings') {
this.app.openNewTab(SettingsTabComponent)
}
}

View file

@ -3,7 +3,9 @@ import { TerminalTabComponent } from './components/terminalTab.component'
export { TerminalTabComponent }
export abstract class TerminalDecorator {
// tslint:disable-next-line no-empty
attach (_terminal: TerminalTabComponent): void { }
// tslint:disable-next-line no-empty
detach (_terminal: TerminalTabComponent): void { }
}

View file

@ -4,7 +4,6 @@ import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, Conf
import { SessionsService } from './services/sessions.service'
import { TerminalTabComponent } from './components/terminalTab.component'
@Injectable()
export class ButtonProvider extends ToolbarButtonProvider {
constructor (
@ -15,7 +14,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
) {
super()
hotkeys.matchedHotkey.subscribe(async (hotkey) => {
if (hotkey == 'new-tab') {
if (hotkey === 'new-tab') {
this.openNewTab()
}
})

View file

@ -3,7 +3,6 @@ import * as path from 'path'
import { Injectable } from '@angular/core'
import { TerminalColorSchemeProvider, ITerminalColorScheme } from './api'
@Injectable()
export class HyperColorSchemes extends TerminalColorSchemeProvider {
async getSchemes (): Promise<ITerminalColorScheme[]> {
@ -14,7 +13,7 @@ export class HyperColorSchemes extends TerminalColorSchemeProvider {
let themes: ITerminalColorScheme[] = []
plugins.forEach(plugin => {
let module = (<any>global).require(path.join(pluginsPath, plugin))
let module = (global as any).require(path.join(pluginsPath, plugin))
if (module.decorateConfig) {
let config = module.decorateConfig({})
if (config.colors) {

View file

@ -1,7 +1,6 @@
import { Component, Input, Output, EventEmitter, HostListener, ViewChild } from '@angular/core'
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'
@Component({
selector: 'color-picker',
template: require('./colorPicker.component.pug'),
@ -29,7 +28,7 @@ export class ColorPickerComponent {
if (!this.isOpen) {
return
}
let windowRef = (<any>this.popover)._windowRef
let windowRef = (this.popover as any)._windowRef
if (!windowRef) {
return
}

View file

@ -12,7 +12,7 @@ import { TerminalColorSchemeProvider, ITerminalColorScheme } from '../api'
let Registry = null
try {
Registry = require('winreg')
} catch (_) { }
} catch (_) { } // tslint:disable-line no-empty
interface IShell {
name: string
@ -31,19 +31,19 @@ export class TerminalSettingsTabComponent {
editingColorScheme: ITerminalColorScheme
schemeChanged = false
constructor(
constructor (
public config: ConfigService,
private hostApp: HostAppService,
@Inject(TerminalColorSchemeProvider) private colorSchemeProviders: TerminalColorSchemeProvider[],
) { }
async ngOnInit () {
if (this.hostApp.platform == Platform.Windows || this.hostApp.platform == Platform.macOS) {
if (this.hostApp.platform === Platform.Windows || this.hostApp.platform === Platform.macOS) {
let fonts = await new Promise<any[]>((resolve) => fontManager.findFonts({ monospace: true }, resolve))
this.fonts = fonts.map(x => x.family)
this.fonts.sort()
}
if (this.hostApp.platform == Platform.Linux) {
if (this.hostApp.platform === Platform.Linux) {
exec('fc-list :spacing=mono').then(([stdout, _]) => {
this.fonts = stdout.toString()
.split('\n')
@ -53,18 +53,18 @@ export class TerminalSettingsTabComponent {
this.fonts.sort()
})
}
if (this.hostApp.platform == Platform.Windows) {
if (this.hostApp.platform === Platform.Windows) {
this.shells = [
{ name: 'CMD', command: 'cmd.exe' },
{ name: 'PowerShell', command: 'powershell.exe' },
]
const wslPath =`${process.env.windir}\\system32\\bash.exe`
const wslPath = `${process.env.windir}\\system32\\bash.exe`
if (await fs.exists(wslPath)) {
this.shells.push({ name: 'Bash on Windows', command: wslPath })
}
let cygwinPath = await new Promise<string>(resolve => {
let reg = new Registry({ hive: Registry.HKLM, key: "\\Software\\Cygwin\\setup" })
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup' })
reg.get('rootdir', (err, item) => {
if (err) {
resolve(null)
@ -76,7 +76,7 @@ export class TerminalSettingsTabComponent {
this.shells.push({ name: 'Cygwin', command: path.join(cygwinPath, 'bin', 'bash.exe') })
}
}
if (this.hostApp.platform == Platform.Linux || this.hostApp.platform == Platform.macOS) {
if (this.hostApp.platform === Platform.Linux || this.hostApp.platform === Platform.macOS) {
this.shells = (await fs.readFile('/etc/shells', 'utf-8'))
.split('\n')
.map(x => x.trim())

View file

@ -7,13 +7,15 @@ import { Session } from '../services/sessions.service'
import { TerminalDecorator, ResizeEvent } from '../api'
import { hterm, preferenceManager } from '../hterm'
@Component({
selector: 'terminalTab',
template: '<div #content class="content" [style.opacity]="htermVisible ? 1 : 0"></div>',
styles: [require('./terminalTab.component.scss')],
selector: 'terminalTab',
template: '<div #content class="content" [style.opacity]="htermVisible ? 1 : 0"></div>',
styles: [require('./terminalTab.component.scss')],
})
export class TerminalTabComponent extends BaseTabComponent {
@Input() session: Session
@ViewChild('content') content
@HostBinding('style.background-color') backgroundColor: string
hterm: any
configSubscription: Subscription
sessionCloseSubscription: Subscription
@ -25,12 +27,9 @@ export class TerminalTabComponent extends BaseTabComponent {
alternateScreenActive$ = new BehaviorSubject(false)
mouseEvent$ = new Subject<Event>()
htermVisible = false
@Input() session: Session
@ViewChild('content') content
@HostBinding('style.background-color') backgroundColor: string
private io: any
constructor(
constructor (
private zone: NgZone,
private app: AppService,
private themes: ThemesService,
@ -92,7 +91,7 @@ export class TerminalTabComponent extends BaseTabComponent {
}, 1000)
this.bell$.subscribe(() => {
if (this.config.store.terminal.bell != 'off') {
if (this.config.store.terminal.bell !== 'off') {
let bg = preferenceManager.get('background-color')
preferenceManager.set('background-color', 'rgba(128,128,128,.25)')
setTimeout(() => {
@ -116,10 +115,10 @@ export class TerminalTabComponent extends BaseTabComponent {
this.alternateScreenActive$.next(state)
}
const _onPaste_ = hterm.scrollPort_.onPaste_.bind(hterm.scrollPort_)
const _onPaste = hterm.scrollPort_.onPaste_.bind(hterm.scrollPort_)
hterm.scrollPort_.onPaste_ = (event) => {
hterm.scrollPort_.pasteTarget_.value = event.clipboardData.getData('text/plain').trim()
_onPaste_()
_onPaste()
event.preventDefault()
}
@ -131,7 +130,7 @@ export class TerminalTabComponent extends BaseTabComponent {
_resize()
}
const _onMouse_ = hterm.onMouse_.bind(hterm)
const _onMouse = hterm.onMouse_.bind(hterm)
hterm.onMouse_ = (event) => {
this.mouseEvent$.next(event)
if ((event.ctrlKey || event.metaKey) && event.type === 'mousewheel') {
@ -139,7 +138,7 @@ export class TerminalTabComponent extends BaseTabComponent {
let delta = Math.round(event.wheelDeltaY / 50)
this.sendInput(((delta > 0) ? '\u001bOA' : '\u001bOB').repeat(Math.abs(delta)))
}
_onMouse_(event)
_onMouse(event)
}
hterm.ringBell = () => {
@ -192,18 +191,18 @@ export class TerminalTabComponent extends BaseTabComponent {
preferenceManager.set('font-size', config.terminal.fontSize)
preferenceManager.set('enable-bold', true)
preferenceManager.set('audible-bell-sound', '')
preferenceManager.set('desktop-notification-bell', config.terminal.bell == 'notification')
preferenceManager.set('desktop-notification-bell', config.terminal.bell === 'notification')
preferenceManager.set('enable-clipboard-notice', false)
preferenceManager.set('receive-encoding', 'raw')
preferenceManager.set('send-encoding', 'raw')
preferenceManager.set('ctrl-plus-minus-zero-zoom', false)
preferenceManager.set('scrollbar-visible', this.hostApp.platform == Platform.macOS)
preferenceManager.set('scrollbar-visible', this.hostApp.platform === Platform.macOS)
preferenceManager.set('copy-on-select', false)
if (config.terminal.colorScheme.foreground) {
preferenceManager.set('foreground-color', config.terminal.colorScheme.foreground)
}
if (config.terminal.background == 'colorScheme') {
if (config.terminal.background === 'colorScheme') {
if (config.terminal.colorScheme.background) {
this.backgroundColor = config.terminal.colorScheme.background
preferenceManager.set('background-color', config.terminal.colorScheme.background)

View file

@ -1,6 +1,5 @@
import { ConfigProvider, Platform } from 'terminus-core'
export class TerminalConfigProvider extends ConfigProvider {
defaults = {
terminal: {

View file

@ -3,12 +3,11 @@ export const hterm = require('hterm-commonjs')
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
export const preferenceManager = new hterm.hterm.PreferenceManager('default')
hterm.hterm.VT.ESC['k'] = function (parseState) {
parseState.resetArguments()
hterm.hterm.VT.ESC['k'] = function(parseState) {
parseState.resetArguments();
function parseOSC(ps) {
if (!this.parseUntilStringTerminator_(ps) || ps.func == parseOSC) {
function parseOSC (ps) {
if (!this.parseUntilStringTerminator_(ps) || ps.func === parseOSC) {
return
}

View file

@ -21,7 +21,6 @@ import { TerminalConfigProvider } from './config'
import { HyperColorSchemes } from './colorSchemes'
import { hterm } from './hterm'
@NgModule({
imports: [
BrowserModule,
@ -36,10 +35,10 @@ import { hterm } from './hterm'
{
provide: SessionPersistenceProvider,
useFactory: (hostApp: HostAppService, screen: ScreenPersistenceProvider) => {
if (hostApp.platform == Platform.Windows) {
return null
if (hostApp.platform === Platform.Windows) {
return null
} else {
return screen
return screen
}
},
deps: [HostAppService, ScreenPersistenceProvider],
@ -74,7 +73,7 @@ export default class TerminalModule {
let oldHandler = hterm.hterm.Keyboard.prototype[event.htermHandler]
hterm.hterm.Keyboard.prototype[event.htermHandler] = function (nativeEvent) {
hotkeys.pushKeystroke(event.name, nativeEvent)
if (hotkeys.getCurrentPartiallyMatchedHotkeys().length == 0) {
if (hotkeys.getCurrentPartiallyMatchedHotkeys().length === 0) {
oldHandler.bind(this)(nativeEvent)
} else {
nativeEvent.stopPropagation()

View file

@ -7,7 +7,6 @@ import { Injectable } from '@angular/core'
import { Logger, LogService } from 'terminus-core'
import { SessionOptions, SessionPersistenceProvider } from './api'
interface IChildProcess {
pid: number
ppid: number
@ -52,16 +51,16 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
return null
}
let truePID_ = new AsyncSubject<number>()
let truePID$ = new AsyncSubject<number>()
this.extractShellPID(screenPID).then(pid => {
truePID_.next(pid)
truePID_.complete()
truePID$.next(pid)
truePID$.complete()
})
return {
recoveryId,
recoveredTruePID$: truePID_.asObservable(),
recoveredTruePID$: truePID$.asObservable(),
command: 'screen',
args: ['-r', recoveryId],
}
@ -74,7 +73,7 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
throw new Error(`Could not find any children of the screen process (PID ${screenPID})!`)
}
if (child.command == 'login') {
if (child.command === 'login') {
await delay(1000)
child = (await listProcesses()).find(x => x.ppid === child.pid)
}

View file

@ -4,7 +4,6 @@ import { TabRecoveryProvider, AppService } from 'terminus-core'
import { TerminalTabComponent } from './components/terminalTab.component'
import { SessionsService } from './services/sessions.service'
@Injectable()
export class RecoveryProvider extends TabRecoveryProvider {
constructor (
@ -15,7 +14,7 @@ export class RecoveryProvider extends TabRecoveryProvider {
}
async recover (recoveryToken: any): Promise<void> {
if (recoveryToken.type == 'app:terminal') {
if (recoveryToken.type === 'app:terminal') {
let session = await this.sessions.recover(recoveryToken.recoveryId)
if (!session) {
return

View file

@ -7,7 +7,6 @@ import { exec } from 'mz/child_process'
import { SessionOptions, SessionPersistenceProvider } from '../api'
export class Session {
open: boolean
name: string
@ -34,9 +33,7 @@ export class Session {
options.command = 'sh'
}
this.pty = nodePTY.spawn(options.command, options.args || [], {
//name: 'screen-256color',
name: 'xterm-256color',
//name: 'xterm-color',
cols: 80,
rows: 30,
cwd: options.cwd || process.env.HOME,
@ -48,7 +45,7 @@ export class Session {
this.truePID = pid
})
} else {
this.truePID = (<any>this.pty).pid
this.truePID = (this.pty as any).pid
}
this.open = true
@ -87,7 +84,7 @@ export class Session {
}
async gracefullyKillProcess (): Promise<void> {
if (process.platform == 'win32') {
if (process.platform === 'win32') {
this.kill()
} else {
await new Promise((resolve) => {
@ -119,32 +116,31 @@ export class Session {
}
async getWorkingDirectory (): Promise<string> {
if (process.platform == 'darwin') {
if (process.platform === 'darwin') {
let lines = (await exec(`lsof -p ${this.truePID} -Fn`))[0].toString().split('\n')
return lines[2].substring(1)
}
if (process.platform == 'linux') {
if (process.platform === 'linux') {
return await fs.readlink(`/proc/${this.truePID}/cwd`)
}
return null
}
}
@Injectable()
export class SessionsService {
sessions: {[id: string]: Session} = {}
logger: Logger
private lastID = 0
constructor(
constructor (
private persistence: SessionPersistenceProvider,
log: LogService,
) {
this.logger = log.create('sessions')
}
async createNewSession (options: SessionOptions) : Promise<Session> {
async createNewSession (options: SessionOptions): Promise<Session> {
if (this.persistence) {
let recoveryId = await this.persistence.startSession(options)
options = await this.persistence.attachSession(recoveryId)
@ -153,7 +149,7 @@ export class SessionsService {
return session
}
addSession (options: SessionOptions) : Session {
addSession (options: SessionOptions): Session {
this.lastID++
options.name = `session-${this.lastID}`
let session = new Session(options)
@ -167,7 +163,7 @@ export class SessionsService {
return session
}
async recover (recoveryId: string) : Promise<Session> {
async recover (recoveryId: string): Promise<Session> {
if (!this.persistence) {
return null
}

View file

@ -3,7 +3,6 @@ import { SettingsTabProvider, ComponentType } from 'terminus-settings'
import { TerminalSettingsTabComponent } from './components/terminalSettingsTab.component'
@Injectable()
export class TerminalSettingsTabProvider extends SettingsTabProvider {
title = 'Terminal'

View file

@ -1,7 +1,6 @@
import { NgModule, Injectable } from '@angular/core'
import { Theme } from 'terminus-core'
@Injectable()
class HypeTheme extends Theme {
name = 'Hype'
@ -9,7 +8,6 @@ class HypeTheme extends Theme {
terminalBackground = '#010101'
}
@NgModule({
providers: [
{ provide: Theme, useClass: HypeTheme, multi: true },

View file

@ -1,31 +1,20 @@
{
"rulesDirectory": [
"node_modules/vrsource-tslint-rules/rules",
"node_modules/tslint-eslint-rules/dist/rules"
"extends": [
"tslint-eslint-rules",
"tslint-config-standard"
],
"rules": {
"radix": false,
"indent": [
true,
"spaces"
],
"rules": {
"no-duplicate-imports": true,
"no-duplicate-variable": true,
"no-jasmine-focus": true,
"no-var-keyword": true,
"no-eval": true,
"no-shadowed-variable": true,
"no-undef": true,
"no-unused-expression": true,
"no-unused-new": true,
"no-unused-variable": true,
"no-use-before-declare": true,
"require-internal-with-underscore": true,
"semicolon": [
false
],
"variable-name": [
true,
"ban-keywords"
],
"no-inner-declarations": [
true,
"function"
]
}
"ter-indent": [true, 4],
"trailing-comma": [
true,
{
"singleline": "never"
}
]
}
}