mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-06 17:31:54 +00:00
Compare commits
17 Commits
v1.0.0-alp
...
v1.0.0-alp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0e9282e079 | ||
![]() |
5511f4d7cb | ||
![]() |
3ae76e66ed | ||
![]() |
42059e3bc6 | ||
![]() |
c093b204d7 | ||
![]() |
8a8f89b386 | ||
![]() |
b109fb8766 | ||
![]() |
f58cf469ed | ||
![]() |
57227ae6ce | ||
![]() |
b670fa843a | ||
![]() |
c41e551c58 | ||
![]() |
60b02b17e4 | ||
![]() |
bf8bb7ee80 | ||
![]() |
1e1d48a5f8 | ||
![]() |
77b55a003c | ||
![]() |
165ab1cfbf | ||
![]() |
d4840bafaf |
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at e@ajenti.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
@@ -67,7 +67,11 @@ terminus-pluginname
|
|||||||
|
|
||||||
# Plugins
|
# Plugins
|
||||||
|
|
||||||
The app will load all plugins from the source checkout in the dev mode, and from the user's plugins directory at all times (click `Open Plugins Directory` under `Settings` > `Plugins`).
|
The app will load all plugins from the source checkout in the dev mode, from the user's plugins directory at all times (click `Open Plugins Directory` under `Settings` > `Plugins`) and from the directory specified by the `TERMINUS_PLUGINS` environment var.
|
||||||
|
|
||||||
|
Only modules whose `package.json` file contains a `terminus-plugin` keyword will be loaded.
|
||||||
|
|
||||||
|
If you're currently in your plugin's directory, start Terminus as `TERMINUS_PLUGINS=$(pwd) terminus --debug`
|
||||||
|
|
||||||
A plugin should only provide a default export, which should be a `NgModule` class (or a `NgModuleWithDependencies` where applicable). This module will be injected as a dependency to the app's root module.
|
A plugin should only provide a default export, which should be a `NgModule` class (or a `NgModuleWithDependencies` where applicable). This module will be injected as a dependency to the app's root module.
|
||||||
|
|
||||||
|
13
README.md
13
README.md
@@ -17,7 +17,16 @@
|
|||||||
* 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Plugins
|
||||||
|
|
||||||
|
Plugins can be installed directly from the Settings view inside Terminus.
|
||||||
|
|
||||||
|
* [clickable-links](https://github.com/Eugeny/terminus-clickable-links) - makes paths and URLs in the terminal clickable
|
||||||
|
* [theme-hype](https://github.com/Eugeny/terminus-theme-hype) - a Hyper inspired theme
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -25,4 +34,4 @@
|
|||||||
|
|
||||||
Pull requests and plugins are welcome! Publish your plugin on NPM with a `terminus-plugin` keyword to make them appear in the Plugin Manager.
|
Pull requests and plugins are welcome! Publish your plugin on NPM with a `terminus-plugin` keyword to make them appear in the Plugin Manager.
|
||||||
|
|
||||||
See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) for a very plugin development tutorial!
|
See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) for a very brief plugin development tutorial!
|
||||||
|
@@ -22,7 +22,6 @@ const yaml = require('js-yaml')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const Config = require('electron-config')
|
const Config = require('electron-config')
|
||||||
require('electron-debug')({enabled: true, showDevTools: process.argv.indexOf('--debug') != -1})
|
|
||||||
let windowConfig = new Config({name: 'window'})
|
let windowConfig = new Config({name: 'window'})
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import 'zone.js/dist/zone.js'
|
import 'zone.js'
|
||||||
import 'core-js/es7/reflect'
|
import 'core-js/es7/reflect'
|
||||||
import 'core-js/core/delay'
|
import 'core-js/core/delay'
|
||||||
import 'rxjs'
|
import 'rxjs'
|
||||||
|
@@ -20,11 +20,7 @@ if (process.env.DEV) {
|
|||||||
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
|
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
|
||||||
}
|
}
|
||||||
|
|
||||||
const builtinPluginsPath = path.join(
|
const builtinPluginsPath = path.join((process as any).resourcesPath, 'builtin-plugins')
|
||||||
path.dirname(require('electron').remote.app.getPath('exe')),
|
|
||||||
(process.platform === 'darwin') ? '../Resources' : 'resources',
|
|
||||||
'builtin-plugins',
|
|
||||||
)
|
|
||||||
|
|
||||||
const userPluginsPath = path.join(
|
const userPluginsPath = path.join(
|
||||||
require('electron').remote.app.getPath('appData'),
|
require('electron').remote.app.getPath('appData'),
|
||||||
@@ -35,9 +31,9 @@ const userPluginsPath = path.join(
|
|||||||
Object.assign(window, { builtinPluginsPath, userPluginsPath })
|
Object.assign(window, { builtinPluginsPath, userPluginsPath })
|
||||||
nodeModule.globalPaths.unshift(builtinPluginsPath)
|
nodeModule.globalPaths.unshift(builtinPluginsPath)
|
||||||
nodeModule.globalPaths.unshift(path.join(userPluginsPath, 'node_modules'))
|
nodeModule.globalPaths.unshift(path.join(userPluginsPath, 'node_modules'))
|
||||||
|
// nodeModule.globalPaths.unshift(path.join((process as any).resourcesPath, 'app.asar', 'node_modules'))
|
||||||
if (process.env.TERMINUS_PLUGINS) {
|
if (process.env.TERMINUS_PLUGINS) {
|
||||||
process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.unshift(normalizePath(x)))
|
process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.push(normalizePath(x)))
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare type ProgressCallback = (current, total) => void
|
export declare type ProgressCallback = (current, total) => void
|
||||||
@@ -53,9 +49,39 @@ export interface IPluginInfo {
|
|||||||
info?: any
|
info?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const builtinModules = [
|
||||||
|
'@angular/animations',
|
||||||
|
'@angular/common',
|
||||||
|
'@angular/compiler',
|
||||||
|
'@angular/core',
|
||||||
|
'@angular/forms',
|
||||||
|
'@angular/platform-browser',
|
||||||
|
'@angular/platform-browser-dynamic',
|
||||||
|
'@ng-bootstrap/ng-bootstrap',
|
||||||
|
'rxjs',
|
||||||
|
'terminus-core',
|
||||||
|
'terminus-settings',
|
||||||
|
'terminus-terminal',
|
||||||
|
'zone.js/dist/zone.js',
|
||||||
|
]
|
||||||
|
|
||||||
|
const cachedBuiltinModules = {}
|
||||||
|
builtinModules.forEach(m => {
|
||||||
|
cachedBuiltinModules[m] = nodeRequire(m)
|
||||||
|
})
|
||||||
|
|
||||||
|
const originalRequire = nodeRequire('module').prototype.require
|
||||||
|
nodeRequire('module').prototype.require = function (query) {
|
||||||
|
if (cachedBuiltinModules[query]) {
|
||||||
|
return cachedBuiltinModules[query]
|
||||||
|
}
|
||||||
|
return originalRequire.apply(this, arguments)
|
||||||
|
}
|
||||||
|
|
||||||
export async function findPlugins (): Promise<IPluginInfo[]> {
|
export async function findPlugins (): Promise<IPluginInfo[]> {
|
||||||
let paths = nodeModule.globalPaths
|
let paths = nodeModule.globalPaths
|
||||||
let foundPlugins: IPluginInfo[] = []
|
let foundPlugins: IPluginInfo[] = []
|
||||||
|
let candidateLocations: { pluginDir: string, pluginName: string }[] = []
|
||||||
|
|
||||||
for (let pluginDir of paths) {
|
for (let pluginDir of paths) {
|
||||||
pluginDir = normalizePath(pluginDir)
|
pluginDir = normalizePath(pluginDir)
|
||||||
@@ -63,32 +89,44 @@ export async function findPlugins (): Promise<IPluginInfo[]> {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let pluginNames = await fs.readdir(pluginDir)
|
let pluginNames = await fs.readdir(pluginDir)
|
||||||
for (let pluginName of pluginNames.filter(x => /^terminus-/.exec(x))) {
|
if (await fs.exists(path.join(pluginDir, 'package.json'))) {
|
||||||
let pluginPath = path.join(pluginDir, pluginName)
|
candidateLocations.push({
|
||||||
let infoPath = path.join(pluginPath, 'package.json')
|
pluginDir: path.dirname(pluginDir),
|
||||||
if (!await fs.exists(infoPath)) {
|
pluginName: path.basename(pluginDir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for (let pluginName of pluginNames) {
|
||||||
|
candidateLocations.push({ pluginDir, pluginName })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let { pluginDir, pluginName } of candidateLocations) {
|
||||||
|
let pluginPath = path.join(pluginDir, pluginName)
|
||||||
|
let infoPath = path.join(pluginPath, 'package.json')
|
||||||
|
if (!await fs.exists(infoPath)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundPlugins.some(x => x.name === pluginName)) {
|
||||||
|
console.info(`Plugin ${pluginName} already exists`)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let info = JSON.parse(await fs.readFile(infoPath, {encoding: 'utf-8'}))
|
||||||
|
if (!info.keywords || info.keywords.indexOf('terminus-plugin') === -1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
foundPlugins.push({
|
||||||
if (foundPlugins.some(x => x.name === pluginName)) {
|
name: pluginName.substring('terminus-'.length),
|
||||||
console.info(`Plugin ${pluginName} already exists`)
|
packageName: pluginName,
|
||||||
}
|
isBuiltin: pluginDir === builtinPluginsPath,
|
||||||
|
version: info.version,
|
||||||
try {
|
description: info.description,
|
||||||
let info = JSON.parse(await fs.readFile(infoPath, {encoding: 'utf-8'}))
|
path: pluginPath,
|
||||||
console.log(pluginDir, builtinPluginsPath)
|
info,
|
||||||
foundPlugins.push({
|
})
|
||||||
name: pluginName.substring('terminus-'.length),
|
} catch (error) {
|
||||||
packageName: pluginName,
|
console.error('Cannot load package info for', pluginName)
|
||||||
isBuiltin: pluginDir === builtinPluginsPath,
|
|
||||||
version: info.version,
|
|
||||||
description: info.description,
|
|
||||||
path: pluginPath,
|
|
||||||
info,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Cannot load package info for', pluginName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -61,7 +61,7 @@ module.exports = {
|
|||||||
'mz': 'commonjs mz',
|
'mz': 'commonjs mz',
|
||||||
'path': 'commonjs path',
|
'path': 'commonjs path',
|
||||||
'rxjs': 'commonjs rxjs',
|
'rxjs': 'commonjs rxjs',
|
||||||
'zone.js': 'commonjs zone.js',
|
'zone.js': 'commonjs zone.js/dist/zone.js',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
|
@@ -80,5 +80,5 @@
|
|||||||
"lint": "tslint -c tslint.json -t stylish terminus-*/src/**/*.ts terminus-*/src/*.ts app/src/*.ts",
|
"lint": "tslint -c tslint.json -t stylish terminus-*/src/**/*.ts terminus-*/src/*.ts app/src/*.ts",
|
||||||
"postinstall": "install-app-deps"
|
"postinstall": "install-app-deps"
|
||||||
},
|
},
|
||||||
"false": {}
|
"repository": "eugeny/terminus"
|
||||||
}
|
}
|
||||||
|
@@ -22,3 +22,4 @@ vars.builtinPlugins.forEach(plugin => {
|
|||||||
}
|
}
|
||||||
sh.cd('..')
|
sh.cd('..')
|
||||||
})
|
})
|
||||||
|
fs.unlinkSync(path.join(target, 'package.json'), '{}')
|
||||||
|
11
scripts/set-plugin-versions.js
Executable file
11
scripts/set-plugin-versions.js
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const sh = require('shelljs')
|
||||||
|
const vars = require('./vars')
|
||||||
|
const log = require('npmlog')
|
||||||
|
|
||||||
|
vars.builtinPlugins.forEach(plugin => {
|
||||||
|
log.info('bump', plugin)
|
||||||
|
sh.cd(plugin)
|
||||||
|
sh.exec('npm --no-git-tag-version version ' + vars.version)
|
||||||
|
sh.cd('..')
|
||||||
|
})
|
@@ -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
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-community-color-schemes",
|
"name": "terminus-community-color-schemes",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0-alpha.14",
|
||||||
"description": "Community color schemes for Terminus",
|
"description": "Community color schemes for Terminus",
|
||||||
|
"keywords": ["terminus-plugin"],
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-core",
|
"name": "terminus-core",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0-alpha.14",
|
||||||
"description": "Terminus core",
|
"description": "Terminus core",
|
||||||
|
"keywords": ["terminus-plugin"],
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-plugin-manager",
|
"name": "terminus-plugin-manager",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0-alpha.14",
|
||||||
"description": "Terminus' plugin manager",
|
"description": "Terminus' plugin manager",
|
||||||
|
"keywords": ["terminus-plugin"],
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-settings",
|
"name": "terminus-settings",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0-alpha.14",
|
||||||
"description": "Terminus terminal settings page",
|
"description": "Terminus terminal settings page",
|
||||||
|
"keywords": ["terminus-plugin"],
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -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'
|
|||||||
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 {
|
|||||||
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 {
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-terminal",
|
"name": "terminus-terminal",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0-alpha.14",
|
||||||
"description": "Terminus' terminal emulation core",
|
"description": "Terminus' terminal emulation core",
|
||||||
|
"keywords": ["terminus-plugin"],
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
'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(':')[6]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
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 {
|
|||||||
{ 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 {
|
|||||||
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 {
|
|||||||
[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 {
|
|||||||
[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 {
|
|||||||
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 {
|
|||||||
...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,
|
||||||
|
Reference in New Issue
Block a user