1
1
mirror of https://github.com/Eugeny/tabby.git synced 2024-12-23 10:32:29 +03:00

autogen docs

This commit is contained in:
Eugene Pankov 2019-03-07 18:04:03 +01:00
parent c70e6fde35
commit 8cf7851801
16 changed files with 171 additions and 34 deletions

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ package-lock.json
yarn-error.log yarn-error.log
docs/api docs/api
.travis.ssh.key

BIN
.travis.ssh.key.enc Normal file

Binary file not shown.

1
.travis.ssh.key.pub Normal file
View File

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDFM4nHSbET5V7EYNgjA8NeVfOxV0wVMdZ2YvsDzD+qPJ4+MYbvsL7ZPaSxQSn7n6ATkLHjKje5RpF/Rl9K3kucGs0P6cqJVeE0qryEteQ3Q+fYAk+bD2J9ZQ/hv/0NtLl8T+7lJUZ3WUxFH73sgph77Sw0z+kMpPaK7U2vqMBQD/7+6iJgya31wP0qW0XKDz1BjKeXgwTg10Pm4vcGsR4c2q7YIzSzBHffcyo0vJyFvOX/ZKHlZRcq/wnQMeOl/hPgf1xCENjQZmFVReQlYSw5cNNDT9HZPKekOAZFFez7/AbPiTIo/bnBYIv0mdUjr3nw8nXF505q8LiD3z/ksaaWDqe9CCLM4W0Bh7/dhP7IGPdfX0fVHLhOnYIOsG21D8rWJjMPkVRSLyEvWNAnVuObJNHoQu8VATnOxfPNnMun72IHyyFWVoADk5JcsMbzcP7gZB+5oJO7U1qpcdndtBOA3ZlF0Uz2jVZnqavoEBWT39tl3vs69hAA3aTPGclg7HMuAJOl4HsKmaUgDxqV2wCX/S4pDqmKMbmumDLX+MM0xl0gXj/zpVJp9BzdnrArkC40ivmC6TSA4wrdN0tNBlqApkH5/jxGWrcu2AXVn9PGF3+QrjW0iu+QMZCaKWDhLIQC835uFwzhnNGlx41B7uxMLuNFxKXdQ3f/cC9QMG8ew== TravisCIDeployKey

View File

@ -13,15 +13,31 @@ cache:
- node_modules - node_modules
- app/node_modules - app/node_modules
before_install: stages:
- rm app/node_modules/.yarn-integrity || true - Build
- yarn - name: Docs
if: branch = master
script: jobs:
- scripts/build-native.js include:
- yarn run build - stage: 'Build'
- scripts/prepackage-plugins.js before_install:
- scripts/build-$BUILD_FOR.js - rm app/node_modules/.yarn-integrity || true
- yarn
script:
- scripts/build-native.js
- yarn run build
- scripts/prepackage-plugins.js
- scripts/build-$BUILD_FOR.js
- stage: 'Docs'
os: linux
script:
- openssl aes-256-cbc -K $encrypted_4e2fb4889ef8_key -iv $encrypted_4e2fb4889ef8_iv -in .travis.ssh.key.enc -out .travis.ssh.key -d
- ssh-add .travis.ssh.key
- yarn
- yarn run docs
- rsync -r docs/api/ root@ajenti.org:/srv/terminus-docs/
dist: trusty dist: trusty
sudo: false sudo: false

View File

@ -131,6 +131,7 @@
"watch": "cross-env TERMINUS_DEV=1 webpack --progress --color --watch", "watch": "cross-env TERMINUS_DEV=1 webpack --progress --color --watch",
"start": "cross-env TERMINUS_DEV=1 electron app --debug", "start": "cross-env TERMINUS_DEV=1 electron app --debug",
"prod": "cross-env TERMINUS_DEV=1 electron app", "prod": "cross-env TERMINUS_DEV=1 electron app",
"docs": "typedoc --out docs/api terminus-core/src && typedoc --out docs/api/terminal terminus-terminal/src && typedoc --out docs/api/settings terminus-settings/src",
"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": "node ./scripts/install-deps.js" "postinstall": "node ./scripts/install-deps.js"
}, },

View File

@ -1,6 +1,8 @@
Terminus Core Plugin Terminus Core Plugin
-------------------- --------------------
See also: [Settings plugin API](./settings/), [Terminal plugin API](./settings/)
* tabbed interface services * tabbed interface services
* toolbar UI * toolbar UI
* config file management * config file management

View File

@ -0,0 +1,23 @@
Terminus Settings Plugin
------------------------
* tabbed settings interface
Using the API:
```ts
import { SettingsTabProvider } from 'terminus-settings'
```
Exporting your subclasses:
```ts
@NgModule({
...
providers: [
...
{ provide: SettingsTabProvider, useClass: MySettingsTab, multi: true },
...
]
})
```

View File

@ -1,3 +1,6 @@
/**
* Extend to add your own settings tabs
*/
export abstract class SettingsTabProvider { export abstract class SettingsTabProvider {
id: string id: string
icon: string icon: string

View File

@ -0,0 +1,26 @@
Terminus Terminal Plugin
------------------------
* terminal tabs
* terminal frontends
* session management
* shell detection
Using the API:
```ts
import { TerminalContextMenuItemProvider } from 'terminus-terminal'
```
Exporting your subclasses:
```ts
@NgModule({
...
providers: [
...
{ provide: TerminalContextMenuItemProvider, useClass: MyContextMenu, multi: true },
...
]
})
```

View File

@ -1,10 +1,18 @@
import { BaseTerminalTabComponent } from './components/baseTerminalTab.component' import { BaseTerminalTabComponent } from './components/baseTerminalTab.component'
/**
* Extend to automatically run actions on new terminals
*/
export abstract class TerminalDecorator { export abstract class TerminalDecorator {
// tslint:disable-next-line no-empty /**
attach (_terminal: BaseTerminalTabComponent): void { } * Called when a new terminal tab starts
// tslint:disable-next-line no-empty */
detach (_terminal: BaseTerminalTabComponent): void { } attach (terminal: BaseTerminalTabComponent): void { } // tslint:disable-line no-empty
/**
* Called before a terminal tab is destroyed
*/
detach (terminal: BaseTerminalTabComponent): void { } // tslint:disable-line no-empty
} }
export interface ResizeEvent { export interface ResizeEvent {
@ -17,7 +25,7 @@ export interface SessionOptions {
command: string command: string
args: string[] args: string[]
cwd?: string cwd?: string
env?: any env?: {[id: string]: string}
width?: number width?: number
height?: number height?: number
pauseAfterExit?: boolean pauseAfterExit?: boolean
@ -37,10 +45,16 @@ export interface ITerminalColorScheme {
colors: string[] colors: string[]
} }
/**
* Extend to add more terminal color schemes
*/
export abstract class TerminalColorSchemeProvider { export abstract class TerminalColorSchemeProvider {
abstract async getSchemes (): Promise<ITerminalColorScheme[]> abstract async getSchemes (): Promise<ITerminalColorScheme[]>
} }
/**
* Extend to add more terminal context menu items
*/
export abstract class TerminalContextMenuItemProvider { export abstract class TerminalContextMenuItemProvider {
weight: number weight: number
@ -52,10 +66,18 @@ export interface IShell {
name?: string name?: string
command: string command: string
args?: string[] args?: string[]
env?: any env?: {[id: string]: string}
/**
* Base path to which shell's internal FS is relative
* Currently used for WSL only
*/
fsBase?: string fsBase?: string
} }
/**
* Extend to add support for more shells
*/
export abstract class ShellProvider { export abstract class ShellProvider {
abstract async provide (): Promise<IShell[]> abstract async provide (): Promise<IShell[]>
} }

View File

@ -10,29 +10,43 @@ import { TerminalFrontendService } from '../services/terminalFrontend.service'
import { TerminalDecorator, ResizeEvent, TerminalContextMenuItemProvider } from '../api' import { TerminalDecorator, ResizeEvent, TerminalContextMenuItemProvider } from '../api'
import { Frontend } from '../frontends/frontend' import { Frontend } from '../frontends/frontend'
/**
* A class to base your custom terminal tabs on
*/
export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit, OnDestroy { export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
static template = ` static template = `
<div <div
#content #content
class="content" class="content"
[style.opacity]="htermVisible ? 1 : 0" [style.opacity]="frontendIsReady ? 1 : 0"
></div> ></div>
` `
static styles = [require('./terminalTab.component.scss')] static styles = [require('./terminalTab.component.scss')]
session: BaseSession session: BaseSession
@Input() zoom = 0 @Input() zoom = 0
/** @hidden */
@ViewChild('content') content @ViewChild('content') content
/** @hidden */
@HostBinding('style.background-color') backgroundColor: string @HostBinding('style.background-color') backgroundColor: string
/** @hidden */
@HostBinding('class.top-padded') topPadded: boolean @HostBinding('class.top-padded') topPadded: boolean
frontend: Frontend frontend: Frontend
sessionCloseSubscription: Subscription
hotkeysSubscription: Subscription /** @hidden */
htermVisible = false frontendIsReady = false
frontendReady = new Subject<void>() frontendReady = new Subject<void>()
size: ResizeEvent size: ResizeEvent
protected logger: Logger protected logger: Logger
protected output = new Subject<string>() protected output = new Subject<string>()
private sessionCloseSubscription: Subscription
private hotkeysSubscription: Subscription
private bellPlayer: HTMLAudioElement private bellPlayer: HTMLAudioElement
private termContainerSubscriptions: Subscription[] = [] private termContainerSubscriptions: Subscription[] = []
@ -122,6 +136,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.contextMenuProviders.sort((a, b) => a.weight - b.weight) this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
} }
/** @hidden */
ngOnInit () { ngOnInit () {
this.focused$.subscribe(() => { this.focused$.subscribe(() => {
this.configure() this.configure()
@ -131,7 +146,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.frontend = this.terminalContainersService.getFrontend(this.session) this.frontend = this.terminalContainersService.getFrontend(this.session)
this.frontend.ready$.subscribe(() => { this.frontend.ready$.subscribe(() => {
this.htermVisible = true this.frontendIsReady = true
}) })
this.frontend.resize$.pipe(first()).subscribe(async ({ columns, rows }) => { this.frontend.resize$.pipe(first()).subscribe(async ({ columns, rows }) => {
@ -191,14 +206,14 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
return items return items
} }
detachTermContainerHandlers () { protected detachTermContainerHandlers () {
for (let subscription of this.termContainerSubscriptions) { for (let subscription of this.termContainerSubscriptions) {
subscription.unsubscribe() subscription.unsubscribe()
} }
this.termContainerSubscriptions = [] this.termContainerSubscriptions = []
} }
attachTermContainerHandlers () { protected attachTermContainerHandlers () {
this.detachTermContainerHandlers() this.detachTermContainerHandlers()
const maybeConfigure = () => { const maybeConfigure = () => {
@ -274,6 +289,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
] ]
} }
/**
* Feeds input into the active session
*/
sendInput (data: string) { sendInput (data: string) {
this.session.write(data) this.session.write(data)
if (this.config.store.terminal.scrollOnInput) { if (this.config.store.terminal.scrollOnInput) {
@ -281,6 +299,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
} }
} }
/**
* Feeds input into the terminal frontend
*/
write (data: string) { write (data: string) {
let percentageMatch = /(^|[^\d])(\d+(\.\d+)?)%([^\d]|$)/.exec(data) let percentageMatch = /(^|[^\d])(\d+(\.\d+)?)%([^\d]|$)/.exec(data)
if (percentageMatch) { if (percentageMatch) {
@ -308,6 +329,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.sendInput(data) this.sendInput(data)
} }
/**
* Applies the user settings to the terminal
*/
configure (): void { configure (): void {
this.frontend.configure() this.frontend.configure()
@ -339,6 +363,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.frontend.setZoom(this.zoom) this.frontend.setZoom(this.zoom)
} }
/** @hidden */
ngOnDestroy () { ngOnDestroy () {
this.frontend.detach(this.content.nativeElement) this.frontend.detach(this.content.nativeElement)
this.detachTermContainerHandlers() this.detachTermContainerHandlers()

View File

@ -5,6 +5,7 @@ import { BaseTerminalTabComponent } from './baseTerminalTab.component'
import { SessionOptions } from '../api' import { SessionOptions } from '../api'
import { Session } from '../services/sessions.service' import { Session } from '../services/sessions.service'
/** @hidden */
@Component({ @Component({
selector: 'terminalTab', selector: 'terminalTab',
template: BaseTerminalTabComponent.template, template: BaseTerminalTabComponent.template,

View File

@ -2,6 +2,9 @@ import { Observable, Subject, AsyncSubject, ReplaySubject, BehaviorSubject } fro
import { ResizeEvent } from '../api' import { ResizeEvent } from '../api'
import { ConfigService, ThemesService } from 'terminus-core' import { ConfigService, ThemesService } from 'terminus-core'
/**
* Extend to add support for a different VT frontend implementation
*/
export abstract class Frontend { export abstract class Frontend {
configService: ConfigService configService: ConfigService
themesService: ThemesService themesService: ThemesService

View File

@ -10,16 +10,13 @@ import { exec } from 'mz/child_process'
import { SessionOptions } from '../api' import { SessionOptions } from '../api'
import { WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild } from '../utils' import { WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild } from '../utils'
let macOSNativeProcessList
try { try {
macOSNativeProcessList = require('macos-native-processlist') var macOSNativeProcessList = require('macos-native-processlist') // tslint:disable-line
} catch (e) { } // tslint:disable-line } catch { } // tslint:disable-line
let windowsProcessTree
try { try {
windowsProcessTree = require('windows-process-tree') var windowsProcessTree = require('windows-process-tree') // tslint:disable-line
} catch (e) { } catch { } // tslint:disable-line
} // tslint:disable-line
export interface IChildProcess { export interface IChildProcess {
pid: number pid: number
@ -31,6 +28,10 @@ const windowsDirectoryRegex = /([a-zA-Z]:[^\:\[\]\?\"\<\>\|]+)/mi // tslint:dis
const OSC1337Prefix = '\x1b]1337;' const OSC1337Prefix = '\x1b]1337;'
const OSC1337Suffix = '\x07' const OSC1337Suffix = '\x07'
/**
* A session object for a [[BaseTerminalTabComponent]]
* Extend this to implement custom I/O and process management for your terminal tab
*/
export abstract class BaseSession { export abstract class BaseSession {
open: boolean open: boolean
name: string name: string
@ -59,10 +60,10 @@ export abstract class BaseSession {
this.initialDataBuffer = null this.initialDataBuffer = null
} }
abstract start (options: SessionOptions) abstract start (options: SessionOptions): void
abstract resize (columns, rows) abstract resize (columns: number, rows: number): void
abstract write (data) abstract write (data: string): void
abstract kill (signal?: string) abstract kill (signal?: string): void
abstract async getChildProcesses (): Promise<IChildProcess[]> abstract async getChildProcesses (): Promise<IChildProcess[]>
abstract async gracefullyKillProcess (): Promise<void> abstract async gracefullyKillProcess (): Promise<void>
abstract async getWorkingDirectory (): Promise<string> abstract async getWorkingDirectory (): Promise<string>

View File

@ -11,8 +11,12 @@ export class TerminalService {
private shells = new AsyncSubject<IShell[]>() private shells = new AsyncSubject<IShell[]>()
private logger: Logger private logger: Logger
/**
* A fresh list of all available shells
*/
get shells$ (): Observable<IShell[]> { return this.shells } get shells$ (): Observable<IShell[]> { return this.shells }
/** @hidden */
constructor ( constructor (
private app: AppService, private app: AppService,
private config: ConfigService, private config: ConfigService,
@ -28,12 +32,12 @@ export class TerminalService {
}) })
} }
async getShells (): Promise<IShell[]> { private async getShells (): Promise<IShell[]> {
let shellLists = await Promise.all(this.config.enabledServices(this.shellProviders).map(x => x.provide())) let shellLists = await Promise.all(this.config.enabledServices(this.shellProviders).map(x => x.provide()))
return shellLists.reduce((a, b) => a.concat(b), []) return shellLists.reduce((a, b) => a.concat(b), [])
} }
async reloadShells () { private async reloadShells () {
this.shells = new AsyncSubject<IShell[]>() this.shells = new AsyncSubject<IShell[]>()
let shells = await this.getShells() let shells = await this.getShells()
this.logger.debug('Shells list:', shells) this.logger.debug('Shells list:', shells)
@ -41,6 +45,10 @@ export class TerminalService {
this.shells.complete() this.shells.complete()
} }
/**
* Launches a new terminal with a specific shell and CWD
* @param pause Wait for a keypress when the shell exits
*/
async openTab (shell?: IShell, cwd?: string, pause?: boolean): Promise<TerminalTabComponent> { async openTab (shell?: IShell, cwd?: string, pause?: boolean): Promise<TerminalTabComponent> {
if (cwd && !fs.existsSync(cwd)) { if (cwd && !fs.existsSync(cwd)) {
console.warn('Ignoring non-existent CWD:', cwd) console.warn('Ignoring non-existent CWD:', cwd)
@ -76,6 +84,9 @@ export class TerminalService {
} }
} }
/**
* Open a terminal with custom session options
*/
openTabWithOptions (sessionOptions: SessionOptions): TerminalTabComponent { openTabWithOptions (sessionOptions: SessionOptions): TerminalTabComponent {
if (sessionOptions.runAsAdministrator && this.uac.isAvailable) { if (sessionOptions.runAsAdministrator && this.uac.isAvailable) {
sessionOptions = this.uac.patchSessionOptionsForUAC(sessionOptions) sessionOptions = this.uac.patchSessionOptionsForUAC(sessionOptions)

View File

@ -9,6 +9,7 @@ import { BaseSession } from '../services/sessions.service'
export class TerminalFrontendService { export class TerminalFrontendService {
private containers = new WeakMap<BaseSession, Frontend>() private containers = new WeakMap<BaseSession, Frontend>()
/** @hidden */
constructor (private config: ConfigService, private themes: ThemesService) { } constructor (private config: ConfigService, private themes: ThemesService) { }
getFrontend (session?: BaseSession): Frontend { getFrontend (session?: BaseSession): Frontend {