提交 57227ae6 编写于 作者: E Eugene Pankov

Merge branch 'master' of github.com:Eugeny/terminus

...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* Doesn't choke on fast-flowing outputs * Doesn't choke on fast-flowing outputs
* Tab persistence on macOS and Linux * Tab persistence on macOS and Linux
* Proper shell-like experience on Windows including tab completion (thanks, Clink!) * Proper shell-like experience on Windows including tab completion (thanks, Clink!)
* CMD, PowerShell and Bash on Windows support * CMD, PowerShell, Cygwin, Git-Bash and Bash on Windows support
--- ---
......
...@@ -16,5 +16,4 @@ exports.builtinPlugins = [ ...@@ -16,5 +16,4 @@ exports.builtinPlugins = [
'terminus-plugin-manager', 'terminus-plugin-manager',
] ]
exports.nativeModules = ['node-pty', 'font-manager'] exports.nativeModules = ['node-pty', 'font-manager']
exports.version = appInfo.version
exports.electronVersion = pkgInfo.devDependencies.electron exports.electronVersion = pkgInfo.devDependencies.electron
...@@ -40,12 +40,12 @@ export class DockingService { ...@@ -40,12 +40,12 @@ export class DockingService {
newBounds.height = Math.round(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 + Math.round(display.bounds.width * (1.0 - fill))
} else { } else {
newBounds.x = display.bounds.x newBounds.x = display.bounds.x
} }
if (dockSide === 'bottom') { if (dockSide === 'bottom') {
newBounds.y = display.bounds.y + display.bounds.height * (1.0 - fill) newBounds.y = display.bounds.y + Math.round(display.bounds.height * (1.0 - fill))
} else { } else {
newBounds.y = display.bounds.y newBounds.y = display.bounds.y
} }
......
...@@ -109,17 +109,17 @@ ngb-tabset.vertical(type='tabs') ...@@ -109,17 +109,17 @@ ngb-tabset.vertical(type='tabs')
label Display on label Display on
br br
div( div(
'[(ngModel)]'='config.store.appearance.dockScreen' [(ngModel)]='config.store.appearance.dockScreen',
'(ngModelChange)'='config.save(); docking.dock()' (ngModelChange)='config.save(); docking.dock()',
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary
input( input(
type='radio', type='radio',
[value]='"current"' value='current'
) )
| Current | Current
label.btn.btn-secondary(*ngFor='let screen of docking.getScreens()') label.btn.btn-secondary(*ngFor='let screen of screens')
input( input(
type='radio', type='radio',
[value]='screen.id' [value]='screen.id'
......
...@@ -14,6 +14,7 @@ import { SettingsTabProvider } from '../api' ...@@ -14,6 +14,7 @@ import { SettingsTabProvider } from '../api'
export class SettingsTabComponent extends BaseTabComponent { export class SettingsTabComponent extends BaseTabComponent {
hotkeyFilter = '' hotkeyFilter = ''
private hotkeyDescriptions: IHotkeyDescription[] private hotkeyDescriptions: IHotkeyDescription[]
private screens
constructor ( constructor (
public config: ConfigService, public config: ConfigService,
...@@ -28,6 +29,7 @@ export class SettingsTabComponent extends BaseTabComponent { ...@@ -28,6 +29,7 @@ export class SettingsTabComponent extends BaseTabComponent {
this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b)) this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b))
this.title$.next('Settings') this.title$.next('Settings')
this.scrollable = true this.scrollable = true
this.screens = this.docking.getScreens()
} }
getRecoveryToken (): any { getRecoveryToken (): any {
......
import * as path from 'path' import * as path from 'path'
import { exec } from 'mz/child_process'
import * as fs from 'mz/fs'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService, ElectronService } from 'terminus-core' import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService, ElectronService, HostAppService, Platform } from 'terminus-core'
import { SessionsService } from './services/sessions.service' import { SessionsService } from './services/sessions.service'
import { TerminalTabComponent } from './components/terminalTab.component' import { TerminalTabComponent } from './components/terminalTab.component'
...@@ -12,6 +14,7 @@ export class ButtonProvider extends ToolbarButtonProvider { ...@@ -12,6 +14,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
private sessions: SessionsService, private sessions: SessionsService,
private config: ConfigService, private config: ConfigService,
private electron: ElectronService, private electron: ElectronService,
private hostApp: HostAppService,
hotkeys: HotkeysService, hotkeys: HotkeysService,
) { ) {
super() super()
...@@ -43,6 +46,22 @@ export class ButtonProvider extends ToolbarButtonProvider { ...@@ -43,6 +46,22 @@ export class ButtonProvider extends ToolbarButtonProvider {
'inject', 'inject',
] ]
} }
if (command === '~default-shell~') {
if (this.hostApp.platform === Platform.Linux) {
let line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' }))
.split('\n').find(x => x.startsWith(process.env.LOGNAME + ':'))
if (!line) {
console.warn('Could not detect user shell')
command = '/bin/sh'
} else {
command = line.split(':')[5]
}
}
if (this.hostApp.platform === Platform.macOS) {
let shellEntry = (await exec(`dscl . -read /Users/${process.env.LOGNAME} UserShell`))[0].toString()
command = shellEntry.split(':')[1].trim()
}
}
let sessionOptions = await this.sessions.prepareNewSession({ command, args, cwd }) let sessionOptions = await this.sessions.prepareNewSession({ command, args, cwd })
this.app.openNewTab( this.app.openNewTab(
TerminalTabComponent, TerminalTabComponent,
......
import { Observable } from 'rxjs' import { Observable } from 'rxjs'
import * as fs from 'fs-promise' import * as fs from 'mz/fs'
import * as path from 'path' import * as path from 'path'
import { exec } from 'mz/child_process' import { exec } from 'mz/child_process'
const equal = require('deep-equal') const equal = require('deep-equal')
...@@ -59,16 +59,20 @@ export class TerminalSettingsTabComponent { ...@@ -59,16 +59,20 @@ export class TerminalSettingsTabComponent {
{ name: 'CMD (stock)', command: 'cmd.exe' }, { name: 'CMD (stock)', command: 'cmd.exe' },
{ name: 'PowerShell', command: 'powershell.exe' }, { name: 'PowerShell', command: 'powershell.exe' },
] ]
// Detect whether BoW is installed
const wslPath = `${process.env.windir}\\system32\\bash.exe` const wslPath = `${process.env.windir}\\system32\\bash.exe`
if (await fs.exists(wslPath)) { if (await fs.exists(wslPath)) {
this.shells.push({ name: 'Bash on Windows', command: wslPath }) this.shells.push({ name: 'Bash on Windows', command: wslPath })
} }
// Detect Cygwin
let cygwinPath = await new Promise<string>(resolve => { let cygwinPath = await new Promise<string>(resolve => {
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup' }) let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup' })
reg.get('rootdir', (err, item) => { reg.get('rootdir', (err, item) => {
if (err) { if (err) {
resolve(null) resolve(null)
return
} }
resolve(item.value) resolve(item.value)
}) })
...@@ -76,13 +80,29 @@ export class TerminalSettingsTabComponent { ...@@ -76,13 +80,29 @@ export class TerminalSettingsTabComponent {
if (cygwinPath) { if (cygwinPath) {
this.shells.push({ name: 'Cygwin', command: path.join(cygwinPath, 'bin', 'bash.exe') }) this.shells.push({ name: 'Cygwin', command: path.join(cygwinPath, '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) { if (this.hostApp.platform === Platform.Linux || this.hostApp.platform === Platform.macOS) {
this.shells = (await fs.readFile('/etc/shells', 'utf-8')) this.shells = [{ name: 'Default shell', command: '~default-shell~' }]
this.shells = this.shells.concat((await fs.readFile('/etc/shells', { encoding: 'utf-8' }))
.split('\n') .split('\n')
.map(x => x.trim()) .map(x => x.trim())
.filter(x => x && !x.startsWith('#')) .filter(x => x && !x.startsWith('#'))
.map(x => ({ name: x, command: x })) .map(x => ({ name: x, command: x })))
} }
this.colorSchemes = (await Promise.all(this.colorSchemeProviders.map(x => x.getSchemes()))).reduce((a, b) => a.concat(b)) this.colorSchemes = (await Promise.all(this.colorSchemeProviders.map(x => x.getSchemes()))).reduce((a, b) => a.concat(b))
} }
......
...@@ -40,7 +40,7 @@ export class TerminalConfigProvider extends ConfigProvider { ...@@ -40,7 +40,7 @@ export class TerminalConfigProvider extends ConfigProvider {
[Platform.macOS]: { [Platform.macOS]: {
terminal: { terminal: {
font: 'Menlo', font: 'Menlo',
shell: '/bin/zsh', shell: '~default-shell~',
}, },
hotkeys: { hotkeys: {
'new-tab': [ 'new-tab': [
...@@ -67,7 +67,7 @@ export class TerminalConfigProvider extends ConfigProvider { ...@@ -67,7 +67,7 @@ export class TerminalConfigProvider extends ConfigProvider {
[Platform.Linux]: { [Platform.Linux]: {
terminal: { terminal: {
font: 'Liberation Mono', font: 'Liberation Mono',
shell: '/bin/bash', shell: '~default-shell~',
}, },
hotkeys: { hotkeys: {
'new-tab': [ 'new-tab': [
......
...@@ -100,7 +100,7 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider { ...@@ -100,7 +100,7 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
altscreen on altscreen on
`, 'utf-8') `, 'utf-8')
let recoveryId = `term-tab-${Date.now()}` let recoveryId = `term-tab-${Date.now()}`
let args = ['-d', '-m', '-c', configPath, '-U', '-S', recoveryId, '-T', 'xterm-256color', '--', options.command].concat(options.args || []) let args = ['-d', '-m', '-c', configPath, '-U', '-S', recoveryId, '-T', 'xterm-256color', '--', '-' + options.command].concat(options.args || [])
this.logger.debug('Spawning screen with', args.join(' ')) this.logger.debug('Spawning screen with', args.join(' '))
await spawn('screen', args, { await spawn('screen', args, {
cwd: options.cwd, cwd: options.cwd,
......
...@@ -28,10 +28,6 @@ export class Session { ...@@ -28,10 +28,6 @@ export class Session {
...options.env, ...options.env,
TERM: 'xterm-256color', TERM: 'xterm-256color',
} }
if (options.command.includes(' ')) {
options.args = ['-c', options.command]
options.command = 'sh'
}
this.pty = nodePTY.spawn(options.command, options.args || [], { this.pty = nodePTY.spawn(options.command, options.args || [], {
name: 'xterm-256color', name: 'xterm-256color',
cols: options.width || 80, cols: options.width || 80,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册