Compare commits

..

23 Commits

Author SHA1 Message Date
Eugene Pankov
5a5cd09832 Merge branch 'master' of github.com:Eugeny/terminus 2018-10-08 11:31:36 +02:00
Eugene Pankov
c2f4c343a7 Revert "use npms.io instead of npmjs.org for plugin search"
This reverts commit 9c6f2747aa.
2018-10-08 11:30:52 +02:00
Eugene
153cd1ec9a Merge pull request #437 from Domain/master
Support regex and optional script
2018-10-08 08:43:15 +02:00
Domain
0254cabdde lint 2018-10-08 14:02:20 +08:00
Domain
9eee600ccc optional script 2018-10-08 14:02:19 +08:00
Domain
24288fac9a add regex support 2018-10-08 14:02:18 +08:00
Eugene Pankov
441164363f transparency support on Linux 2018-10-06 20:50:06 +02:00
Eugene Pankov
3d7a4a1e0e build fix 2018-10-06 20:31:50 +02:00
Eugene Pankov
7984313b06 dropped electron-vibrancy 2018-10-05 21:25:44 +02:00
Eugene Pankov
89cc6c0d20 build fix 2018-10-05 20:20:21 +02:00
Eugene Pankov
d104f5e771 reimplemented Windows vibrancy using windows-swca and windows-blurbehind (#383) 2018-10-05 11:12:06 -07:00
Eugene Pankov
5b5d145bd0 lint 2018-10-05 11:36:37 +01:00
Eugene Pankov
78212a9538 build fix 2018-10-05 11:36:15 +01:00
Eugene Pankov
1b1b2af545 possibly fixed cursor blink interval overlaps (fixes #216) 2018-10-05 10:24:28 +01:00
Eugene Pankov
f3f969a006 fixed cursor visibility (fixes #439) 2018-10-05 10:18:34 +01:00
Eugene Pankov
621a6d8127 cleanup 2018-10-05 10:10:02 +01:00
Eugene Pankov
87933edb96 fixed context menu and xterm mouse events (fixes #442) 2018-10-05 10:02:03 +01:00
Eugene Pankov
a931d47c23 auto-update terminus path in registry (fixes #447) 2018-10-05 09:47:04 +01:00
Eugene Pankov
1ae027f17c ci 2018-10-03 22:44:04 +01:00
Eugene
5360b2f292 Merge pull request #443 from vsailev/master
Restore Bash on Windows
2018-10-03 21:57:36 +01:00
vsailev
d806fb6e1e Restore Bash on Windows 2018-10-03 21:15:16 +01:00
Eugene Pankov
57de182013 Merge branch 'master' of github.com:Eugeny/terminus 2018-09-25 10:48:24 +02:00
Eugene Pankov
3fd57e81a6 install terminus into /usr/bin on Debian (fixes #433) 2018-09-25 10:48:00 +02:00
25 changed files with 187 additions and 96 deletions

View File

@@ -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
View 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 {}
}
}

View File

@@ -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()

View File

@@ -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 () {

View File

@@ -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"
} }

View File

@@ -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(),

View File

@@ -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"

View File

@@ -4,7 +4,7 @@ platform:
- x64 - x64
environment: environment:
nodejs_version: "7" nodejs_version: "10"
cache: cache:
- '%USERPROFILE%\.electron' - '%USERPROFILE%\.electron'

View File

@@ -0,0 +1,4 @@
#!/bin/bash
# Link to the binary
ln -sf '/opt/${productFilename}/${executable}' '/usr/bin/${executable}'

View File

@@ -120,7 +120,8 @@
"libxtst6", "libxtst6",
"libnss3", "libnss3",
"tmux" "tmux"
] ],
"afterInstall": "build/linux/after-install.tpl"
}, },
"rpm": { "rpm": {
"depends": [ "depends": [

View File

@@ -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 {

View File

@@ -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 () {

View File

@@ -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> {

View File

@@ -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'
) )

View File

@@ -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,

View File

@@ -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')

View File

@@ -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()

View File

@@ -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()')

View File

@@ -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
} }
} }

View File

@@ -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',

View File

@@ -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',
) )

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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[]

View File

@@ -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[] = [{