mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-22 09:11:50 +00:00
Compare commits
19 Commits
v1.0.0-alp
...
v1.0.0-alp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f58cf469ed | ||
![]() |
57227ae6ce | ||
![]() |
b670fa843a | ||
![]() |
c41e551c58 | ||
![]() |
60b02b17e4 | ||
![]() |
bf8bb7ee80 | ||
![]() |
1e1d48a5f8 | ||
![]() |
77b55a003c | ||
![]() |
165ab1cfbf | ||
![]() |
d4840bafaf | ||
![]() |
9badd88c80 | ||
![]() |
7a24c9aa3a | ||
![]() |
8a7e7c4eb5 | ||
![]() |
d0c10278fb | ||
![]() |
2ae004db53 | ||
![]() |
7b34b668c1 | ||
![]() |
7c09fc4a38 | ||
![]() |
89ff9d0ea2 | ||
![]() |
b4e503b26c |
30
README.md
30
README.md
@@ -1,2 +1,28 @@
|
|||||||
[](https://travis-ci.org/Eugeny/terminus)
|
# Terminus α
|
||||||
[](https://ci.appveyor.com/project/Eugeny/terminus)
|
*A terminal for a more modern age*
|
||||||
|
|
||||||
|
[](https://travis-ci.org/Eugeny/terminus) [](https://ci.appveyor.com/project/Eugeny/terminus) [](https://raw.githubusercontent.com/Eugeny/terminus/master/LICENSE) [](https://github.com/Eugeny/terminus/releases/latest)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Terminus** is a web technology based terminal heavily inspired by Hyper. It is, however, designed for people who need to get things done.
|
||||||
|
|
||||||
|
* Runs on Windows, macOS and Linux
|
||||||
|
* Theming and color schemes
|
||||||
|
* Configurable hotkey schemes
|
||||||
|
* **GNU Screen** style hotkeys available by default
|
||||||
|
* Full Unicode support including double-width characters
|
||||||
|
* Doesn't choke on fast-flowing outputs
|
||||||
|
* Tab persistence on macOS and Linux
|
||||||
|
* Proper shell-like experience on Windows including tab completion (thanks, Clink!)
|
||||||
|
* CMD, PowerShell, Cygwin, Git-Bash and Bash on Windows support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
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!
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
if (process.platform == 'win32' && require('electron-squirrel-startup')) process.exit(0)
|
if (process.platform == 'win32' && require('electron-squirrel-startup')) process.exit(0)
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
require('electron-debug')({enabled: true, showDevTools: (process.argv.indexOf('--debug') != -1) ? 'undocked' : false})
|
if (process.argv.indexOf('--debug') !== -1) {
|
||||||
|
require('electron-debug')({enabled: true, showDevTools: 'undocked'})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let app = electron.app
|
let app = electron.app
|
||||||
@@ -20,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'})
|
||||||
|
|
||||||
|
|
||||||
@@ -146,7 +147,7 @@ start = () => {
|
|||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 400,
|
height: 600,
|
||||||
//icon: `${app.getAppPath()}/assets/img/icon.png`,
|
//icon: `${app.getAppPath()}/assets/img/icon.png`,
|
||||||
title: 'Terminus',
|
title: 'Terminus',
|
||||||
minWidth: 400,
|
minWidth: 400,
|
||||||
|
@@ -25,10 +25,13 @@
|
|||||||
"electron-debug": "^1.0.1",
|
"electron-debug": "^1.0.1",
|
||||||
"electron-is-dev": "0.1.2",
|
"electron-is-dev": "0.1.2",
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
"fs-promise": "^2.0.2",
|
|
||||||
"js-yaml": "3.8.2",
|
"js-yaml": "3.8.2",
|
||||||
|
"mz": "^2.6.0",
|
||||||
"path": "0.12.7",
|
"path": "0.12.7",
|
||||||
"rxjs": "5.3.0",
|
"rxjs": "5.3.0",
|
||||||
"zone.js": "0.8.4"
|
"zone.js": "0.8.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/mz": "0.0.31"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import * as fs from 'fs-promise'
|
import * as fs from 'mz/fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
const nodeModule = require('module')
|
const nodeModule = require('module')
|
||||||
const nodeRequire = (global as any).require
|
const nodeRequire = (global as any).require
|
||||||
@@ -75,7 +75,7 @@ export async function findPlugins (): Promise<IPluginInfo[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let info = await fs.readJson(infoPath)
|
let info = JSON.parse(await fs.readFile(infoPath, {encoding: 'utf-8'}))
|
||||||
console.log(pluginDir, builtinPluginsPath)
|
console.log(pluginDir, builtinPluginsPath)
|
||||||
foundPlugins.push({
|
foundPlugins.push({
|
||||||
name: pluginName.substring('terminus-'.length),
|
name: pluginName.substring('terminus-'.length),
|
||||||
|
@@ -55,10 +55,10 @@ module.exports = {
|
|||||||
'@angular/forms': 'commonjs @angular/forms',
|
'@angular/forms': 'commonjs @angular/forms',
|
||||||
'@angular/common': 'commonjs @angular/common',
|
'@angular/common': 'commonjs @angular/common',
|
||||||
'@ng-bootstrap/ng-bootstrap': 'commonjs @ng-bootstrap/ng-bootstrap',
|
'@ng-bootstrap/ng-bootstrap': 'commonjs @ng-bootstrap/ng-bootstrap',
|
||||||
'fs-promise': 'commonjs fs-promise',
|
|
||||||
'electron': 'commonjs electron',
|
'electron': 'commonjs electron',
|
||||||
'electron-is-dev': 'commonjs electron-is-dev',
|
'electron-is-dev': 'commonjs electron-is-dev',
|
||||||
'module': 'commonjs module',
|
'module': 'commonjs module',
|
||||||
|
'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',
|
||||||
|
@@ -1,22 +1,53 @@
|
|||||||
<!DOCTYPE html><html><head><link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"><link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400" rel="stylesheet"><style>body {
|
<!DOCTYPE html><html><head><link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400" rel="stylesheet"><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"><link href="https://cdn.jsdelivr.net/g/bootstrap@4.0.0-alpha.6(css/bootstrap.min.css)" rel="stylesheet"><script src="https://cdn.jsdelivr.net/g/jquery@3.2.1,tether@1.4.0,bootstrap@4.0.0-alpha.6,modernizr@3.3.1,detectizr@2.2.0"></script><title>Terminus</title><style>body {
|
||||||
font-family: 'Source Sans Pro', sans-serif;
|
font-family: 'Source Sans Pro', sans-serif;
|
||||||
background: #111;
|
background: #111;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-image: radial-gradient(#111, #000);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 64px;
|
font-size: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h3, h5 {
|
h1, h2, h3, h5 {
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn i + span {
|
.btn i + span,
|
||||||
|
.nav-link i + span {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-outline-primary {
|
.btn-outline-primary {
|
||||||
color: #b6e7ff !important;
|
color: #b6e7ff !important;
|
||||||
}</style></head><body><div class="container mt-5 mb-3"><div class="text-center"><h1>Terminus</h1><h5>A terminal for a more modern age</h5><div class="btn-group mt-3 mb-3"><a class="btn btn-outline-primary"><i class="fa fa-windows"></i><span>Windows</span></a><a class="btn btn-outline-primary"><i class="fa fa-apple"></i><span>macOS</span></a><a class="btn btn-outline-primary"><i class="fa fa-archive"></i><span>DEB</span></a><a class="btn btn-outline-primary"><i class="fa fa-archive"></i><span>RPM</span></a><a class="btn btn-outline-primary"><i class="fa fa-archive"></i><span>TGZ</span></a></div></div><div class="row mt-5"><div class="col-6"><h3>Proper Windows experience</h3><p> <b>Clink </b>provides tab completion, readline-style editing and persistent command history on Windows.</p><p>Also supported:<ul> <li>Classic CMD</li><li>PowerShell </li><li>Bash on Windows </li></ul></p></div><div class="col-6"><h3>User experience</h3><ul><li>Spawn and hide with a global hotkey</li><li>Fully customizable hotkey schema</li><li>Restores tabs </li><li>Drag in a file to paste the path</li><li>Click paths and URLs to open in browser/file manager</li><li>Keeps the current directory in new tabs</li></ul></div></div><div class="row mt-5"><div class="col-6"><h3>Customizable</h3><p>Multiple app themes and a myriad of community color schemes for the terminal. Color scheme editor included.</p></div><div class="col-6"><h3>Infinitely extensible</h3><p>Install plugins from the NPM repository, or create your own with Typescript and Angular framework.</p></div></div></div></body></html>
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video, img {
|
||||||
|
max-width: 100%;
|
||||||
|
box-shadow: 0 0 50px black;
|
||||||
|
}
|
||||||
|
</style><script defer>setTimeout(function () {
|
||||||
|
/*
|
||||||
|
if (Detectizr.os.name == 'windows') {
|
||||||
|
$('[href="#windows"]').tab('show')
|
||||||
|
}
|
||||||
|
if (Detectizr.os.name == 'mac os') {
|
||||||
|
$('[href="#macos"]').tab('show')
|
||||||
|
}
|
||||||
|
if (Detectizr.os.name == 'linux') {
|
||||||
|
$('[href="#linux"]').tab('show')
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
})</script></head><body><div class="container mt-5 mb-5"><div class="text-center"><h1>Terminus</h1><h5>A terminal for a more modern age</h5><h2 class="text-muted">alpha</h2></div><div class="d-flex flex-row mt-5 mb-5"><ul class="nav nav-pills flex-column mr-5" style="min-width: 200px;"><li class="nav-item"><a class="nav-link active" data-toggle="tab" href="#windows" role="tab"><i class="fa fa-windows"></i><span>Windows</span></a></li><li class="nav-item"><a class="nav-link" data-toggle="tab" href="#macos" role="tab"><i class="fa fa-apple"></i><span>macOS</span></a></li><li class="nav-item"><a class="nav-link" data-toggle="tab" href="#linux" role="tab"><i class="fa fa-linux"></i><span>Linux</span></a></li></ul><div class="tab-content"><div class="tab-pane active" id="windows" role="tabpanel"><div class="row"><div class="col-6"><video src="videos/windows.mp4" autoplay loop></video></div><div class="col-6"><h3>A proper Windows experience</h3><p> <b>Clink </b>provides tab completion, readline-style editing and persistent command history on Windows.</p><p>Also supported:<ul> <li>Classic CMD</li><li>PowerShell </li><li>Bash on Windows </li></ul></p></div></div></div><div class="tab-pane" id="macos" role="tabpanel"><div class="row"><div class="col-6"><!--video(src='videos/windows.mp4', autoplay, loop)--></div><div class="col-6"><h3>Well...</h3><p>Not much to say here, it just works.</p></div></div></div><div class="tab-pane" id="linux" role="tabpanel"><div class="row"><div class="col-6"><img src="linux.png"></div><div class="col-6"><p><ul> <li>Spawn with a global hotkey</li><li>Tabs persist after restart</li><li>Auto-dock to any side of any screen</li><li>Full Unicode and double-width character support</li></ul></p></div></div></div></div></div><div class="text-center"><div class="mt-3 mb-3"><h2></h2><div><div class="btn-group mt-3 mb-1"><a class="btn btn-lg btn-outline-success" href="https://github.com/Eugeny/terminus/releases/latest" target="_blank"><i class="fa fa-download"></i><span>Downloads</span></a><a class="btn btn-lg btn-outline-secondary" href="https://github.com/Eugeny/terminus" target="_blank"><i class="fa fa-github"></i><span>GitHub</span></a></div></div><small class="text-muted">EXE, DMG, DEB, RPM, TGZ</small></div></div><div class="row mt-5"><div class="col-6"><h3>User experience</h3><ul><li>Spawn and hide with a global hotkey</li><li>Fully customizable hotkey schema</li><li>Restores tabs </li><li>Drag in a file to paste the path</li><li>Click paths and URLs to open in browser/file manager</li><li>Keeps the current directory in new tabs</li></ul></div><div class="col-6"><div class="mb-5"><h3>Customizable</h3><p>Multiple app themes and a myriad of community color schemes for the terminal. Color scheme editor included.</p></div><div> <h3>Infinitely extensible</h3><p>Install plugins from the NPM repository, or create your own with Typescript and Angular framework.</p></div></div></div></div><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||||
|
|
||||||
|
ga('create', 'UA-3278102-18', 'auto');
|
||||||
|
ga('send', 'pageview');</script></body></html>
|
156
docs/index.pug
156
docs/index.pug
@@ -1,71 +1,136 @@
|
|||||||
doctype html
|
doctype html
|
||||||
html
|
html
|
||||||
head
|
head
|
||||||
link(href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css", rel="stylesheet")
|
|
||||||
link(href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css", rel="stylesheet")
|
|
||||||
link(href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400", rel="stylesheet")
|
link(href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400", rel="stylesheet")
|
||||||
|
link(href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css", rel="stylesheet")
|
||||||
|
link(href="https://cdn.jsdelivr.net/g/bootstrap@4.0.0-alpha.6(css/bootstrap.min.css)", rel="stylesheet")
|
||||||
|
script(src="https://cdn.jsdelivr.net/g/jquery@3.2.1,tether@1.4.0,bootstrap@4.0.0-alpha.6,modernizr@3.3.1,detectizr@2.2.0")
|
||||||
|
title Terminus
|
||||||
style.
|
style.
|
||||||
body {
|
body {
|
||||||
font-family: 'Source Sans Pro', sans-serif;
|
font-family: 'Source Sans Pro', sans-serif;
|
||||||
background: #111;
|
background: #111;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-image: radial-gradient(#111, #000);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 64px;
|
font-size: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h3, h5 {
|
h1, h2, h3, h5 {
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn i + span {
|
.btn i + span,
|
||||||
|
.nav-link i + span {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-outline-primary {
|
.btn-outline-primary {
|
||||||
color: #b6e7ff !important;
|
color: #b6e7ff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video, img {
|
||||||
|
max-width: 100%;
|
||||||
|
box-shadow: 0 0 50px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
script(defer).
|
||||||
|
setTimeout(function () {
|
||||||
|
/*
|
||||||
|
if (Detectizr.os.name == 'windows') {
|
||||||
|
$('[href="#windows"]').tab('show')
|
||||||
|
}
|
||||||
|
if (Detectizr.os.name == 'mac os') {
|
||||||
|
$('[href="#macos"]').tab('show')
|
||||||
|
}
|
||||||
|
if (Detectizr.os.name == 'linux') {
|
||||||
|
$('[href="#linux"]').tab('show')
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
})
|
||||||
body
|
body
|
||||||
.container.mt-5.mb-3
|
.container.mt-5.mb-5
|
||||||
.text-center
|
.text-center
|
||||||
h1 Terminus
|
h1 Terminus
|
||||||
h5 A terminal for a more modern age
|
h5 A terminal for a more modern age
|
||||||
|
h2.text-muted alpha
|
||||||
|
|
||||||
|
.d-flex.flex-row.mt-5.mb-5
|
||||||
|
ul.nav.nav-pills.flex-column.mr-5(style='min-width: 200px')
|
||||||
|
li.nav-item
|
||||||
|
a.nav-link.active(data-toggle='tab', href='#windows', role='tab')
|
||||||
|
i.fa.fa-windows
|
||||||
|
span Windows
|
||||||
|
li.nav-item
|
||||||
|
a.nav-link(data-toggle='tab', href='#macos', role='tab')
|
||||||
|
i.fa.fa-apple
|
||||||
|
span macOS
|
||||||
|
li.nav-item
|
||||||
|
a.nav-link(data-toggle='tab', href='#linux', role='tab')
|
||||||
|
i.fa.fa-linux
|
||||||
|
span Linux
|
||||||
|
|
||||||
|
.tab-content
|
||||||
|
#windows.tab-pane.active(role='tabpanel')
|
||||||
|
.row
|
||||||
|
.col-6
|
||||||
|
video(src='videos/windows.mp4', autoplay, loop)
|
||||||
|
.col-6
|
||||||
|
h3 A proper Windows experience
|
||||||
|
p
|
||||||
|
b Clink
|
||||||
|
| provides tab completion, readline-style editing and persistent command history on Windows.
|
||||||
|
p Also supported:
|
||||||
|
ul
|
||||||
|
li Classic CMD
|
||||||
|
li PowerShell
|
||||||
|
li Bash on Windows
|
||||||
|
|
||||||
|
#macos.tab-pane(role='tabpanel')
|
||||||
|
.row
|
||||||
|
.col-6
|
||||||
|
//video(src='videos/windows.mp4', autoplay, loop)
|
||||||
|
.col-6
|
||||||
|
h3 Well...
|
||||||
|
p Not much to say here, it just works.
|
||||||
|
|
||||||
|
#linux.tab-pane(role='tabpanel')
|
||||||
|
.row
|
||||||
|
.col-6
|
||||||
|
img(src='linux.png')
|
||||||
|
.col-6
|
||||||
|
p
|
||||||
|
ul
|
||||||
|
li Spawn with a global hotkey
|
||||||
|
li Tabs persist after restart
|
||||||
|
li Auto-dock to any side of any screen
|
||||||
|
li Full Unicode and double-width character support
|
||||||
|
|
||||||
|
|
||||||
.btn-group.mt-3.mb-3
|
.text-center
|
||||||
a.btn.btn-outline-primary
|
.mt-3.mb-3
|
||||||
i.fa.fa-windows
|
h2
|
||||||
span Windows
|
|
||||||
|
|
||||||
a.btn.btn-outline-primary
|
|
||||||
i.fa.fa-apple
|
|
||||||
span macOS
|
|
||||||
|
|
||||||
a.btn.btn-outline-primary
|
div
|
||||||
i.fa.fa-archive
|
.btn-group.mt-3.mb-1
|
||||||
span DEB
|
a.btn.btn-lg.btn-outline-success(href='https://github.com/Eugeny/terminus/releases/latest', target='_blank')
|
||||||
|
i.fa.fa-download
|
||||||
|
span Downloads
|
||||||
|
a.btn.btn-lg.btn-outline-secondary(href='https://github.com/Eugeny/terminus', target='_blank')
|
||||||
|
i.fa.fa-github
|
||||||
|
span GitHub
|
||||||
|
small.text-muted EXE, DMG, DEB, RPM, TGZ
|
||||||
|
|
||||||
a.btn.btn-outline-primary
|
|
||||||
i.fa.fa-archive
|
|
||||||
span RPM
|
|
||||||
|
|
||||||
a.btn.btn-outline-primary
|
|
||||||
i.fa.fa-archive
|
|
||||||
span TGZ
|
|
||||||
|
|
||||||
.row.mt-5
|
.row.mt-5
|
||||||
.col-6
|
|
||||||
h3 Proper Windows experience
|
|
||||||
p
|
|
||||||
b Clink
|
|
||||||
| provides tab completion, readline-style editing and persistent command history on Windows.
|
|
||||||
p Also supported:
|
|
||||||
ul
|
|
||||||
li Classic CMD
|
|
||||||
li PowerShell
|
|
||||||
li Bash on Windows
|
|
||||||
|
|
||||||
.col-6
|
.col-6
|
||||||
h3 User experience
|
h3 User experience
|
||||||
ul
|
ul
|
||||||
@@ -76,13 +141,20 @@ html
|
|||||||
li Click paths and URLs to open in browser/file manager
|
li Click paths and URLs to open in browser/file manager
|
||||||
li Keeps the current directory in new tabs
|
li Keeps the current directory in new tabs
|
||||||
|
|
||||||
.row.mt-5
|
|
||||||
.col-6
|
.col-6
|
||||||
h3 Customizable
|
.mb-5
|
||||||
p Multiple app themes and a myriad of community color schemes for the terminal. Color scheme editor included.
|
h3 Customizable
|
||||||
|
p Multiple app themes and a myriad of community color schemes for the terminal. Color scheme editor included.
|
||||||
.col-6
|
|
||||||
h3 Infinitely extensible
|
|
||||||
p Install plugins from the NPM repository, or create your own with Typescript and Angular framework.
|
|
||||||
|
|
||||||
|
|
||||||
|
div
|
||||||
|
h3 Infinitely extensible
|
||||||
|
p Install plugins from the NPM repository, or create your own with Typescript and Angular framework.
|
||||||
|
|
||||||
|
script.
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||||
|
|
||||||
|
ga('create', 'UA-3278102-18', 'auto');
|
||||||
|
ga('send', 'pageview');
|
||||||
|
BIN
docs/linux.png
Normal file
BIN
docs/linux.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
BIN
docs/videos/windows.mp4
Normal file
BIN
docs/videos/windows.mp4
Normal file
Binary file not shown.
@@ -21,7 +21,7 @@
|
|||||||
"less-loader": "2.2.3",
|
"less-loader": "2.2.3",
|
||||||
"node-abi": "2.0.3",
|
"node-abi": "2.0.3",
|
||||||
"node-gyp": "3.4.0",
|
"node-gyp": "3.4.0",
|
||||||
"node-sass": "4.5.3",
|
"node-sass": "^4.5.3",
|
||||||
"npmlog": "4.1.0",
|
"npmlog": "4.1.0",
|
||||||
"pug": "2.0.0-beta11",
|
"pug": "2.0.0-beta11",
|
||||||
"pug-html-loader": "1.0.9",
|
"pug-html-loader": "1.0.9",
|
||||||
@@ -65,6 +65,12 @@
|
|||||||
"linux": {
|
"linux": {
|
||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"icon": "./build/icons"
|
"icon": "./build/icons"
|
||||||
|
},
|
||||||
|
"deb": {
|
||||||
|
"depends": ["screen", "gconf2", "gconf-service", "libnotify4", "libappindicator1", "libxtst6", "libnss3"]
|
||||||
|
},
|
||||||
|
"rpm": {
|
||||||
|
"depends": ["screen"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
const childProcess = require('child_process')
|
||||||
|
|
||||||
const appInfo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../app/package.json')))
|
const appInfo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../app/package.json')))
|
||||||
const pkgInfo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json')))
|
const pkgInfo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json')))
|
||||||
|
|
||||||
|
exports.version = childProcess.execSync('git describe --tags', {encoding:'utf-8'})
|
||||||
|
exports.version = exports.version.substring(1, exports.version.length - 1)
|
||||||
|
|
||||||
exports.builtinPlugins = [
|
exports.builtinPlugins = [
|
||||||
'terminus-core',
|
'terminus-core',
|
||||||
'terminus-settings',
|
'terminus-settings',
|
||||||
@@ -12,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
|
||||||
|
@@ -15,6 +15,7 @@ div
|
|||||||
.part(style='transform: rotateZ(308deg)')
|
.part(style='transform: rotateZ(308deg)')
|
||||||
div
|
div
|
||||||
h1.terminus-title Terminus
|
h1.terminus-title Terminus
|
||||||
|
span.text-muted α
|
||||||
|
|
||||||
button.btn.btn-primary.btn-lg.btn-block(
|
button.btn.btn-primary.btn-lg.btn-block(
|
||||||
*ngFor='let button of getButtons()',
|
*ngFor='let button of getButtons()',
|
||||||
|
@@ -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')
|
|||||||
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,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,
|
||||||
|
@@ -6,7 +6,7 @@ import { TerminalColorSchemeProvider, ITerminalColorScheme } from './api'
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class HyperColorSchemes extends TerminalColorSchemeProvider {
|
export class HyperColorSchemes extends TerminalColorSchemeProvider {
|
||||||
async getSchemes (): Promise<ITerminalColorScheme[]> {
|
async getSchemes (): Promise<ITerminalColorScheme[]> {
|
||||||
let pluginsPath = path.join(process.env.HOME, '.hyper_plugins', 'node_modules')
|
let pluginsPath = path.join(process.env.HOME || (process.env.HOMEDRIVE + process.env.HOMEPATH), '.hyper_plugins', 'node_modules')
|
||||||
if (!(await fs.exists(pluginsPath))) return []
|
if (!(await fs.exists(pluginsPath))) return []
|
||||||
let plugins = await fs.readdir(pluginsPath)
|
let plugins = await fs.readdir(pluginsPath)
|
||||||
|
|
||||||
|
@@ -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))
|
||||||
}
|
}
|
||||||
|
@@ -9,10 +9,28 @@ export class TerminalConfigProvider extends ConfigProvider {
|
|||||||
background: 'theme',
|
background: 'theme',
|
||||||
colorScheme: {
|
colorScheme: {
|
||||||
__nonStructural: true,
|
__nonStructural: true,
|
||||||
foreground: null,
|
name: 'Material',
|
||||||
background: null,
|
foreground: '#eceff1',
|
||||||
cursor: null,
|
background: 'rgba(38, 50, 56, 1)',
|
||||||
colors: [],
|
cursor: '#FFCC00',
|
||||||
|
colors: [
|
||||||
|
'#000000',
|
||||||
|
'#D62341',
|
||||||
|
'#9ECE58',
|
||||||
|
'#FAED70',
|
||||||
|
'#396FE2',
|
||||||
|
'#BB80B3',
|
||||||
|
'#2DDAFD',
|
||||||
|
'#d0d0d0',
|
||||||
|
'rgba(255, 255, 255, 0.2)',
|
||||||
|
'#FF5370',
|
||||||
|
'#C3E88D',
|
||||||
|
'#FFCB6B',
|
||||||
|
'#82AAFF',
|
||||||
|
'#C792EA',
|
||||||
|
'#89DDFF',
|
||||||
|
'#ffffff',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
customColorSchemes: []
|
customColorSchemes: []
|
||||||
},
|
},
|
||||||
@@ -22,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': [
|
||||||
@@ -49,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': [
|
||||||
|
@@ -12,4 +12,5 @@ a:hover {
|
|||||||
|
|
||||||
x-screen {
|
x-screen {
|
||||||
transition: 0.125s ease background;
|
transition: 0.125s ease background;
|
||||||
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
|
@@ -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