mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-08 21:40:03 +00:00
.
This commit is contained in:
parent
2c2da1d697
commit
f659a45532
42
app/main.js
42
app/main.js
@ -1,12 +1,23 @@
|
|||||||
|
const electron = require('electron')
|
||||||
|
|
||||||
|
let app = electron.app
|
||||||
|
|
||||||
|
let secondInstance = app.makeSingleInstance((argv) => {
|
||||||
|
app.window.webContents.send('host:second-instance')
|
||||||
|
})
|
||||||
|
|
||||||
|
if (secondInstance) {
|
||||||
|
app.quit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const yaml = require('js-yaml')
|
const yaml = require('js-yaml')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const Config = require('electron-config')
|
const Config = require('electron-config')
|
||||||
const electron = require('electron')
|
|
||||||
const platform = require('os').platform()
|
const platform = require('os').platform()
|
||||||
require('electron-debug')({enabled: true, showDevTools: process.argv.indexOf('--debug') != -1})
|
require('electron-debug')({enabled: true, showDevTools: process.argv.indexOf('--debug') != -1})
|
||||||
|
|
||||||
let app = electron.app
|
|
||||||
let windowConfig = new Config({name: 'window'})
|
let windowConfig = new Config({name: 'window'})
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +25,8 @@ setupWindowManagement = () => {
|
|||||||
let windowCloseable
|
let windowCloseable
|
||||||
|
|
||||||
app.window.on('show', () => {
|
app.window.on('show', () => {
|
||||||
electron.ipcMain.send('window-shown')
|
app.window.focus()
|
||||||
|
app.window.webContents.send('host:window-shown')
|
||||||
})
|
})
|
||||||
|
|
||||||
app.window.on('close', (e) => {
|
app.window.on('close', (e) => {
|
||||||
@ -46,6 +58,14 @@ setupWindowManagement = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
electron.ipcMain.on('window-maximize', () => {
|
electron.ipcMain.on('window-maximize', () => {
|
||||||
|
app.window.maximize()
|
||||||
|
})
|
||||||
|
|
||||||
|
electron.ipcMain.on('window-unmaximize', () => {
|
||||||
|
app.window.unmaximize()
|
||||||
|
})
|
||||||
|
|
||||||
|
electron.ipcMain.on('window-toggle-maximize', () => {
|
||||||
if (app.window.isMaximized()) {
|
if (app.window.isMaximized()) {
|
||||||
app.window.unmaximize()
|
app.window.unmaximize()
|
||||||
} else {
|
} else {
|
||||||
@ -61,6 +81,10 @@ setupWindowManagement = () => {
|
|||||||
app.window.setBounds(bounds, true)
|
app.window.setBounds(bounds, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
electron.ipcMain.on('window-set-always-on-top', (event, flag) => {
|
||||||
|
app.window.setAlwaysOnTop(flag)
|
||||||
|
})
|
||||||
|
|
||||||
app.on('before-quit', () => windowCloseable = true)
|
app.on('before-quit', () => windowCloseable = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,15 +119,6 @@ setupMenu = () => {
|
|||||||
start = () => {
|
start = () => {
|
||||||
let t0 = Date.now()
|
let t0 = Date.now()
|
||||||
|
|
||||||
let secondInstance = app.makeSingleInstance((argv) => {
|
|
||||||
app.window.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
if (secondInstance) {
|
|
||||||
app.quit()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let configPath = path.join(electron.app.getPath('userData'), 'config.yaml')
|
let configPath = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||||
let configData
|
let configData
|
||||||
if (fs.existsSync(configPath)) {
|
if (fs.existsSync(configPath)) {
|
||||||
@ -123,6 +138,7 @@ start = () => {
|
|||||||
//- background to avoid the flash of unstyled window
|
//- background to avoid the flash of unstyled window
|
||||||
backgroundColor: '#1D272D',
|
backgroundColor: '#1D272D',
|
||||||
frame: false,
|
frame: false,
|
||||||
|
type: 'toolbar',
|
||||||
}
|
}
|
||||||
Object.assign(options, windowConfig.get('windowBoundaries'))
|
Object.assign(options, windowConfig.get('windowBoundaries'))
|
||||||
|
|
||||||
|
@ -3,15 +3,15 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"child-process-promise": "^2.2.0",
|
"child-process-promise": "2.2.0",
|
||||||
"devtron": "^1.4.0",
|
"devtron": "1.4.0",
|
||||||
"electron-config": "^0.2.1",
|
"electron-config": "0.2.1",
|
||||||
"electron-debug": "^1.0.1",
|
"electron-debug": "1.0.1",
|
||||||
"electron-is-dev": "^0.1.2",
|
"electron-is-dev": "0.1.2",
|
||||||
"path": "^0.12.7",
|
"node-pty": "0.6.3",
|
||||||
"pty.js": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642"
|
"path": "0.12.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"js-yaml": "^3.8.2"
|
"js-yaml": "3.8.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ import { PluginDispatcherService } from 'services/pluginDispatcher'
|
|||||||
import { QuitterService } from 'services/quitter'
|
import { QuitterService } from 'services/quitter'
|
||||||
import { SessionsService } from 'services/sessions'
|
import { SessionsService } from 'services/sessions'
|
||||||
import { DockingService } from 'services/docking'
|
import { DockingService } from 'services/docking'
|
||||||
import { LocalStorageService } from 'angular2-localstorage/LocalStorageEmitter'
|
|
||||||
|
|
||||||
import { AppComponent } from 'components/app'
|
import { AppComponent } from 'components/app'
|
||||||
import { CheckboxComponent } from 'components/checkbox'
|
import { CheckboxComponent } from 'components/checkbox'
|
||||||
@ -48,7 +47,6 @@ import { TerminalComponent } from 'components/terminal'
|
|||||||
PluginDispatcherService,
|
PluginDispatcherService,
|
||||||
QuitterService,
|
QuitterService,
|
||||||
SessionsService,
|
SessionsService,
|
||||||
LocalStorageService,
|
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
HotkeyInputModalComponent,
|
HotkeyInputModalComponent,
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background: @title-bg;
|
background: @title-bg;
|
||||||
|
box-shadow: 0px -1px 0px 0px blue;
|
||||||
|
|
||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
//border-bottom: 2px solid #69bbea;
|
//border-bottom: 2px solid #69bbea;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
.titlebar(*ngIf='!config.store.appearance.useNativeFrame && config.store.appearance.dock == "off"')
|
.titlebar(*ngIf='!config.store.appearance.useNativeFrame && config.store.appearance.dock == "off"')
|
||||||
.title((dblclick)='hostApp.maximizeWindow()') Term
|
.title((dblclick)='hostApp.toggleMaximize()') Term
|
||||||
button.btn.btn-secondary.btn-minimize((click)='hostApp.minimizeWindow()')
|
button.btn.btn-secondary.btn-minimize((click)='hostApp.minimize()')
|
||||||
i.fa.fa-window-minimize
|
i.fa.fa-window-minimize
|
||||||
button.btn.btn-secondary.btn-maximize((click)='hostApp.maximizeWindow()')
|
button.btn.btn-secondary.btn-maximize((click)='hostApp.toggleMaximize()')
|
||||||
i.fa.fa-window-maximize
|
i.fa.fa-window-maximize
|
||||||
button.btn.btn-secondary.btn-close((click)='hostApp.quit()')
|
button.btn.btn-secondary.btn-close((click)='hostApp.quit()')
|
||||||
i.fa.fa-close
|
i.fa.fa-close
|
||||||
|
@ -66,11 +66,11 @@ export class AppComponent {
|
|||||||
private elementRef: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private sessions: SessionsService,
|
private sessions: SessionsService,
|
||||||
private docking: DockingService,
|
private docking: DockingService,
|
||||||
|
private electron: ElectronService,
|
||||||
public hostApp: HostAppService,
|
public hostApp: HostAppService,
|
||||||
public hotkeys: HotkeysService,
|
public hotkeys: HotkeysService,
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
log: LogService,
|
log: LogService,
|
||||||
electron: ElectronService,
|
|
||||||
_quitter: QuitterService,
|
_quitter: QuitterService,
|
||||||
) {
|
) {
|
||||||
console.timeStamp('AppComponent ctor')
|
console.timeStamp('AppComponent ctor')
|
||||||
@ -135,10 +135,33 @@ export class AppComponent {
|
|||||||
this.hostApp.shown.subscribe(() => {
|
this.hostApp.shown.subscribe(() => {
|
||||||
this.docking.dock()
|
this.docking.dock()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.hostApp.secondInstance.subscribe(() => {
|
||||||
|
if (this.electron.app.window.isFocused()) {
|
||||||
|
// focused
|
||||||
|
this.electron.app.window.hide()
|
||||||
|
} else {
|
||||||
|
if (!this.electron.app.window.isVisible()) {
|
||||||
|
// unfocused, invisible
|
||||||
|
this.electron.app.window.show()
|
||||||
|
} else {
|
||||||
|
if (this.config.full().appearance.dock == 'off') {
|
||||||
|
// not docked, visible
|
||||||
|
setTimeout(() => {
|
||||||
|
this.electron.app.window.focus()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// docked, visible
|
||||||
|
this.electron.app.window.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.docking.dock()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
newTab () {
|
newTab () {
|
||||||
this.addTerminalTab(this.sessions.createNewSession({command: 'bash'}))
|
this.addTerminalTab(this.sessions.createNewSession({shell: 'zsh'}))
|
||||||
}
|
}
|
||||||
|
|
||||||
addTerminalTab (session) {
|
addTerminalTab (session) {
|
||||||
|
@ -31,7 +31,7 @@ ngb-tabset(type='tabs')
|
|||||||
label Dock the terminal
|
label Dock the terminal
|
||||||
br
|
br
|
||||||
.row
|
.row
|
||||||
.col-auto
|
.col.col-auto
|
||||||
div(
|
div(
|
||||||
'[(ngModel)]'='config.store.appearance.dock'
|
'[(ngModel)]'='config.store.appearance.dock'
|
||||||
'(ngModelChange)'='config.save(); docking.dock()'
|
'(ngModelChange)'='config.save(); docking.dock()'
|
||||||
@ -71,10 +71,10 @@ ngb-tabset(type='tabs')
|
|||||||
input(
|
input(
|
||||||
type='range',
|
type='range',
|
||||||
'[(ngModel)]'='config.store.appearance.dockFill',
|
'[(ngModel)]'='config.store.appearance.dockFill',
|
||||||
'(ngModelChange)'='config.save(); docking.dock()',
|
'(mouseup)'='config.save(); docking.dock()',
|
||||||
min='1',
|
min='0.05',
|
||||||
max='100',
|
max='1',
|
||||||
step='1'
|
step='0.01'
|
||||||
)
|
)
|
||||||
br
|
br
|
||||||
div(
|
div(
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
:host {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
10
app/src/components/terminal.scss
Normal file
10
app/src/components/terminal.scss
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
div[style]:last-child {
|
||||||
|
background: black !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
}
|
@ -25,19 +25,10 @@ hterm.hterm.VT.ESC['k'] = function(parseState) {
|
|||||||
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
|
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
|
||||||
const preferenceManager = new hterm.hterm.PreferenceManager('default')
|
const preferenceManager = new hterm.hterm.PreferenceManager('default')
|
||||||
preferenceManager.set('user-css', dataurl.convert({
|
preferenceManager.set('user-css', dataurl.convert({
|
||||||
data: `
|
data: require('./terminal.userCSS.scss'),
|
||||||
a {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
mimetype: 'text/css',
|
mimetype: 'text/css',
|
||||||
charset: 'utf8',
|
charset: 'utf8',
|
||||||
}))
|
}))
|
||||||
preferenceManager.set('font-size', 12)
|
|
||||||
preferenceManager.set('background-color', '#1D272D')
|
preferenceManager.set('background-color', '#1D272D')
|
||||||
preferenceManager.set('color-palette-overrides', {
|
preferenceManager.set('color-palette-overrides', {
|
||||||
0: '#1D272D',
|
0: '#1D272D',
|
||||||
@ -49,11 +40,12 @@ hterm.hterm.ScrollPort.prototype.decorate = function (...args) {
|
|||||||
this.screen_.style.cssText += `; padding-right: ${this.screen_.offsetWidth - this.screen_.clientWidth}px;`
|
this.screen_.style.cssText += `; padding-right: ${this.screen_.offsetWidth - this.screen_.clientWidth}px;`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hterm.hterm.Terminal.prototype.showOverlay = () => null
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'terminal',
|
selector: 'terminal',
|
||||||
template: '',
|
template: '',
|
||||||
styles: [require('./terminal.less')],
|
styles: [require('./terminal.scss')],
|
||||||
})
|
})
|
||||||
export class TerminalComponent {
|
export class TerminalComponent {
|
||||||
@Input() session: Session
|
@Input() session: Session
|
||||||
@ -115,6 +107,7 @@ export class TerminalComponent {
|
|||||||
preferenceManager.set('font-size', config.appearance.fontSize)
|
preferenceManager.set('font-size', config.appearance.fontSize)
|
||||||
preferenceManager.set('audible-bell-sound', '')
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
|
11
app/src/components/terminal.userCSS.scss
Normal file
11
app/src/components/terminal.userCSS.scss
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
font-feature-settings: "liga" 0; // disable ligatures (they break monospacing)
|
||||||
|
}
|
@ -14,6 +14,7 @@ export interface IAppearanceData {
|
|||||||
fontSize: number
|
fontSize: number
|
||||||
dock: string
|
dock: string
|
||||||
dockScreen: string
|
dockScreen: string
|
||||||
|
dockFill: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITerminalData {
|
export interface ITerminalData {
|
||||||
|
@ -26,18 +26,19 @@ export class DockingService {
|
|||||||
|
|
||||||
let dockSide = this.config.full().appearance.dock
|
let dockSide = this.config.full().appearance.dock
|
||||||
let newBounds: Electron.Rectangle = { x: 0, y: 0, width: 0, height: 0 }
|
let newBounds: Electron.Rectangle = { x: 0, y: 0, width: 0, height: 0 }
|
||||||
let fill = 0.5
|
let fill = this.config.full().appearance.dockFill
|
||||||
|
|
||||||
if (dockSide == 'off') {
|
if (dockSide == 'off') {
|
||||||
|
this.hostApp.setAlwaysOnTop(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (dockSide == 'left' || dockSide == 'right') {
|
if (dockSide == 'left' || dockSide == 'right') {
|
||||||
newBounds.width = fill * display.bounds.width
|
newBounds.width = Math.round(fill * display.bounds.width)
|
||||||
newBounds.height = display.bounds.height
|
newBounds.height = display.bounds.height
|
||||||
}
|
}
|
||||||
if (dockSide == 'top' || dockSide == 'bottom') {
|
if (dockSide == 'top' || dockSide == 'bottom') {
|
||||||
newBounds.width = display.bounds.width
|
newBounds.width = display.bounds.width
|
||||||
newBounds.height = fill * display.bounds.height
|
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)
|
newBounds.x = display.bounds.x + display.bounds.width * (1.0 - fill)
|
||||||
@ -50,6 +51,8 @@ export class DockingService {
|
|||||||
newBounds.y = display.bounds.y
|
newBounds.y = display.bounds.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.hostApp.setAlwaysOnTop(true)
|
||||||
|
this.hostApp.unmaximize()
|
||||||
this.hostApp.setBounds(newBounds)
|
this.hostApp.setBounds(newBounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +23,14 @@ export class HostAppService {
|
|||||||
console.error('Unhandled exception:', err)
|
console.error('Unhandled exception:', err)
|
||||||
})
|
})
|
||||||
|
|
||||||
electron.ipcRenderer.on('window-shown', () => {
|
electron.ipcRenderer.on('host:window-shown', () => {
|
||||||
this.shown.emit()
|
this.shown.emit()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
electron.ipcRenderer.on('host:second-instance', () => {
|
||||||
|
this.secondInstance.emit()
|
||||||
|
})
|
||||||
|
|
||||||
this.ready.subscribe(() => {
|
this.ready.subscribe(() => {
|
||||||
electron.ipcRenderer.send('app:ready')
|
electron.ipcRenderer.send('app:ready')
|
||||||
})
|
})
|
||||||
@ -36,6 +40,7 @@ export class HostAppService {
|
|||||||
quitRequested = new EventEmitter<any>()
|
quitRequested = new EventEmitter<any>()
|
||||||
ready = new EventEmitter<any>()
|
ready = new EventEmitter<any>()
|
||||||
shown = new EventEmitter<any>()
|
shown = new EventEmitter<any>()
|
||||||
|
secondInstance = new EventEmitter<any>()
|
||||||
|
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
@ -59,8 +64,8 @@ export class HostAppService {
|
|||||||
this.electron.app.webContents.openDevTools()
|
this.electron.app.webContents.openDevTools()
|
||||||
}
|
}
|
||||||
|
|
||||||
setWindowCloseable(flag: boolean) {
|
setCloseable(flag: boolean) {
|
||||||
this.electron.ipcRenderer.send('window-closeable', flag)
|
this.electron.ipcRenderer.send('window-set-closeable', flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
focusWindow() {
|
focusWindow() {
|
||||||
@ -71,18 +76,30 @@ export class HostAppService {
|
|||||||
this.electron.ipcRenderer.send('window-toggle-focus')
|
this.electron.ipcRenderer.send('window-toggle-focus')
|
||||||
}
|
}
|
||||||
|
|
||||||
minimizeWindow () {
|
minimize () {
|
||||||
this.electron.ipcRenderer.send('window-minimize')
|
this.electron.ipcRenderer.send('window-minimize')
|
||||||
}
|
}
|
||||||
|
|
||||||
maximizeWindow () {
|
maximize () {
|
||||||
this.electron.ipcRenderer.send('window-maximize')
|
this.electron.ipcRenderer.send('window-maximize')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unmaximize () {
|
||||||
|
this.electron.ipcRenderer.send('window-unmaximize')
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleMaximize () {
|
||||||
|
this.electron.ipcRenderer.send('window-toggle-maximize')
|
||||||
|
}
|
||||||
|
|
||||||
setBounds (bounds: Electron.Rectangle) {
|
setBounds (bounds: Electron.Rectangle) {
|
||||||
this.electron.ipcRenderer.send('window-set-bounds', bounds)
|
this.electron.ipcRenderer.send('window-set-bounds', bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAlwaysOnTop (flag: boolean) {
|
||||||
|
this.electron.ipcRenderer.send('window-set-always-on-top', flag)
|
||||||
|
}
|
||||||
|
|
||||||
quit () {
|
quit () {
|
||||||
this.logger.info('Quitting')
|
this.logger.info('Quitting')
|
||||||
this.electron.app.quit()
|
this.electron.app.quit()
|
||||||
|
@ -13,7 +13,7 @@ export class QuitterService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quit() {
|
quit() {
|
||||||
this.hostApp.setWindowCloseable(true)
|
this.hostApp.setCloseable(true)
|
||||||
this.hostApp.quit()
|
this.hostApp.quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
|||||||
import { Logger, LogService } from 'services/log'
|
import { Logger, LogService } from 'services/log'
|
||||||
const exec = require('child-process-promise').exec
|
const exec = require('child-process-promise').exec
|
||||||
import * as crypto from 'crypto'
|
import * as crypto from 'crypto'
|
||||||
import * as ptyjs from 'pty.js'
|
import * as nodePTY from 'node-pty'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
|
||||||
|
|
||||||
export interface SessionRecoveryProvider {
|
export interface SessionRecoveryProvider {
|
||||||
@ -42,16 +43,26 @@ export class ScreenSessionRecoveryProvider implements SessionRecoveryProvider {
|
|||||||
|
|
||||||
getNewSessionCommand(command: string): string {
|
getNewSessionCommand(command: string): string {
|
||||||
const id = crypto.randomBytes(8).toString('hex')
|
const id = crypto.randomBytes(8).toString('hex')
|
||||||
return `screen -U -S term-tab-${id} -- ${command}`
|
// TODO
|
||||||
|
let configPath = '/tmp/.termScreenConfig'
|
||||||
|
fs.writeFileSync(configPath, `
|
||||||
|
escape ^^^
|
||||||
|
vbell off
|
||||||
|
term xterm-color
|
||||||
|
bindkey "^[OH" beginning-of-line
|
||||||
|
bindkey "^[OF" end-of-line
|
||||||
|
`, 'utf-8')
|
||||||
|
return `screen -c ${configPath} -U -S term-tab-${id} -- ${command}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface SessionOptions {
|
export interface SessionOptions {
|
||||||
name?: string,
|
name?: string,
|
||||||
command: string,
|
command?: string,
|
||||||
|
shell?: string,
|
||||||
cwd?: string,
|
cwd?: string,
|
||||||
env?: string,
|
env?: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Session {
|
export class Session {
|
||||||
@ -67,14 +78,22 @@ export class Session {
|
|||||||
constructor (options: SessionOptions) {
|
constructor (options: SessionOptions) {
|
||||||
this.name = options.name
|
this.name = options.name
|
||||||
console.log('Spawning', options.command)
|
console.log('Spawning', options.command)
|
||||||
this.pty = ptyjs.spawn('sh', ['-c', options.command], {
|
|
||||||
name: 'screen-256color',
|
let binary = options.shell || 'sh'
|
||||||
//name: 'xterm-256color',
|
let args = options.shell ? [] : ['-c', options.command]
|
||||||
|
let env = {
|
||||||
|
...process.env,
|
||||||
|
...options.env,
|
||||||
|
TERM: 'xterm-256color',
|
||||||
|
}
|
||||||
|
this.pty = nodePTY.spawn(binary, args, {
|
||||||
|
//name: 'screen-256color',
|
||||||
|
name: 'xterm-256color',
|
||||||
//name: 'xterm-color',
|
//name: 'xterm-color',
|
||||||
cols: 80,
|
cols: 80,
|
||||||
rows: 30,
|
rows: 30,
|
||||||
cwd: options.cwd || process.env.HOME,
|
cwd: options.cwd || process.env.HOME,
|
||||||
env: options.env || process.env,
|
env: env,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.open = true
|
this.open = true
|
||||||
@ -156,8 +175,8 @@ export class SessionsService {
|
|||||||
log: LogService,
|
log: LogService,
|
||||||
) {
|
) {
|
||||||
this.logger = log.create('sessions')
|
this.logger = log.create('sessions')
|
||||||
//this.recoveryProvider = new ScreenSessionRecoveryProvider()
|
this.recoveryProvider = new ScreenSessionRecoveryProvider()
|
||||||
this.recoveryProvider = new NullSessionRecoveryProvider()
|
//this.recoveryProvider = new NullSessionRecoveryProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
createNewSession (options: SessionOptions) : Session {
|
createNewSession (options: SessionOptions) : Session {
|
||||||
|
11
package.json
11
package.json
@ -4,13 +4,12 @@
|
|||||||
"apply-loader": "^0.1.0",
|
"apply-loader": "^0.1.0",
|
||||||
"autoprefixer": "^6.7.7",
|
"autoprefixer": "^6.7.7",
|
||||||
"awesome-typescript-loader": "3.0.8",
|
"awesome-typescript-loader": "3.0.8",
|
||||||
"bootstrap": "^4.0.0-alpha.6",
|
|
||||||
"css-loader": "0.26.1",
|
"css-loader": "0.26.1",
|
||||||
"dataurl": "^0.1.0",
|
"dataurl": "^0.1.0",
|
||||||
"electron": "^1.4.13",
|
"electron": "1.6.2",
|
||||||
"electron-builder": "10.6.1",
|
"electron-builder": "10.6.1",
|
||||||
"electron-osx-sign": "electron-userland/electron-osx-sign#f092181a1bffa2b3248a23ee28447a47e14a8f04",
|
"electron-osx-sign": "electron-userland/electron-osx-sign#f092181a1bffa2b3248a23ee28447a47e14a8f04",
|
||||||
"electron-rebuild": "1.4.0",
|
"electron-rebuild": "1.5.7",
|
||||||
"file-loader": "^0.9.0",
|
"file-loader": "^0.9.0",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"html-loader": "^0.4.4",
|
"html-loader": "^0.4.4",
|
||||||
@ -69,14 +68,12 @@
|
|||||||
"@angular/router": "3.3.1",
|
"@angular/router": "3.3.1",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.15",
|
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.15",
|
||||||
"@types/core-js": "^0.9.35",
|
"@types/core-js": "^0.9.35",
|
||||||
"@types/electron": "^1.4.33",
|
"@types/electron": "1.4.34",
|
||||||
"@types/js-yaml": "^3.5.29",
|
"@types/js-yaml": "^3.5.29",
|
||||||
"@types/node": "^7.0.5",
|
"@types/node": "^7.0.5",
|
||||||
"@types/pty.js": "^0.2.32",
|
|
||||||
"angular2-localstorage": "github:AilisObrian/angular2-localstorage",
|
|
||||||
"angular2-perfect-scrollbar": "^1.1.0",
|
"angular2-perfect-scrollbar": "^1.1.0",
|
||||||
"angular2-toaster": "^1.1.0",
|
"angular2-toaster": "^1.1.0",
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "4.0.0-alpha.6",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
"deepmerge": "^1.3.2",
|
"deepmerge": "^1.3.2",
|
||||||
"hterm-commonjs": "^1.0.0",
|
"hterm-commonjs": "^1.0.0",
|
||||||
|
@ -13,7 +13,12 @@
|
|||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noUnusedLocals": true
|
"noUnusedLocals": true,
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es2015",
|
||||||
|
"es7"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
@ -4,7 +4,7 @@ const webpack = require("webpack")
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
target: 'node',
|
target: 'node',
|
||||||
entry: {
|
entry: {
|
||||||
'index.ignore': 'file-loader?name=index.html!val-loader!pug-html-loader!./app/index.pug',
|
'index.ignore': 'file-loader?name=index.html!pug-html-loader!./app/index.pug',
|
||||||
'preload': './app/src/entry.preload.ts',
|
'preload': './app/src/entry.preload.ts',
|
||||||
'bundle': './app/src/entry.ts',
|
'bundle': './app/src/entry.ts',
|
||||||
},
|
},
|
||||||
@ -52,7 +52,13 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: ['style-loader', 'css-loader', 'sass-loader']
|
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||||
|
exclude: [/app\/src\/components\//],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: ['to-string-loader', 'css-loader', 'sass-loader'],
|
||||||
|
include: [/app\/src\/components\//],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|svg)$/,
|
test: /\.(png|svg)$/,
|
||||||
@ -83,7 +89,7 @@ module.exports = {
|
|||||||
'shell': 'require("shell")',
|
'shell': 'require("shell")',
|
||||||
'ipc': 'require("ipc")',
|
'ipc': 'require("ipc")',
|
||||||
'crypto': 'require("crypto")',
|
'crypto': 'require("crypto")',
|
||||||
'pty.js': 'require("pty.js")',
|
'node-pty': 'require("node-pty")',
|
||||||
'child-process-promise': 'require("child-process-promise")',
|
'child-process-promise': 'require("child-process-promise")',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user