mirror of
https://github.com/Eugeny/tabby.git
synced 2024-12-25 19:42:42 +03:00
shell context menu integration (fixes #362)
This commit is contained in:
parent
9ad1371c2b
commit
7f8d012a8a
@ -43,6 +43,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deepmerge": "^1.5.0",
|
"deepmerge": "^1.5.0",
|
||||||
"js-yaml": "^3.9.0",
|
"js-yaml": "^3.9.0",
|
||||||
|
"winreg": "^1.2.4",
|
||||||
"winston": "^2.4.0"
|
"winston": "^2.4.0"
|
||||||
},
|
},
|
||||||
"false": {}
|
"false": {}
|
||||||
|
@ -13,4 +13,5 @@ export { Logger, LogService } from '../services/log.service'
|
|||||||
export { HomeBaseService } from '../services/homeBase.service'
|
export { HomeBaseService } from '../services/homeBase.service'
|
||||||
export { HotkeysService } from '../services/hotkeys.service'
|
export { HotkeysService } from '../services/hotkeys.service'
|
||||||
export { HostAppService, Platform } from '../services/hostApp.service'
|
export { HostAppService, Platform } from '../services/hostApp.service'
|
||||||
|
export { ShellIntegrationService } from '../services/shellIntegration.service'
|
||||||
export { ThemesService } from '../services/themes.service'
|
export { ThemesService } from '../services/themes.service'
|
||||||
|
@ -14,6 +14,7 @@ import { LogService } from './services/log.service'
|
|||||||
import { HomeBaseService } from './services/homeBase.service'
|
import { HomeBaseService } from './services/homeBase.service'
|
||||||
import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
|
import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
|
||||||
import { DockingService } from './services/docking.service'
|
import { DockingService } from './services/docking.service'
|
||||||
|
import { ShellIntegrationService } from './services/shellIntegration.service'
|
||||||
import { TabRecoveryService } from './services/tabRecovery.service'
|
import { TabRecoveryService } from './services/tabRecovery.service'
|
||||||
import { ThemesService } from './services/themes.service'
|
import { ThemesService } from './services/themes.service'
|
||||||
import { TouchbarService } from './services/touchbar.service'
|
import { TouchbarService } from './services/touchbar.service'
|
||||||
@ -51,6 +52,7 @@ const PROVIDERS = [
|
|||||||
HostAppService,
|
HostAppService,
|
||||||
HotkeysService,
|
HotkeysService,
|
||||||
LogService,
|
LogService,
|
||||||
|
ShellIntegrationService,
|
||||||
TabRecoveryService,
|
TabRecoveryService,
|
||||||
ThemesService,
|
ThemesService,
|
||||||
TouchbarService,
|
TouchbarService,
|
||||||
|
85
terminus-core/src/services/shellIntegration.service.ts
Normal file
85
terminus-core/src/services/shellIntegration.service.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import * as path from 'path'
|
||||||
|
import * as fs from 'mz/fs'
|
||||||
|
import { exec } from 'mz/child_process'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { ElectronService } from './electron.service'
|
||||||
|
import { HostAppService, Platform } from './hostApp.service'
|
||||||
|
|
||||||
|
let Registry = null
|
||||||
|
try {
|
||||||
|
Registry = require('winreg')
|
||||||
|
} catch (_) { } // tslint:disable-line no-empty
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ShellIntegrationService {
|
||||||
|
private automatorWorkflows = ['Open Terminus here.workflow', 'Paste path into Terminus.workflow']
|
||||||
|
private automatorWorkflowsLocation: string
|
||||||
|
private automatorWorkflowsDestination: string
|
||||||
|
private registryKeys = [
|
||||||
|
{
|
||||||
|
path: '\\Software\\Classes\\Directory\\Background\\shell\\Open Terminus here',
|
||||||
|
command: 'open "%V"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '\\Software\\Classes\\*\\shell\\Paste path into Terminus',
|
||||||
|
command: 'paste "%V"'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
constructor (
|
||||||
|
private electron: ElectronService,
|
||||||
|
private hostApp: HostAppService,
|
||||||
|
) {
|
||||||
|
if (this.hostApp.platform === Platform.macOS) {
|
||||||
|
this.automatorWorkflowsLocation = path.join(
|
||||||
|
path.dirname(path.dirname(this.electron.app.getPath('exe'))),
|
||||||
|
'Resources',
|
||||||
|
'extras',
|
||||||
|
'automator-workflows',
|
||||||
|
)
|
||||||
|
this.automatorWorkflowsDestination = path.join(process.env.HOME, 'Library', 'Services')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async isInstalled (): Promise<boolean> {
|
||||||
|
if (this.hostApp.platform === Platform.macOS) {
|
||||||
|
return await fs.exists(path.join(this.automatorWorkflowsDestination, this.automatorWorkflows[0]))
|
||||||
|
} else if (this.hostApp.platform === Platform.Windows) {
|
||||||
|
return await new Promise<boolean>(resolve => {
|
||||||
|
let reg = new Registry({ hive: Registry.HKCU, key: this.registryKeys[0].path, arch: 'x64' })
|
||||||
|
reg.keyExists((err, exists) => resolve(!err && exists))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async install () {
|
||||||
|
if (this.hostApp.platform === Platform.macOS) {
|
||||||
|
for (let wf of this.automatorWorkflows) {
|
||||||
|
await exec(`cp -r "${this.automatorWorkflowsLocation}/${wf}" "${this.automatorWorkflowsDestination}"`)
|
||||||
|
}
|
||||||
|
} else if (this.hostApp.platform === Platform.Windows) {
|
||||||
|
for (let registryKey of this.registryKeys) {
|
||||||
|
let reg = new Registry({ hive: Registry.HKCU, key: registryKey.path, arch: 'x64' })
|
||||||
|
await new Promise(resolve => {
|
||||||
|
reg.set('Icon', Registry.REG_SZ, this.electron.app.getPath('exe'), () => {
|
||||||
|
reg.create(() => {
|
||||||
|
let cmd = new Registry({
|
||||||
|
hive: Registry.HKCU,
|
||||||
|
key: registryKey.path + '\\command',
|
||||||
|
arch: 'x64'
|
||||||
|
})
|
||||||
|
cmd.create(() => {
|
||||||
|
cmd.set(
|
||||||
|
'',
|
||||||
|
Registry.REG_SZ,
|
||||||
|
this.electron.app.getPath('exe') + ' ' + registryKey.command,
|
||||||
|
() => resolve()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -549,6 +549,10 @@ verror@1.10.0:
|
|||||||
core-util-is "1.0.2"
|
core-util-is "1.0.2"
|
||||||
extsprintf "^1.2.0"
|
extsprintf "^1.2.0"
|
||||||
|
|
||||||
|
winreg@^1.2.4:
|
||||||
|
version "1.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
|
||||||
|
|
||||||
winston@^2.4.0:
|
winston@^2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee"
|
resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee"
|
||||||
|
@ -19,11 +19,11 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
|||||||
i.fa.fa-bug
|
i.fa.fa-bug
|
||||||
span Report a problem
|
span Report a problem
|
||||||
|
|
||||||
.form-line(*ngIf='!automatorWorkflowsInstalled')
|
.form-line(*ngIf='!isShellIntegrationInstalled')
|
||||||
.header
|
.header
|
||||||
.title Finder context menu items
|
.title Shell integration
|
||||||
.description Allows quickly opening a terminal in the selected folder
|
.description Allows quickly opening a terminal in the selected folder
|
||||||
button.btn.btn-primary((click)='installAutomatorWorkflows()')
|
button.btn.btn-primary((click)='installShellIntegration()')
|
||||||
i.fa.fa-check
|
i.fa.fa-check
|
||||||
span Install
|
span Install
|
||||||
|
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
import * as path from 'path'
|
|
||||||
import * as fs from 'mz/fs'
|
|
||||||
import { exec } from 'mz/child_process'
|
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { Component, Inject, Input } from '@angular/core'
|
import { Component, Inject, Input } from '@angular/core'
|
||||||
import { ElectronService, DockingService, ConfigService, IHotkeyDescription, HotkeyProvider, BaseTabComponent, Theme, HostAppService, Platform, HomeBaseService } from 'terminus-core'
|
import {
|
||||||
|
ElectronService,
|
||||||
|
DockingService,
|
||||||
|
ConfigService,
|
||||||
|
IHotkeyDescription,
|
||||||
|
HotkeyProvider,
|
||||||
|
BaseTabComponent,
|
||||||
|
Theme,
|
||||||
|
HostAppService,
|
||||||
|
Platform,
|
||||||
|
HomeBaseService,
|
||||||
|
ShellIntegrationService
|
||||||
|
} from 'terminus-core'
|
||||||
|
|
||||||
import { SettingsTabProvider } from '../api'
|
import { SettingsTabProvider } from '../api'
|
||||||
|
|
||||||
@ -24,11 +33,8 @@ export class SettingsTabComponent extends BaseTabComponent {
|
|||||||
Platform = Platform
|
Platform = Platform
|
||||||
configDefaults: any
|
configDefaults: any
|
||||||
configFile: string
|
configFile: string
|
||||||
automatorWorkflowsInstalled = false
|
isShellIntegrationInstalled = false
|
||||||
private configSubscription: Subscription
|
private configSubscription: Subscription
|
||||||
private automatorWorkflows = ['Open Terminus here.workflow', 'Paste path into Terminus.workflow']
|
|
||||||
private automatorWorkflowsLocation: string
|
|
||||||
private automatorWorkflowsDestination: string
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
@ -36,6 +42,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
|||||||
public docking: DockingService,
|
public docking: DockingService,
|
||||||
public hostApp: HostAppService,
|
public hostApp: HostAppService,
|
||||||
public homeBase: HomeBaseService,
|
public homeBase: HomeBaseService,
|
||||||
|
public shellIntegration: ShellIntegrationService,
|
||||||
@Inject(HotkeyProvider) hotkeyProviders: HotkeyProvider[],
|
@Inject(HotkeyProvider) hotkeyProviders: HotkeyProvider[],
|
||||||
@Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[],
|
@Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[],
|
||||||
@Inject(Theme) public themes: Theme[],
|
@Inject(Theme) public themes: Theme[],
|
||||||
@ -52,19 +59,10 @@ export class SettingsTabComponent extends BaseTabComponent {
|
|||||||
this.configSubscription = config.changed$.subscribe(() => {
|
this.configSubscription = config.changed$.subscribe(() => {
|
||||||
this.configFile = config.readRaw()
|
this.configFile = config.readRaw()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.automatorWorkflowsLocation = path.join(
|
|
||||||
path.dirname(path.dirname(this.electron.app.getPath('exe'))),
|
|
||||||
'Resources',
|
|
||||||
'extras',
|
|
||||||
'automator-workflows',
|
|
||||||
)
|
|
||||||
|
|
||||||
this.automatorWorkflowsDestination = path.join(process.env.HOME, 'Library', 'Services')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
this.automatorWorkflowsInstalled = await fs.exists(path.join(this.automatorWorkflowsDestination, this.automatorWorkflows[0]))
|
this.isShellIntegrationInstalled = await this.shellIntegration.isInstalled()
|
||||||
}
|
}
|
||||||
|
|
||||||
getRecoveryToken (): any {
|
getRecoveryToken (): any {
|
||||||
@ -96,10 +94,8 @@ export class SettingsTabComponent extends BaseTabComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async installAutomatorWorkflows () {
|
async installShellIntegration () {
|
||||||
for (let wf of this.automatorWorkflows) {
|
await this.shellIntegration.install()
|
||||||
await exec(`cp -r "${this.automatorWorkflowsLocation}/${wf}" "${this.automatorWorkflowsDestination}"`)
|
this.isShellIntegrationInstalled = true
|
||||||
}
|
|
||||||
this.automatorWorkflowsInstalled = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user