mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-16 09:29:59 +00:00
WSL2 support - fixes #271
This commit is contained in:
parent
f58cab0820
commit
b29ab2690f
@ -155,6 +155,8 @@ export class ConfigService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save (): void {
|
save (): void {
|
||||||
|
// Scrub undefined values
|
||||||
|
this._store = JSON.parse(JSON.stringify(this._store))
|
||||||
fs.writeFileSync(this.path, yaml.safeDump(this._store), 'utf8')
|
fs.writeFileSync(this.path, yaml.safeDump(this._store), 'utf8')
|
||||||
this.emitChange()
|
this.emitChange()
|
||||||
this.hostApp.broadcastConfigChange(this.store)
|
this.hostApp.broadcastConfigChange(this.store)
|
||||||
|
@ -19,6 +19,7 @@ export interface Profile {
|
|||||||
name: string
|
name: string
|
||||||
color?: string
|
color?: string
|
||||||
sessionOptions: SessionOptions
|
sessionOptions: SessionOptions
|
||||||
|
shell?: string
|
||||||
isBuiltin?: boolean
|
isBuiltin?: boolean
|
||||||
icon?: string
|
icon?: string
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ h3.mb-3 Shell
|
|||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
*ngFor='let profile of profiles',
|
*ngFor='let profile of profiles',
|
||||||
[ngValue]='slugify(profile.name).toLowerCase()'
|
[ngValue]='terminal.getProfileID(profile)'
|
||||||
) {{profile.name}}
|
) {{profile.name}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import slugify from 'slugify'
|
|
||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
@ -17,14 +16,13 @@ export class ShellSettingsTabComponent {
|
|||||||
Platform = Platform
|
Platform = Platform
|
||||||
isConPTYAvailable: boolean
|
isConPTYAvailable: boolean
|
||||||
isConPTYStable: boolean
|
isConPTYStable: boolean
|
||||||
slugify = slugify
|
|
||||||
private configSubscription: Subscription
|
private configSubscription: Subscription
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
public hostApp: HostAppService,
|
public hostApp: HostAppService,
|
||||||
|
public terminal: TerminalService,
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private terminalService: TerminalService,
|
|
||||||
private ngbModal: NgbModal,
|
private ngbModal: NgbModal,
|
||||||
) {
|
) {
|
||||||
config.store.terminal.environment = config.store.terminal.environment || {}
|
config.store.terminal.environment = config.store.terminal.environment || {}
|
||||||
@ -38,7 +36,7 @@ export class ShellSettingsTabComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit (): Promise<void> {
|
async ngOnInit (): Promise<void> {
|
||||||
this.shells = await this.terminalService.shells$.toPromise()
|
this.shells = await this.terminal.shells$.toPromise()
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy (): void {
|
ngOnDestroy (): void {
|
||||||
@ -46,21 +44,22 @@ export class ShellSettingsTabComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reload (): Promise<void> {
|
async reload (): Promise<void> {
|
||||||
this.profiles = await this.terminalService.getProfiles({ includeHidden: true })
|
this.profiles = await this.terminal.getProfiles({ includeHidden: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
pickWorkingDirectory (): void {
|
async pickWorkingDirectory (): Promise<void> {
|
||||||
const shell = this.shells.find(x => x.id === this.config.store.terminal.shell)
|
const profile = await this.terminal.getProfileByID(this.config.store.terminal.profile)
|
||||||
|
const shell = this.shells.find(x => x.id === profile?.shell)
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const paths = this.electron.dialog.showOpenDialog(
|
const paths = (await this.electron.dialog.showOpenDialog(
|
||||||
this.hostApp.getWindow(),
|
this.hostApp.getWindow(),
|
||||||
{
|
{
|
||||||
defaultPath: shell.fsBase,
|
defaultPath: shell.fsBase,
|
||||||
properties: ['openDirectory', 'showHiddenFiles'],
|
properties: ['openDirectory', 'showHiddenFiles'],
|
||||||
}
|
}
|
||||||
)
|
)).filePaths
|
||||||
if (paths) {
|
if (paths) {
|
||||||
this.config.store.terminal.workingDirectory = paths[0]
|
this.config.store.terminal.workingDirectory = paths[0]
|
||||||
}
|
}
|
||||||
@ -69,7 +68,8 @@ export class ShellSettingsTabComponent {
|
|||||||
newProfile (shell: Shell): void {
|
newProfile (shell: Shell): void {
|
||||||
const profile: Profile = {
|
const profile: Profile = {
|
||||||
name: shell.name || '',
|
name: shell.name || '',
|
||||||
sessionOptions: this.terminalService.optionsFromShell(shell),
|
shell: shell.id,
|
||||||
|
sessionOptions: this.terminal.optionsFromShell(shell),
|
||||||
}
|
}
|
||||||
this.config.store.terminal.profiles = [profile, ...this.config.store.terminal.profiles]
|
this.config.store.terminal.profiles = [profile, ...this.config.store.terminal.profiles]
|
||||||
this.config.save()
|
this.config.save()
|
||||||
|
@ -30,7 +30,7 @@ h3.mb-3 Terminal
|
|||||||
)
|
)
|
||||||
| Audible
|
| Audible
|
||||||
|
|
||||||
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.bell != "audible" && config.store.terminal.shell.startsWith("wsl")')
|
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.bell != "audible" && config.store.terminal.profile.startsWith("wsl")')
|
||||||
.mr-auto WSL terminal bell can only be muted via Volume Mixer
|
.mr-auto WSL terminal bell can only be muted via Volume Mixer
|
||||||
button.btn.btn-secondary((click)='openWSLVolumeMixer()') Show Mixer
|
button.btn.btn-secondary((click)='openWSLVolumeMixer()') Show Mixer
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import slugify from 'slugify'
|
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { HotkeyDescription, HotkeyProvider } from 'terminus-core'
|
import { HotkeyDescription, HotkeyProvider } from 'terminus-core'
|
||||||
import { TerminalService } from './services/terminal.service'
|
import { TerminalService } from './services/terminal.service'
|
||||||
@ -78,7 +77,7 @@ export class TerminalHotkeyProvider extends HotkeyProvider {
|
|||||||
return [
|
return [
|
||||||
...this.hotkeys,
|
...this.hotkeys,
|
||||||
...profiles.map(profile => ({
|
...profiles.map(profile => ({
|
||||||
id: `profile.${slugify(profile.name).toLowerCase()}`,
|
id: `profile.${this.terminal.getProfileID(profile)}`,
|
||||||
name: `New tab: ${profile.name}`,
|
name: `New tab: ${profile.name}`,
|
||||||
})),
|
})),
|
||||||
]
|
]
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import * as fs from 'mz/fs'
|
import * as fs from 'mz/fs'
|
||||||
import slugify from 'slugify'
|
|
||||||
|
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { BrowserModule } from '@angular/platform-browser'
|
import { BrowserModule } from '@angular/platform-browser'
|
||||||
@ -187,8 +186,7 @@ export default class TerminalModule { // eslint-disable-line @typescript-eslint/
|
|||||||
hostApp.newWindow()
|
hostApp.newWindow()
|
||||||
}
|
}
|
||||||
if (hotkey.startsWith('profile.')) {
|
if (hotkey.startsWith('profile.')) {
|
||||||
const profiles = await terminal.getProfiles()
|
const profile = await terminal.getProfileByID(hotkey.split('.')[1])
|
||||||
const profile = profiles.find(x => slugify(x.name).toLowerCase() === hotkey.split('.')[1])
|
|
||||||
if (profile) {
|
if (profile) {
|
||||||
terminal.openTabWithOptions(profile.sessionOptions)
|
terminal.openTabWithOptions(profile.sessionOptions)
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ export class TerminalService {
|
|||||||
...this.config.store.terminal.profiles,
|
...this.config.store.terminal.profiles,
|
||||||
...skipDefault ? [] : shells.filter(x => includeHidden || !x.hidden).map(shell => ({
|
...skipDefault ? [] : shells.filter(x => includeHidden || !x.hidden).map(shell => ({
|
||||||
name: shell.name,
|
name: shell.name,
|
||||||
|
shell: shell.id,
|
||||||
icon: shell.icon,
|
icon: shell.icon,
|
||||||
sessionOptions: this.optionsFromShell(shell),
|
sessionOptions: this.optionsFromShell(shell),
|
||||||
isBuiltin: true,
|
isBuiltin: true,
|
||||||
@ -47,14 +48,25 @@ export class TerminalService {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProfileID (profile: Profile): string {
|
||||||
|
return slugify(profile.name).toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProfileByID (id: string): Promise<Profile> {
|
||||||
|
const profiles = await this.getProfiles({ includeHidden: true })
|
||||||
|
return profiles.find(x => this.getProfileID(x) === id) || profiles[0]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches a new terminal with a specific shell and CWD
|
* Launches a new terminal with a specific shell and CWD
|
||||||
* @param pause Wait for a keypress when the shell exits
|
* @param pause Wait for a keypress when the shell exits
|
||||||
*/
|
*/
|
||||||
async openTab (profile?: Profile, cwd?: string|null, pause?: boolean): Promise<TerminalTabComponent> {
|
async openTab (profile?: Profile, cwd?: string|null, pause?: boolean): Promise<TerminalTabComponent> {
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
const profiles = await this.getProfiles({ includeHidden: true })
|
profile = await this.getProfileByID(this.config.store.terminal.profile)
|
||||||
profile = profiles.find(x => slugify(x.name).toLowerCase() === this.config.store.terminal.profile) || profiles[0]
|
if (!profile) {
|
||||||
|
profile = (await this.getProfiles({ includeHidden: true }))[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd = cwd || profile.sessionOptions.cwd
|
cwd = cwd || profile.sessionOptions.cwd
|
||||||
|
@ -88,13 +88,15 @@ export class WSLShellProvider extends ShellProvider {
|
|||||||
if (!childKey.DistributionName) {
|
if (!childKey.DistributionName) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
const wslVersion = (childKey.Flags.value & 8) ? 2 : 1
|
||||||
const name = childKey.DistributionName.value
|
const name = childKey.DistributionName.value
|
||||||
|
const fsBase = (wslVersion === 2) ? `\\\\wsl$\\${name}` : (childKey.BasePath.value as string + '\\rootfs')
|
||||||
const shell: Shell = {
|
const shell: Shell = {
|
||||||
id: `wsl-${slugify(name)}`,
|
id: `wsl-${slugify(name)}`,
|
||||||
name: `WSL / ${name}`,
|
name: `WSL / ${name}`,
|
||||||
command: wslPath,
|
command: wslPath,
|
||||||
args: ['-d', name],
|
args: ['-d', name],
|
||||||
fsBase: childKey.BasePath.value as string + '\\rootfs',
|
fsBase,
|
||||||
env: {
|
env: {
|
||||||
TERM: 'xterm-color',
|
TERM: 'xterm-color',
|
||||||
COLORTERM: 'truecolor',
|
COLORTERM: 'truecolor',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user