mirror of
https://github.com/Eugeny/tabby.git
synced 2025-09-21 07:36:05 +00:00
Compare commits
23 Commits
v1.0.0-alp
...
v1.0.0-alp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5a5cd09832 | ||
![]() |
c2f4c343a7 | ||
![]() |
153cd1ec9a | ||
![]() |
0254cabdde | ||
![]() |
9eee600ccc | ||
![]() |
24288fac9a | ||
![]() |
441164363f | ||
![]() |
3d7a4a1e0e | ||
![]() |
7984313b06 | ||
![]() |
89cc6c0d20 | ||
![]() |
d104f5e771 | ||
![]() |
5b5d145bd0 | ||
![]() |
78212a9538 | ||
![]() |
1b1b2af545 | ||
![]() |
f3f969a006 | ||
![]() |
621a6d8127 | ||
![]() |
87933edb96 | ||
![]() |
a931d47c23 | ||
![]() |
1ae027f17c | ||
![]() |
5360b2f292 | ||
![]() |
d806fb6e1e | ||
![]() |
57de182013 | ||
![]() |
3fd57e81a6 |
@@ -1,4 +1,5 @@
|
|||||||
import { app, ipcMain, Menu, Tray, shell } from 'electron'
|
import { app, ipcMain, Menu, Tray, shell } from 'electron'
|
||||||
|
import { loadConfig } from './config'
|
||||||
import { Window } from './window'
|
import { Window } from './window'
|
||||||
|
|
||||||
export class Application {
|
export class Application {
|
||||||
@@ -9,6 +10,14 @@ export class Application {
|
|||||||
ipcMain.on('app:config-change', () => {
|
ipcMain.on('app:config-change', () => {
|
||||||
this.broadcast('host:config-change')
|
this.broadcast('host:config-change')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const configData = loadConfig()
|
||||||
|
if (process.platform === 'linux' && ((configData.appearance || {}).opacity || 1) !== 1) {
|
||||||
|
app.commandLine.appendSwitch('enable-transparent-visuals')
|
||||||
|
app.disableHardwareAcceleration()
|
||||||
|
}
|
||||||
|
|
||||||
|
app.commandLine.appendSwitch('disable-http-cache')
|
||||||
}
|
}
|
||||||
|
|
||||||
async newWindow (): Promise<Window> {
|
async newWindow (): Promise<Window> {
|
||||||
|
13
app/lib/config.ts
Normal file
13
app/lib/config.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import * as fs from 'fs'
|
||||||
|
import * as path from 'path'
|
||||||
|
import * as yaml from 'js-yaml'
|
||||||
|
import { app } from 'electron'
|
||||||
|
|
||||||
|
export function loadConfig (): any {
|
||||||
|
let configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||||
|
if (fs.existsSync(configPath)) {
|
||||||
|
return yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
|
||||||
|
} else {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
@@ -11,8 +11,6 @@ if (!process.env.TERMINUS_PLUGINS) {
|
|||||||
|
|
||||||
const application = new Application()
|
const application = new Application()
|
||||||
|
|
||||||
app.commandLine.appendSwitch('disable-http-cache')
|
|
||||||
|
|
||||||
ipcMain.on('app:new-window', () => {
|
ipcMain.on('app:new-window', () => {
|
||||||
console.log('new-window')
|
console.log('new-window')
|
||||||
application.newWindow()
|
application.newWindow()
|
||||||
|
@@ -1,33 +1,30 @@
|
|||||||
import { Subject, Observable } from 'rxjs'
|
import { Subject, Observable } from 'rxjs'
|
||||||
import { BrowserWindow, app, ipcMain, Rectangle, Menu } from 'electron'
|
import { BrowserWindow, app, ipcMain, Rectangle } from 'electron'
|
||||||
import ElectronConfig = require('electron-config')
|
import ElectronConfig = require('electron-config')
|
||||||
import * as yaml from 'js-yaml'
|
import * as os from 'os'
|
||||||
import * as fs from 'fs'
|
|
||||||
import * as path from 'path'
|
|
||||||
|
|
||||||
let electronVibrancy: any
|
import { loadConfig } from './config'
|
||||||
if (process.platform !== 'linux') {
|
|
||||||
electronVibrancy = require('electron-vibrancy')
|
let SetWindowCompositionAttribute: any
|
||||||
|
let AccentState: any
|
||||||
|
let DwmEnableBlurBehindWindow: any
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
SetWindowCompositionAttribute = require('windows-swca').SetWindowCompositionAttribute
|
||||||
|
AccentState = require('windows-swca').AccentState
|
||||||
|
DwmEnableBlurBehindWindow = require('windows-blurbehind').DwmEnableBlurBehindWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Window {
|
export class Window {
|
||||||
ready: Promise<void>
|
ready: Promise<void>
|
||||||
private visible = new Subject<boolean>()
|
private visible = new Subject<boolean>()
|
||||||
private window: BrowserWindow
|
private window: BrowserWindow
|
||||||
private vibrancyViewID: number
|
|
||||||
private windowConfig: ElectronConfig
|
private windowConfig: ElectronConfig
|
||||||
private windowBounds: Rectangle
|
private windowBounds: Rectangle
|
||||||
|
|
||||||
get visible$ (): Observable<boolean> { return this.visible }
|
get visible$ (): Observable<boolean> { return this.visible }
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
let configPath = path.join(app.getPath('userData'), 'config.yaml')
|
let configData = loadConfig()
|
||||||
let configData
|
|
||||||
if (fs.existsSync(configPath)) {
|
|
||||||
configData = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
|
|
||||||
} else {
|
|
||||||
configData = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.windowConfig = new ElectronConfig({ name: 'window' })
|
this.windowConfig = new ElectronConfig({ name: 'window' })
|
||||||
this.windowBounds = this.windowConfig.get('windowBoundaries')
|
this.windowBounds = this.windowConfig.get('windowBoundaries')
|
||||||
@@ -42,6 +39,7 @@ export class Window {
|
|||||||
webPreferences: { webSecurity: false },
|
webPreferences: { webSecurity: false },
|
||||||
frame: false,
|
frame: false,
|
||||||
show: false,
|
show: false,
|
||||||
|
backgroundColor: '#00000000'
|
||||||
}
|
}
|
||||||
Object.assign(options, this.windowBounds)
|
Object.assign(options, this.windowBounds)
|
||||||
|
|
||||||
@@ -53,10 +51,6 @@ export class Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'win32' && (configData.appearance || {}).vibrancy) {
|
|
||||||
options.transparent = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
options.backgroundColor = '#131d27'
|
options.backgroundColor = '#131d27'
|
||||||
}
|
}
|
||||||
@@ -95,11 +89,22 @@ export class Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setVibrancy (enabled: boolean) {
|
setVibrancy (enabled: boolean) {
|
||||||
if (enabled && !this.vibrancyViewID) {
|
if (process.platform === 'win32') {
|
||||||
this.vibrancyViewID = electronVibrancy.SetVibrancy(this.window, 0)
|
if (parseFloat(os.release()) >= 10) {
|
||||||
} else if (!enabled && this.vibrancyViewID) {
|
let attribValue = AccentState.ACCENT_DISABLED
|
||||||
electronVibrancy.RemoveView(this.window, this.vibrancyViewID)
|
let color = 0x00000000
|
||||||
this.vibrancyViewID = null
|
if (enabled) {
|
||||||
|
if (parseInt(os.release().split('.')[2]) >= 17063) {
|
||||||
|
attribValue = AccentState.ACCENT_ENABLE_FLUENT
|
||||||
|
color = 0x01000000 // using a small alpha because acrylic bugs out at full transparency.
|
||||||
|
} else {
|
||||||
|
attribValue = AccentState.ACCENT_ENABLE_BLURBEHIND
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetWindowCompositionAttribute(this.window, attribValue, color)
|
||||||
|
} else {
|
||||||
|
DwmEnableBlurBehindWindow(this.window, enabled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,10 +193,6 @@ export class Window {
|
|||||||
ipcMain.on('window-set-title', (_event, title) => {
|
ipcMain.on('window-set-title', (_event, title) => {
|
||||||
this.window.setTitle(title)
|
this.window.setTitle(title)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('window-popup-context-menu', (_event, menuDefinition) => {
|
|
||||||
Menu.buildFromTemplate(menuDefinition).popup({ window: this.window })
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private destroy () {
|
private destroy () {
|
||||||
|
@@ -25,7 +25,6 @@
|
|||||||
"electron-debug": "^2.0.0",
|
"electron-debug": "^2.0.0",
|
||||||
"electron-is-dev": "0.1.2",
|
"electron-is-dev": "0.1.2",
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
"electron-vibrancy": "^0.1.3",
|
|
||||||
"js-yaml": "3.8.2",
|
"js-yaml": "3.8.2",
|
||||||
"mz": "^2.6.0",
|
"mz": "^2.6.0",
|
||||||
"ngx-toastr": "^8.7.3",
|
"ngx-toastr": "^8.7.3",
|
||||||
@@ -34,6 +33,10 @@
|
|||||||
"yargs": "^12.0.1",
|
"yargs": "^12.0.1",
|
||||||
"zone.js": "~0.8.26"
|
"zone.js": "~0.8.26"
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"windows-blurbehind": "^1.0.0",
|
||||||
|
"windows-swca": "^1.1.1"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mz": "0.0.31"
|
"@types/mz": "0.0.31"
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,8 @@ module.exports = {
|
|||||||
mz: 'commonjs mz',
|
mz: 'commonjs mz',
|
||||||
path: 'commonjs path',
|
path: 'commonjs path',
|
||||||
yargs: 'commonjs yargs',
|
yargs: 'commonjs yargs',
|
||||||
|
'windows-swca': 'commonjs windows-swca',
|
||||||
|
'windows-blurbehind': 'commonjs windows-blurbehind',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
|
@@ -80,10 +80,6 @@ argparse@^1.0.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
sprintf-js "~1.0.2"
|
sprintf-js "~1.0.2"
|
||||||
|
|
||||||
bindings@^1.2.1:
|
|
||||||
version "1.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
|
|
||||||
|
|
||||||
camelcase@^4.1.0:
|
camelcase@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
|
||||||
@@ -183,13 +179,6 @@ electron-squirrel-startup@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
debug "^2.2.0"
|
debug "^2.2.0"
|
||||||
|
|
||||||
electron-vibrancy@^0.1.3:
|
|
||||||
version "0.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/electron-vibrancy/-/electron-vibrancy-0.1.3.tgz#04382dd6e030e5ca5e60f8e024033738cb8479e3"
|
|
||||||
dependencies:
|
|
||||||
bindings "^1.2.1"
|
|
||||||
nan "^2.0.5"
|
|
||||||
|
|
||||||
env-paths@^0.3.0:
|
env-paths@^0.3.0:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-0.3.1.tgz#c30ccfcbc30c890943dc08a85582517ef00da463"
|
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-0.3.1.tgz#c30ccfcbc30c890943dc08a85582517ef00da463"
|
||||||
@@ -336,10 +325,6 @@ mz@^2.6.0:
|
|||||||
object-assign "^4.0.1"
|
object-assign "^4.0.1"
|
||||||
thenify-all "^1.0.0"
|
thenify-all "^1.0.0"
|
||||||
|
|
||||||
nan@^2.0.5:
|
|
||||||
version "2.10.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
|
|
||||||
|
|
||||||
ngx-toastr@^8.7.3:
|
ngx-toastr@^8.7.3:
|
||||||
version "8.7.3"
|
version "8.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-8.7.3.tgz#d3b7a8077ba1c860dd8a44779ccad38c5ea15c92"
|
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-8.7.3.tgz#d3b7a8077ba1c860dd8a44779ccad38c5ea15c92"
|
||||||
@@ -532,6 +517,14 @@ which@^1.2.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
isexe "^2.0.0"
|
isexe "^2.0.0"
|
||||||
|
|
||||||
|
windows-blurbehind@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/windows-blurbehind/-/windows-blurbehind-1.0.0.tgz#050efb988704c44335bdc3efefd757f6e463b8ac"
|
||||||
|
|
||||||
|
windows-swca@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/windows-swca/-/windows-swca-1.1.1.tgz#0b3530278c67d408baac71c3a6aeb16d55318bf8"
|
||||||
|
|
||||||
wrap-ansi@^2.0.0:
|
wrap-ansi@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
||||||
|
@@ -4,7 +4,7 @@ platform:
|
|||||||
- x64
|
- x64
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
nodejs_version: "7"
|
nodejs_version: "10"
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
- '%USERPROFILE%\.electron'
|
- '%USERPROFILE%\.electron'
|
||||||
|
4
build/linux/after-install.tpl
Normal file
4
build/linux/after-install.tpl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Link to the binary
|
||||||
|
ln -sf '/opt/${productFilename}/${executable}' '/usr/bin/${executable}'
|
@@ -120,7 +120,8 @@
|
|||||||
"libxtst6",
|
"libxtst6",
|
||||||
"libnss3",
|
"libnss3",
|
||||||
"tmux"
|
"tmux"
|
||||||
]
|
],
|
||||||
|
"afterInstall": "build/linux/after-install.tpl"
|
||||||
},
|
},
|
||||||
"rpm": {
|
"rpm": {
|
||||||
"depends": [
|
"depends": [
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { TouchBar, BrowserWindow } from 'electron'
|
import { TouchBar, BrowserWindow, Menu } from 'electron'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ElectronService {
|
export class ElectronService {
|
||||||
@@ -14,6 +14,7 @@ export class ElectronService {
|
|||||||
remote: any
|
remote: any
|
||||||
TouchBar: typeof TouchBar
|
TouchBar: typeof TouchBar
|
||||||
BrowserWindow: typeof BrowserWindow
|
BrowserWindow: typeof BrowserWindow
|
||||||
|
Menu: typeof Menu
|
||||||
private electron: any
|
private electron: any
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -29,6 +30,7 @@ export class ElectronService {
|
|||||||
this.nativeImage = this.remote.nativeImage
|
this.nativeImage = this.remote.nativeImage
|
||||||
this.TouchBar = this.remote.TouchBar
|
this.TouchBar = this.remote.TouchBar
|
||||||
this.BrowserWindow = this.remote.BrowserWindow
|
this.BrowserWindow = this.remote.BrowserWindow
|
||||||
|
this.Menu = this.remote.Menu
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteRequire (name: string): any {
|
remoteRequire (name: string): any {
|
||||||
|
@@ -169,7 +169,7 @@ export class HostAppService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]) {
|
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]) {
|
||||||
this.electron.ipcRenderer.send('window-popup-context-menu', menuDefinition)
|
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastConfigChange () {
|
broadcastConfigChange () {
|
||||||
|
@@ -38,6 +38,16 @@ export class ShellIntegrationService {
|
|||||||
)
|
)
|
||||||
this.automatorWorkflowsDestination = path.join(process.env.HOME, 'Library', 'Services')
|
this.automatorWorkflowsDestination = path.join(process.env.HOME, 'Library', 'Services')
|
||||||
}
|
}
|
||||||
|
this.updatePaths()
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePaths (): Promise<void> {
|
||||||
|
// Update paths in case of an update
|
||||||
|
if (this.hostApp.platform === Platform.Windows) {
|
||||||
|
if (await this.isInstalled()) {
|
||||||
|
await this.install()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async isInstalled (): Promise<boolean> {
|
async isInstalled (): Promise<boolean> {
|
||||||
|
@@ -66,7 +66,7 @@ div(*ngIf='npmInstalled')
|
|||||||
i.fa.fa-fw.fa-search(*ngIf='availablePluginsReady')
|
i.fa.fa-fw.fa-search(*ngIf='availablePluginsReady')
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='text',
|
type='text',
|
||||||
'[(ngModel)]'='_1',
|
[(ngModel)]='_1',
|
||||||
(ngModelChange)='searchAvailable(_1)',
|
(ngModelChange)='searchAvailable(_1)',
|
||||||
placeholder='Search plugins'
|
placeholder='Search plugins'
|
||||||
)
|
)
|
||||||
|
@@ -72,9 +72,13 @@ export class PluginManagerService {
|
|||||||
|
|
||||||
listAvailable (query?: string): Observable<IPluginInfo[]> {
|
listAvailable (query?: string): Observable<IPluginInfo[]> {
|
||||||
return from(
|
return from(
|
||||||
axios.get(`https://api.npms.io/v2/search?q=keywords%3A${KEYWORD}+${encodeURIComponent(query || '')}&from=0&size=250`, {})
|
axios.get(`https://www.npmjs.com/search?q=keywords%3A${KEYWORD}+${encodeURIComponent(query || '')}&from=0&size=1000`, {
|
||||||
|
headers: {
|
||||||
|
'x-spiferack': '1',
|
||||||
|
}
|
||||||
|
})
|
||||||
).pipe(
|
).pipe(
|
||||||
map(response => response.data.results.map(item => ({
|
map(response => response.data.objects.map(item => ({
|
||||||
name: item.package.name.substring(NAME_PREFIX.length),
|
name: item.package.name.substring(NAME_PREFIX.length),
|
||||||
packageName: item.package.name,
|
packageName: item.package.name,
|
||||||
description: item.package.description,
|
description: item.package.description,
|
||||||
|
@@ -64,33 +64,18 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
|||||||
.title Vibrancy
|
.title Vibrancy
|
||||||
.description Gives the window a blurred transparent background
|
.description Gives the window a blurred transparent background
|
||||||
|
|
||||||
.btn-group(
|
toggle(
|
||||||
[(ngModel)]='config.store.appearance.vibrancy',
|
[(ngModel)]='config.store.appearance.vibrancy',
|
||||||
(ngModelChange)='config.save(); (hostApp.platform === Platform.Windows && config.requestRestart())',
|
(ngModelChange)='config.save()'
|
||||||
ngbRadioGroup
|
|
||||||
)
|
)
|
||||||
label.btn.btn-secondary(ngbButtonLabel)
|
|
||||||
input(
|
|
||||||
type='radio',
|
|
||||||
ngbButton,
|
|
||||||
[value]='true'
|
|
||||||
)
|
|
||||||
| Enable
|
|
||||||
label.btn.btn-secondary(ngbButtonLabel)
|
|
||||||
input(
|
|
||||||
type='radio',
|
|
||||||
ngbButton,
|
|
||||||
[value]='false'
|
|
||||||
)
|
|
||||||
| Disable
|
|
||||||
|
|
||||||
.form-line(*ngIf='hostApp.platform !== Platform.Linux')
|
.form-line
|
||||||
.header
|
.header
|
||||||
.title Window opacity
|
.title Window opacity
|
||||||
input(
|
input(
|
||||||
type='range',
|
type='range',
|
||||||
[(ngModel)]='config.store.appearance.opacity',
|
[(ngModel)]='config.store.appearance.opacity',
|
||||||
(ngModelChange)='config.save()',
|
(ngModelChange)='config.save(); (hostApp.platform === Platform.Linux && config.requestRestart())',
|
||||||
min='0.05',
|
min='0.05',
|
||||||
max='1',
|
max='1',
|
||||||
step='0.01'
|
step='0.01'
|
||||||
@@ -259,8 +244,8 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
|||||||
td {{hotkey.id}}
|
td {{hotkey.id}}
|
||||||
td
|
td
|
||||||
multi-hotkey-input(
|
multi-hotkey-input(
|
||||||
'[(model)]'='config.store.hotkeys[hotkey.id]'
|
[(model)]='config.store.hotkeys[hotkey.id]',
|
||||||
'(modelChange)'='config.save(); docking.dock()'
|
(modelChange)='config.save(); docking.dock()'
|
||||||
)
|
)
|
||||||
|
|
||||||
ngb-tab(*ngFor='let provider of settingsProviders', [id]='provider.id')
|
ngb-tab(*ngFor='let provider of settingsProviders', [id]='provider.id')
|
||||||
|
@@ -3,6 +3,8 @@ import { BaseSession } from 'terminus-terminal'
|
|||||||
export interface LoginScript {
|
export interface LoginScript {
|
||||||
expect?: string
|
expect?: string
|
||||||
send: string
|
send: string
|
||||||
|
isRegex?: boolean
|
||||||
|
optional?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SSHConnection {
|
export interface SSHConnection {
|
||||||
@@ -37,15 +39,37 @@ export class SSHSession extends BaseSession {
|
|||||||
if (this.scripts) {
|
if (this.scripts) {
|
||||||
let found = false
|
let found = false
|
||||||
for (let script of this.scripts) {
|
for (let script of this.scripts) {
|
||||||
if (dataString.includes(script.expect)) {
|
let match = false
|
||||||
console.log('Executing script:', script.send)
|
let cmd = ''
|
||||||
this.shell.write(script.send + '\n')
|
if (script.isRegex) {
|
||||||
this.scripts = this.scripts.filter(x => x !== script)
|
let re = new RegExp(script.expect, 'g')
|
||||||
|
if (dataString.match(re)) {
|
||||||
|
cmd = dataString.replace(re, script.send)
|
||||||
|
match = true
|
||||||
found = true
|
found = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dataString.includes(script.expect)) {
|
||||||
|
cmd = script.send
|
||||||
|
match = true
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
console.log('Executing script: "' + cmd + '"')
|
||||||
|
this.shell.write(cmd + '\n')
|
||||||
|
this.scripts = this.scripts.filter(x => x !== script)
|
||||||
|
} else {
|
||||||
|
if (script.optional) {
|
||||||
|
console.log('Skip optional script: ' + script.expect)
|
||||||
|
found = true
|
||||||
|
this.scripts = this.scripts.filter(x => x !== script)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
this.executeUnconditionalScripts()
|
this.executeUnconditionalScripts()
|
||||||
|
@@ -94,6 +94,8 @@
|
|||||||
tr
|
tr
|
||||||
th String to expect
|
th String to expect
|
||||||
th String to be sent
|
th String to be sent
|
||||||
|
th Regex
|
||||||
|
th Optional
|
||||||
th Actions
|
th Actions
|
||||||
tr(*ngFor='let script of connection.scripts')
|
tr(*ngFor='let script of connection.scripts')
|
||||||
td
|
td
|
||||||
@@ -106,6 +108,14 @@
|
|||||||
type='text',
|
type='text',
|
||||||
[(ngModel)]='script.send'
|
[(ngModel)]='script.send'
|
||||||
)
|
)
|
||||||
|
td
|
||||||
|
toggle(
|
||||||
|
[(ngModel)]='script.isRegex',
|
||||||
|
)
|
||||||
|
td
|
||||||
|
toggle(
|
||||||
|
[(ngModel)]='script.optional',
|
||||||
|
)
|
||||||
td
|
td
|
||||||
.input-group.flex-nowrap
|
.input-group.flex-nowrap
|
||||||
button.btn.btn-outline-info.ml-0((click)='moveScriptUp(script)')
|
button.btn.btn-outline-info.ml-0((click)='moveScriptUp(script)')
|
||||||
@@ -127,6 +137,14 @@
|
|||||||
placeholder='Enter a string to be sent',
|
placeholder='Enter a string to be sent',
|
||||||
[(ngModel)]='newScript.send'
|
[(ngModel)]='newScript.send'
|
||||||
)
|
)
|
||||||
|
td
|
||||||
|
toggle(
|
||||||
|
[(ngModel)]='newScript.isRegex',
|
||||||
|
)
|
||||||
|
td
|
||||||
|
toggle(
|
||||||
|
[(ngModel)]='newScript.optional',
|
||||||
|
)
|
||||||
td
|
td
|
||||||
.input-group.flex-nowrap
|
.input-group.flex-nowrap
|
||||||
button.btn.btn-outline-info.ml-0((click)='addScript()')
|
button.btn.btn-outline-info.ml-0((click)='addScript()')
|
||||||
|
@@ -83,5 +83,7 @@ export class EditConnectionModalComponent {
|
|||||||
clearScript () {
|
clearScript () {
|
||||||
this.newScript.expect = ''
|
this.newScript.expect = ''
|
||||||
this.newScript.send = ''
|
this.newScript.send = ''
|
||||||
|
this.newScript.isRegex = false
|
||||||
|
this.newScript.optional = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ ng-template(#content)
|
|||||||
[style.width]='"100%"',
|
[style.width]='"100%"',
|
||||||
[style.background]='model',
|
[style.background]='model',
|
||||||
)
|
)
|
||||||
input.form-control(type='text', '[(ngModel)]'='model', (ngModelChange)='onChange()', #input)
|
input.form-control(type='text', [(ngModel)]='model', (ngModelChange)='onChange()', #input)
|
||||||
|
|
||||||
div(
|
div(
|
||||||
[ngbPopover]='content',
|
[ngbPopover]='content',
|
||||||
|
@@ -70,23 +70,23 @@ h3.mb-3 Appearance
|
|||||||
|
|
||||||
.form-group(*ngIf='editingColorScheme')
|
.form-group(*ngIf='editingColorScheme')
|
||||||
color-picker(
|
color-picker(
|
||||||
'[(model)]'='editingColorScheme.foreground',
|
[(model)]='editingColorScheme.foreground',
|
||||||
(modelChange)='config.save(); schemeChanged = true',
|
(modelChange)='config.save(); schemeChanged = true',
|
||||||
title='FG',
|
title='FG',
|
||||||
)
|
)
|
||||||
color-picker(
|
color-picker(
|
||||||
'[(model)]'='editingColorScheme.background',
|
[(model)]='editingColorScheme.background',
|
||||||
(modelChange)='config.save(); schemeChanged = true',
|
(modelChange)='config.save(); schemeChanged = true',
|
||||||
title='BG',
|
title='BG',
|
||||||
)
|
)
|
||||||
color-picker(
|
color-picker(
|
||||||
'[(model)]'='editingColorScheme.cursor',
|
[(model)]='editingColorScheme.cursor',
|
||||||
(modelChange)='config.save(); schemeChanged = true',
|
(modelChange)='config.save(); schemeChanged = true',
|
||||||
title='CU',
|
title='CU',
|
||||||
)
|
)
|
||||||
color-picker(
|
color-picker(
|
||||||
*ngFor='let _ of editingColorScheme.colors; let idx = index; trackBy: colorsTrackBy',
|
*ngFor='let _ of editingColorScheme.colors; let idx = index; trackBy: colorsTrackBy',
|
||||||
'[(model)]'='editingColorScheme.colors[idx]',
|
[(model)]='editingColorScheme.colors[idx]',
|
||||||
(modelChange)='config.save(); schemeChanged = true',
|
(modelChange)='config.save(); schemeChanged = true',
|
||||||
[title]='idx',
|
[title]='idx',
|
||||||
)
|
)
|
||||||
|
@@ -43,6 +43,10 @@ export class XTermFrontend extends Frontend {
|
|||||||
|
|
||||||
host.addEventListener('dragOver', (event: any) => this.dragOver.next(event))
|
host.addEventListener('dragOver', (event: any) => this.dragOver.next(event))
|
||||||
host.addEventListener('drop', event => this.drop.next(event))
|
host.addEventListener('drop', event => this.drop.next(event))
|
||||||
|
|
||||||
|
host.addEventListener('mousedown', event => this.mouseEvent.next(event))
|
||||||
|
host.addEventListener('mouseup', event => this.mouseEvent.next(event))
|
||||||
|
host.addEventListener('mousewheel', event => this.mouseEvent.next(event))
|
||||||
}
|
}
|
||||||
|
|
||||||
detach (host: HTMLElement): void {
|
detach (host: HTMLElement): void {
|
||||||
|
@@ -57,8 +57,13 @@ hterm.hterm.Terminal.prototype.applyCursorShape = function () {
|
|||||||
console.warn('Unknown cursor style: ' + modeNumber)
|
console.warn('Unknown cursor style: ' + modeNumber)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
setTimeout(() => {
|
||||||
this.setCursorShape(modes[modeNumber][0])
|
this.setCursorShape(modes[modeNumber][0])
|
||||||
this.setCursorBlink(modes[modeNumber][1])
|
this.setCursorBlink(modes[modeNumber][1])
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setCursorVisible(true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
hterm.hterm.VT.CSI[' q'] = function (parseState) {
|
hterm.hterm.VT.CSI[' q'] = function (parseState) {
|
||||||
|
@@ -7,7 +7,6 @@ import { WSLShellProvider } from './wsl'
|
|||||||
import { PowerShellCoreShellProvider } from './powershellCore'
|
import { PowerShellCoreShellProvider } from './powershellCore'
|
||||||
import { WindowsStockShellsProvider } from './windowsStock'
|
import { WindowsStockShellsProvider } from './windowsStock'
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WindowsDefaultShellProvider extends ShellProvider {
|
export class WindowsDefaultShellProvider extends ShellProvider {
|
||||||
private providers: ShellProvider[]
|
private providers: ShellProvider[]
|
||||||
|
@@ -18,11 +18,25 @@ export class WSLShellProvider extends ShellProvider {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bashPath = `${process.env.windir}\\system32\\bash.exe`
|
||||||
const wslPath = `${process.env.windir}\\system32\\wsl.exe`
|
const wslPath = `${process.env.windir}\\system32\\wsl.exe`
|
||||||
const wslConfigPath = `${process.env.windir}\\system32\\wslconfig.exe`
|
const wslConfigPath = `${process.env.windir}\\system32\\wslconfig.exe`
|
||||||
|
|
||||||
if (!await fs.exists(wslPath)) {
|
if (!await fs.exists(wslPath)) {
|
||||||
|
if (await fs.exists(bashPath)) {
|
||||||
|
return [{
|
||||||
|
id: 'wsl',
|
||||||
|
name: 'WSL / Bash on Windows',
|
||||||
|
command: bashPath,
|
||||||
|
env: {
|
||||||
|
TERM: 'xterm-color',
|
||||||
|
COLORTERM: 'truecolor',
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
} else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let lines = (await exec(`${wslConfigPath} /l`, { encoding: 'ucs2' }))[0].toString().split('\n').splice(1)
|
let lines = (await exec(`${wslConfigPath} /l`, { encoding: 'ucs2' }))[0].toString().split('\n').splice(1)
|
||||||
let shells: IShell[] = [{
|
let shells: IShell[] = [{
|
||||||
|
Reference in New Issue
Block a user