mirror of
https://github.com/Eugeny/tabby.git
synced 2024-11-24 06:04:04 +03:00
make shell providers pluggable
This commit is contained in:
parent
17ad43bf65
commit
1f825b16c1
@ -5,14 +5,15 @@ export class Logger {
|
||||
private name: string,
|
||||
) {}
|
||||
|
||||
log (level: string, ...args: any[]) {
|
||||
doLog (level: string, ...args: any[]) {
|
||||
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.doLog('debug', ...args) }
|
||||
info (...args: any[]) { this.doLog('info', ...args) }
|
||||
warn (...args: any[]) { this.doLog('warn', ...args) }
|
||||
error (...args: any[]) { this.doLog('error', ...args) }
|
||||
log (...args: any[]) { this.doLog('log', ...args) }
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
@ -44,3 +44,15 @@ export interface ITerminalColorScheme {
|
||||
export abstract class TerminalColorSchemeProvider {
|
||||
abstract async getSchemes (): Promise<ITerminalColorScheme[]>
|
||||
}
|
||||
|
||||
export interface IShell {
|
||||
id: string
|
||||
name: string
|
||||
command: string
|
||||
args?: string[]
|
||||
env?: any
|
||||
}
|
||||
|
||||
export abstract class ShellProvider {
|
||||
abstract async provide (): Promise<IShell[]>
|
||||
}
|
||||
|
@ -1,24 +1,34 @@
|
||||
import { AsyncSubject } from 'rxjs'
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService, HostAppService, Platform, ElectronService } from 'terminus-core'
|
||||
import { Injectable, Inject } from '@angular/core'
|
||||
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService, HostAppService, ElectronService, Logger, LogService } from 'terminus-core'
|
||||
|
||||
import { IShell, ShellProvider } from './api'
|
||||
import { SessionsService } from './services/sessions.service'
|
||||
import { ShellsService } from './services/shells.service'
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
|
||||
@Injectable()
|
||||
export class ButtonProvider extends ToolbarButtonProvider {
|
||||
private shells$ = new AsyncSubject<IShell[]>()
|
||||
private logger: Logger
|
||||
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private sessions: SessionsService,
|
||||
private config: ConfigService,
|
||||
private shells: ShellsService,
|
||||
private hostApp: HostAppService,
|
||||
log: LogService,
|
||||
hostApp: HostAppService,
|
||||
@Inject(ShellProvider) shellProviders: ShellProvider[],
|
||||
electron: ElectronService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
this.logger = log.create('newTerminalButton')
|
||||
Promise.all(shellProviders.map(x => x.provide())).then(shellLists => {
|
||||
this.shells$.next(shellLists.reduce((a, b) => a.concat(b)))
|
||||
this.shells$.complete()
|
||||
})
|
||||
hotkeys.matchedHotkey.subscribe(async (hotkey) => {
|
||||
if (hotkey === 'new-tab') {
|
||||
this.openNewTab()
|
||||
@ -50,24 +60,20 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
if (!cwd && this.app.activeTab instanceof TerminalTabComponent) {
|
||||
cwd = await this.app.activeTab.session.getWorkingDirectory()
|
||||
}
|
||||
let command = this.config.store.terminal.shell
|
||||
let env: any = process.env
|
||||
let args: string[] = []
|
||||
if (command === '~clink~') {
|
||||
({ command, args } = this.shells.getClinkOptions())
|
||||
}
|
||||
if (command === '~default-shell~') {
|
||||
command = await this.shells.getDefaultShell()
|
||||
}
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
env.TERM = 'cygwin'
|
||||
}
|
||||
let shells = await this.shells$.first().toPromise()
|
||||
let shell = shells.find(x => x.id === this.config.store.terminal.shell) || shells[0]
|
||||
let env: any = Object.assign({}, process.env, shell.env || {})
|
||||
|
||||
this.logger.log(`Starting shell ${shell.name}`, shell)
|
||||
let sessionOptions = await this.sessions.prepareNewSession({
|
||||
command,
|
||||
args,
|
||||
command: shell.command,
|
||||
args: shell.args || [],
|
||||
cwd,
|
||||
env,
|
||||
})
|
||||
|
||||
this.logger.log('Using session options:', sessionOptions)
|
||||
|
||||
this.app.openNewTab(
|
||||
TerminalTabComponent,
|
||||
{ sessionOptions }
|
||||
|
@ -1,23 +1,11 @@
|
||||
import { Observable } from 'rxjs'
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import { exec } from 'mz/child_process'
|
||||
const equal = require('deep-equal')
|
||||
const fontManager = require('font-manager')
|
||||
|
||||
import { Component, Inject } from '@angular/core'
|
||||
import { ConfigService, HostAppService, Platform } from 'terminus-core'
|
||||
import { TerminalColorSchemeProvider, ITerminalColorScheme } from '../api'
|
||||
|
||||
let Registry = null
|
||||
try {
|
||||
Registry = require('winreg')
|
||||
} catch (_) { } // tslint:disable-line no-empty
|
||||
|
||||
interface IShell {
|
||||
name: string
|
||||
command: string
|
||||
}
|
||||
import { TerminalColorSchemeProvider, ITerminalColorScheme, IShell, ShellProvider } from '../api'
|
||||
|
||||
@Component({
|
||||
template: require('./terminalSettingsTab.component.pug'),
|
||||
@ -34,6 +22,7 @@ export class TerminalSettingsTabComponent {
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
@Inject(ShellProvider) private shellProviders: ShellProvider[],
|
||||
@Inject(TerminalColorSchemeProvider) private colorSchemeProviders: TerminalColorSchemeProvider[],
|
||||
) { }
|
||||
|
||||
@ -53,71 +42,8 @@ export class TerminalSettingsTabComponent {
|
||||
this.fonts.sort()
|
||||
})
|
||||
}
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
this.shells = [
|
||||
{ name: 'CMD (clink)', command: '~clink~' },
|
||||
{ name: 'CMD (stock)', command: 'cmd.exe' },
|
||||
{ name: 'PowerShell', command: 'powershell.exe' },
|
||||
]
|
||||
|
||||
// Detect whether BoW is installed
|
||||
const wslPath = `${process.env.windir}\\system32\\bash.exe`
|
||||
if (await fs.exists(wslPath)) {
|
||||
this.shells.push({ name: 'Bash on Windows', command: wslPath })
|
||||
}
|
||||
|
||||
// Detect Cygwin
|
||||
let cygwinPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x64' })
|
||||
reg.get('rootdir', (err, item) => {
|
||||
if (err) {
|
||||
return resolve(null)
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
if (cygwinPath) {
|
||||
this.shells.push({ name: 'Cygwin', command: path.join(cygwinPath, 'bin', 'bash.exe') })
|
||||
}
|
||||
|
||||
// Detect 32-bit Cygwin
|
||||
let cygwin32Path = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x86' })
|
||||
reg.get('rootdir', (err, item) => {
|
||||
if (err) {
|
||||
return resolve(null)
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
if (cygwin32Path) {
|
||||
this.shells.push({ name: 'Cygwin (32 bit)', command: path.join(cygwin32Path, 'bin', 'bash.exe') })
|
||||
}
|
||||
|
||||
// Detect Git-Bash
|
||||
let gitBashPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\GitForWindows' })
|
||||
reg.get('InstallPath', (err, item) => {
|
||||
if (err) {
|
||||
resolve(null)
|
||||
return
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
if (gitBashPath) {
|
||||
this.shells.push({ name: 'Git-Bash', command: path.join(gitBashPath, 'bin', 'bash.exe') })
|
||||
}
|
||||
}
|
||||
if (this.hostApp.platform === Platform.Linux || this.hostApp.platform === Platform.macOS) {
|
||||
this.shells = [{ name: 'Default shell', command: '~default-shell~' }]
|
||||
this.shells = this.shells.concat((await fs.readFile('/etc/shells', { encoding: 'utf-8' }))
|
||||
.split('\n')
|
||||
.map(x => x.trim())
|
||||
.filter(x => x && !x.startsWith('#'))
|
||||
.map(x => ({ name: x, command: x })))
|
||||
}
|
||||
this.colorSchemes = (await Promise.all(this.colorSchemeProviders.map(x => x.getSchemes()))).reduce((a, b) => a.concat(b))
|
||||
this.shells = (await Promise.all(this.shellProviders.map(x => x.provide()))).reduce((a, b) => a.concat(b))
|
||||
}
|
||||
|
||||
fontAutocomplete = (text$: Observable<string>) => {
|
||||
|
@ -11,18 +11,27 @@ import { TerminalSettingsTabComponent } from './components/terminalSettingsTab.c
|
||||
import { ColorPickerComponent } from './components/colorPicker.component'
|
||||
|
||||
import { SessionsService } from './services/sessions.service'
|
||||
import { ShellsService } from './services/shells.service'
|
||||
|
||||
import { ScreenPersistenceProvider } from './persistenceProviders'
|
||||
import { TMuxPersistenceProvider } from './tmux'
|
||||
import { ButtonProvider } from './buttonProvider'
|
||||
import { RecoveryProvider } from './recoveryProvider'
|
||||
import { SessionPersistenceProvider, TerminalColorSchemeProvider, TerminalDecorator } from './api'
|
||||
import { SessionPersistenceProvider, TerminalColorSchemeProvider, TerminalDecorator, ShellProvider } from './api'
|
||||
import { TerminalSettingsTabProvider } from './settings'
|
||||
import { PathDropDecorator } from './pathDrop'
|
||||
import { TerminalConfigProvider } from './config'
|
||||
import { TerminalHotkeyProvider } from './hotkeys'
|
||||
import { HyperColorSchemes } from './colorSchemes'
|
||||
|
||||
import { Cygwin32ShellProvider } from './shells/cygwin32'
|
||||
import { Cygwin64ShellProvider } from './shells/cygwin64'
|
||||
import { GitBashShellProvider } from './shells/gitBash'
|
||||
import { LinuxDefaultShellProvider } from './shells/linuxDefault'
|
||||
import { MacOSDefaultShellProvider } from './shells/macDefault'
|
||||
import { POSIXShellsProvider } from './shells/posix'
|
||||
import { WindowsStockShellsProvider } from './shells/windowsStock'
|
||||
import { WSLShellProvider } from './shells/wsl'
|
||||
|
||||
import { hterm } from './hterm'
|
||||
|
||||
@NgModule({
|
||||
@ -33,7 +42,6 @@ import { hterm } from './hterm'
|
||||
],
|
||||
providers: [
|
||||
SessionsService,
|
||||
ShellsService,
|
||||
ScreenPersistenceProvider,
|
||||
TMuxPersistenceProvider,
|
||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||
@ -63,6 +71,15 @@ import { hterm } from './hterm'
|
||||
{ provide: HotkeyProvider, useClass: TerminalHotkeyProvider, multi: true },
|
||||
{ provide: TerminalColorSchemeProvider, useClass: HyperColorSchemes, multi: true },
|
||||
{ provide: TerminalDecorator, useClass: PathDropDecorator, multi: true },
|
||||
|
||||
{ provide: ShellProvider, useClass: WindowsStockShellsProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: MacOSDefaultShellProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: LinuxDefaultShellProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: Cygwin32ShellProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: Cygwin64ShellProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: GitBashShellProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: POSIXShellsProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: WSLShellProvider, multi: true },
|
||||
],
|
||||
entryComponents: [
|
||||
TerminalTabComponent,
|
||||
|
@ -1,58 +0,0 @@
|
||||
import * as path from 'path'
|
||||
import { exec } from 'mz/child_process'
|
||||
import * as fs from 'mz/fs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ElectronService, HostAppService, Platform, Logger, LogService } from 'terminus-core'
|
||||
|
||||
@Injectable()
|
||||
export class ShellsService {
|
||||
private logger: Logger
|
||||
|
||||
constructor (
|
||||
log: LogService,
|
||||
private electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
this.logger = log.create('shells')
|
||||
}
|
||||
|
||||
getClinkOptions (): { command, args } {
|
||||
return {
|
||||
command: 'cmd.exe',
|
||||
args: [
|
||||
'/k',
|
||||
path.join(
|
||||
path.dirname(this.electron.app.getPath('exe')),
|
||||
'resources',
|
||||
'clink',
|
||||
`clink_${process.arch}.exe`,
|
||||
),
|
||||
'inject',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async getDefaultShell (): Promise<string> {
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
return this.getDefaultMacOSShell()
|
||||
} else {
|
||||
return this.getDefaultLinuxShell()
|
||||
}
|
||||
}
|
||||
|
||||
async getDefaultMacOSShell (): Promise<string> {
|
||||
let shellEntry = (await exec(`dscl . -read /Users/${process.env.LOGNAME} UserShell`))[0].toString()
|
||||
return shellEntry.split(' ')[1].trim()
|
||||
}
|
||||
|
||||
async getDefaultLinuxShell (): Promise<string> {
|
||||
let line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' }))
|
||||
.split('\n').find(x => x.startsWith(process.env.LOGNAME + ':'))
|
||||
if (!line) {
|
||||
this.logger.warn('Could not detect user shell')
|
||||
return '/bin/sh'
|
||||
} else {
|
||||
return line.split(':')[6]
|
||||
}
|
||||
}
|
||||
}
|
19
terminus-terminal/src/shellProviders.ts
Normal file
19
terminus-terminal/src/shellProviders.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ConfigService, HostAppService, Platform, ElectronService } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from './api'
|
||||
|
||||
@Injectable()
|
||||
export class POSIXShellsProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
|
||||
}
|
||||
}
|
48
terminus-terminal/src/shells/cygwin32.ts
Normal file
48
terminus-terminal/src/shells/cygwin32.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
let Registry = null
|
||||
try {
|
||||
Registry = require('winreg')
|
||||
} catch (_) { } // tslint:disable-line no-empty
|
||||
|
||||
@Injectable()
|
||||
export class Cygwin32ShellProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.Windows) {
|
||||
return []
|
||||
}
|
||||
|
||||
let cygwinPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x86' })
|
||||
reg.get('rootdir', (err, item) => {
|
||||
if (err) {
|
||||
return resolve(null)
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
|
||||
if (!cygwinPath) {
|
||||
return []
|
||||
}
|
||||
|
||||
return [{
|
||||
id: 'cygwin32',
|
||||
name: 'Cygwin (32 bit)',
|
||||
command: path.join(cygwinPath, 'bin', 'bash.exe'),
|
||||
env: {
|
||||
TERM: 'cygwin',
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
48
terminus-terminal/src/shells/cygwin64.ts
Normal file
48
terminus-terminal/src/shells/cygwin64.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
let Registry = null
|
||||
try {
|
||||
Registry = require('winreg')
|
||||
} catch (_) { } // tslint:disable-line no-empty
|
||||
|
||||
@Injectable()
|
||||
export class Cygwin64ShellProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.Windows) {
|
||||
return []
|
||||
}
|
||||
|
||||
let cygwinPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x64' })
|
||||
reg.get('rootdir', (err, item) => {
|
||||
if (err) {
|
||||
return resolve(null)
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
|
||||
if (!cygwinPath) {
|
||||
return []
|
||||
}
|
||||
|
||||
return [{
|
||||
id: 'cygwin64',
|
||||
name: 'Cygwin',
|
||||
command: path.join(cygwinPath, 'bin', 'bash.exe'),
|
||||
env: {
|
||||
TERM: 'cygwin',
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
49
terminus-terminal/src/shells/gitBash.ts
Normal file
49
terminus-terminal/src/shells/gitBash.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
let Registry = null
|
||||
try {
|
||||
Registry = require('winreg')
|
||||
} catch (_) { } // tslint:disable-line no-empty
|
||||
|
||||
@Injectable()
|
||||
export class GitBashShellProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.Windows) {
|
||||
return []
|
||||
}
|
||||
|
||||
let gitBashPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\GitForWindows' })
|
||||
reg.get('InstallPath', (err, item) => {
|
||||
if (err) {
|
||||
resolve(null)
|
||||
return
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
|
||||
if (!gitBashPath) {
|
||||
return []
|
||||
}
|
||||
|
||||
return [{
|
||||
id: 'git-bash',
|
||||
name: 'Git-Bash',
|
||||
command: path.join(gitBashPath, 'bin', 'bash.exe'),
|
||||
env: {
|
||||
TERM: 'cygwin',
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
40
terminus-terminal/src/shells/linuxDefault.ts
Normal file
40
terminus-terminal/src/shells/linuxDefault.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform, LogService, Logger } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
@Injectable()
|
||||
export class LinuxDefaultShellProvider extends ShellProvider {
|
||||
private logger: Logger
|
||||
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
log: LogService,
|
||||
) {
|
||||
super()
|
||||
this.logger = log.create('linuxDefaultShell')
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.Linux) {
|
||||
return []
|
||||
}
|
||||
let line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' }))
|
||||
.split('\n').find(x => x.startsWith(process.env.LOGNAME + ':'))
|
||||
if (!line) {
|
||||
this.logger.warn('Could not detect user shell')
|
||||
return [{
|
||||
id: 'default',
|
||||
name: 'User default',
|
||||
command: '/bin/sh'
|
||||
}]
|
||||
} else {
|
||||
return [{
|
||||
id: 'default',
|
||||
name: 'User default',
|
||||
command: line.split(':')[6]
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
26
terminus-terminal/src/shells/macDefault.ts
Normal file
26
terminus-terminal/src/shells/macDefault.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { exec } from 'mz/child_process'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
@Injectable()
|
||||
export class MacOSDefaultShellProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.macOS) {
|
||||
return []
|
||||
}
|
||||
let shellEntry = (await exec(`dscl . -read /Users/${process.env.LOGNAME} UserShell`))[0].toString()
|
||||
return [{
|
||||
id: 'default',
|
||||
name: 'User default',
|
||||
command: shellEntry.split(' ')[1].trim()
|
||||
}]
|
||||
}
|
||||
}
|
29
terminus-terminal/src/shells/posix.ts
Normal file
29
terminus-terminal/src/shells/posix.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
@Injectable()
|
||||
export class POSIXShellsProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
return []
|
||||
}
|
||||
return (await fs.readFile('/etc/shells', { encoding: 'utf-8' }))
|
||||
.split('\n')
|
||||
.map(x => x.trim())
|
||||
.filter(x => x && !x.startsWith('#'))
|
||||
.map(x => ({
|
||||
id: x,
|
||||
name: x,
|
||||
command: x,
|
||||
}))
|
||||
}
|
||||
}
|
40
terminus-terminal/src/shells/windowsStock.ts
Normal file
40
terminus-terminal/src/shells/windowsStock.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform, ElectronService } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
@Injectable()
|
||||
export class WindowsStockShellsProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private electron: ElectronService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.Windows) {
|
||||
return []
|
||||
}
|
||||
return [
|
||||
{
|
||||
id: 'clink',
|
||||
name: 'CMD (clink)',
|
||||
command: 'cmd.exe',
|
||||
args: [
|
||||
'/k',
|
||||
path.join(
|
||||
path.dirname(this.electron.app.getPath('exe')),
|
||||
'resources',
|
||||
'clink',
|
||||
`clink_${process.arch}.exe`,
|
||||
),
|
||||
'inject',
|
||||
]
|
||||
},
|
||||
{ id: 'cmd', name: 'CMD (stock)', command: 'cmd.exe' },
|
||||
{ id: 'powershell', name: 'PowerShell', command: 'powershell.exe' },
|
||||
]
|
||||
}
|
||||
}
|
31
terminus-terminal/src/shells/wsl.ts
Normal file
31
terminus-terminal/src/shells/wsl.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
import { ShellProvider, IShell } from '../api'
|
||||
|
||||
@Injectable()
|
||||
export class WSLShellProvider extends ShellProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (): Promise<IShell[]> {
|
||||
if (this.hostApp.platform !== Platform.Windows) {
|
||||
return []
|
||||
}
|
||||
|
||||
const wslPath = `${process.env.windir}\\system32\\bash.exe`
|
||||
if (!await fs.exists(wslPath)) {
|
||||
return []
|
||||
}
|
||||
|
||||
return [{
|
||||
id: 'wsl',
|
||||
name: 'Bash on Windows',
|
||||
command: wslPath
|
||||
}]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user