mirror of
https://github.com/Eugeny/tabby.git
synced 2024-12-22 18:11:43 +03:00
prepared terminus-core for typedocs
This commit is contained in:
parent
cf5e31be79
commit
2ed35cb400
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,3 +18,5 @@ npm-debug.log
|
||||
builtin-plugins
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
|
||||
docs/api
|
||||
|
@ -45,6 +45,7 @@
|
||||
"tslint": "^5.12.0",
|
||||
"tslint-config-standard": "^8.0.1",
|
||||
"tslint-eslint-rules": "^5.4.0",
|
||||
"typedoc": "^0.14.2",
|
||||
"typescript": "^3.1.3",
|
||||
"url-loader": "^1.1.1",
|
||||
"val-loader": "0.5.0",
|
||||
|
29
terminus-core/README.md
Normal file
29
terminus-core/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
Terminus Core Plugin
|
||||
--------------------
|
||||
|
||||
* tabbed interface services
|
||||
* toolbar UI
|
||||
* config file management
|
||||
* hotkeys
|
||||
* tab recovery
|
||||
* logging
|
||||
* theming
|
||||
|
||||
Using the API:
|
||||
|
||||
```ts
|
||||
import { AppService, TabContextMenuItemProvider } from 'terminus-core'
|
||||
```
|
||||
|
||||
Exporting your subclasses:
|
||||
|
||||
```ts
|
||||
@NgModule({
|
||||
...
|
||||
providers: [
|
||||
...
|
||||
{ provide: TabContextMenuItemProvider, useClass: MyContextMenu, multi: true },
|
||||
...
|
||||
]
|
||||
})
|
||||
```
|
@ -1,4 +1,37 @@
|
||||
/**
|
||||
* Extend to add your own config options
|
||||
*/
|
||||
export abstract class ConfigProvider {
|
||||
/**
|
||||
* Default values, e.g.
|
||||
*
|
||||
* ```ts
|
||||
* defaults = {
|
||||
* myPlugin: {
|
||||
* foo: 1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
defaults: any = {}
|
||||
platformDefaults: any = {}
|
||||
|
||||
/**
|
||||
* [[Platform]] specific defaults, e.g.
|
||||
*
|
||||
* ```ts
|
||||
* platformDefaults = {
|
||||
* [Platform.Windows]: {
|
||||
* myPlugin: {
|
||||
* bar: true
|
||||
* }
|
||||
* },
|
||||
* [Platform.macOS]: {
|
||||
* myPlugin: {
|
||||
* bar: false
|
||||
* }
|
||||
* },
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
platformDefaults: {[platform: string]: any} = {}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
export interface IHotkeyDescription {
|
||||
id: string,
|
||||
name: string,
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend to provide your own hotkeys. A corresponding [[ConfigProvider]]
|
||||
* must also provide the `hotkeys.foo` config options with the default values
|
||||
*/
|
||||
export abstract class HotkeyProvider {
|
||||
hotkeys: IHotkeyDescription[] = []
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { TabHeaderComponent } from '../components/tabHeader.component'
|
||||
|
||||
/**
|
||||
* Extend to add items to the tab header's context menu
|
||||
*/
|
||||
export abstract class TabContextMenuItemProvider {
|
||||
weight = 0
|
||||
|
||||
|
@ -1,10 +1,38 @@
|
||||
import { TabComponentType } from '../services/tabs.service'
|
||||
|
||||
export interface RecoveredTab {
|
||||
type: TabComponentType,
|
||||
options?: any,
|
||||
/**
|
||||
* Component type to be instantiated
|
||||
*/
|
||||
type: TabComponentType
|
||||
|
||||
/**
|
||||
* Component instance inputs
|
||||
*/
|
||||
options?: any
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend to enable recovery for your custom tab.
|
||||
* This works in conjunction with [[getRecoveryToken()]]
|
||||
*
|
||||
* Terminus will try to find any [[TabRecoveryProvider]] that is able to process
|
||||
* the recovery token previously returned by [[getRecoveryToken]].
|
||||
*
|
||||
* Recommended token format:
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* type: 'my-tab-type',
|
||||
* foo: 'bar',
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export abstract class TabRecoveryProvider {
|
||||
/**
|
||||
* @param recoveryToken a recovery token found in the saved tabs list
|
||||
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs
|
||||
* or `null` if this token is from a different tab type or is not supported
|
||||
*/
|
||||
abstract async recover (recoveryToken: any): Promise<RecoveredTab | null>
|
||||
}
|
||||
|
@ -1,5 +1,13 @@
|
||||
/**
|
||||
* Extend to add a custom CSS theme
|
||||
*/
|
||||
export abstract class Theme {
|
||||
name: string
|
||||
|
||||
/**
|
||||
* Complete CSS stylesheet
|
||||
*/
|
||||
css: string
|
||||
|
||||
terminalBackground: string
|
||||
}
|
||||
|
@ -1,14 +1,34 @@
|
||||
import { SafeHtml } from '@angular/platform-browser'
|
||||
|
||||
/**
|
||||
* See [[ToolbarButtonProvider]]
|
||||
*/
|
||||
export interface IToolbarButton {
|
||||
/**
|
||||
* Raw SVG icon code
|
||||
*/
|
||||
icon: SafeHtml
|
||||
touchBarNSImage?: string
|
||||
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar icon ID
|
||||
*/
|
||||
touchBarNSImage?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar button label
|
||||
*/
|
||||
touchBarTitle?: string
|
||||
|
||||
weight?: number
|
||||
|
||||
click: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend to add buttons to the toolbar
|
||||
*/
|
||||
export abstract class ToolbarButtonProvider {
|
||||
abstract provide (): IToolbarButton[]
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import { BaseTabComponent } from './baseTab.component'
|
||||
import { SafeModeModalComponent } from './safeModeModal.component'
|
||||
import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: require('./appRoot.component.pug'),
|
||||
@ -126,6 +127,11 @@ export class AppRootComponent {
|
||||
this.onGlobalHotkey()
|
||||
})
|
||||
|
||||
this.hostApp.windowCloseRequest$.subscribe(async () => {
|
||||
await this.app.closeAllTabs()
|
||||
this.hostApp.closeWindow()
|
||||
})
|
||||
|
||||
if (window['safeModeReason']) {
|
||||
ngbModal.open(SafeModeModalComponent)
|
||||
}
|
||||
|
@ -1,26 +1,58 @@
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { ViewRef } from '@angular/core'
|
||||
|
||||
/**
|
||||
* Represents an active "process" inside a tab,
|
||||
* for example, a user process running inside a terminal tab
|
||||
*/
|
||||
export interface BaseTabProcess {
|
||||
name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for custom tab components
|
||||
*/
|
||||
export abstract class BaseTabComponent {
|
||||
/**
|
||||
* Current tab title
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* User-defined title override
|
||||
*/
|
||||
customTitle: string
|
||||
hasFocus = false
|
||||
|
||||
/**
|
||||
* Last tab activity state
|
||||
*/
|
||||
hasActivity = false
|
||||
|
||||
/**
|
||||
* ViewRef to the tab DOM element
|
||||
*/
|
||||
hostView: ViewRef
|
||||
|
||||
/**
|
||||
* CSS color override for the tab's header
|
||||
*/
|
||||
color: string = null
|
||||
protected titleChange = new Subject<string>()
|
||||
protected focused = new Subject<void>()
|
||||
protected blurred = new Subject<void>()
|
||||
protected progress = new Subject<number>()
|
||||
protected activity = new Subject<boolean>()
|
||||
protected destroyed = new Subject<void>()
|
||||
|
||||
protected hasFocus = false
|
||||
|
||||
/**
|
||||
* Ping this if your recovery state has been changed and you want
|
||||
* your tab state to be saved sooner
|
||||
*/
|
||||
protected recoveryStateChangedHint = new Subject<void>()
|
||||
|
||||
private progressClearTimeout: number
|
||||
private titleChange = new Subject<string>()
|
||||
private focused = new Subject<void>()
|
||||
private blurred = new Subject<void>()
|
||||
private progress = new Subject<number>()
|
||||
private activity = new Subject<boolean>()
|
||||
private destroyed = new Subject<void>()
|
||||
|
||||
get focused$ (): Observable<void> { return this.focused }
|
||||
get blurred$ (): Observable<void> { return this.blurred }
|
||||
@ -46,6 +78,11 @@ export abstract class BaseTabComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets visual progressbar on the tab
|
||||
*
|
||||
* @param {type} progress: value between 0 and 1, or `null` to remove
|
||||
*/
|
||||
setProgress (progress: number) {
|
||||
this.progress.next(progress)
|
||||
if (progress) {
|
||||
@ -58,24 +95,43 @@ export abstract class BaseTabComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the acticity marker on the tab header
|
||||
*/
|
||||
displayActivity (): void {
|
||||
this.hasActivity = true
|
||||
this.activity.next(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the acticity marker from the tab header
|
||||
*/
|
||||
clearActivity (): void {
|
||||
this.hasActivity = false
|
||||
this.activity.next(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this and implement a [[TabRecoveryProvider]] to enable recovery
|
||||
* for your custom tab
|
||||
*
|
||||
* @return JSON serializable tab state representation
|
||||
* for your [[TabRecoveryProvider]] to parse
|
||||
*/
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to enable task completion notifications for the tab
|
||||
*/
|
||||
async getCurrentProcess (): Promise<BaseTabProcess> {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false to prevent the tab from being closed
|
||||
*/
|
||||
async canClose (): Promise<boolean> {
|
||||
return true
|
||||
}
|
||||
@ -88,6 +144,9 @@ export abstract class BaseTabComponent {
|
||||
this.blurred.next()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the tab is closed
|
||||
*/
|
||||
destroy (): void {
|
||||
this.focused.complete()
|
||||
this.blurred.complete()
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { NgZone, Component, Input, HostBinding, HostListener } from '@angular/core'
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'checkbox',
|
||||
template: require('./checkbox.component.pug'),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, Input, ElementRef, ViewChild } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'rename-tab-modal',
|
||||
template: require('./renameTabModal.component.pug'),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: require('./safeModeModal.component.pug'),
|
||||
})
|
||||
|
@ -9,15 +9,30 @@ import { TabRecoveryService } from '../services/tabRecovery.service'
|
||||
export declare type SplitOrientation = 'v' | 'h'
|
||||
export declare type SplitDirection = 'r' | 't' | 'b' | 'l'
|
||||
|
||||
/**
|
||||
* Describes a horizontal or vertical split row or column
|
||||
*/
|
||||
export class SplitContainer {
|
||||
orientation: SplitOrientation = 'h'
|
||||
|
||||
/**
|
||||
* Children could be tabs or other containers
|
||||
*/
|
||||
children: (BaseTabComponent | SplitContainer)[] = []
|
||||
|
||||
/**
|
||||
* Relative sizes of children, between 0 and 1. Total sum is 1
|
||||
*/
|
||||
ratios: number[] = []
|
||||
|
||||
x: number
|
||||
y: number
|
||||
w: number
|
||||
h: number
|
||||
|
||||
/**
|
||||
* @return Flat list of all tabs inside this container
|
||||
*/
|
||||
getAllTabs () {
|
||||
let r = []
|
||||
for (let child of this.children) {
|
||||
@ -30,6 +45,9 @@ export class SplitContainer {
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unnecessarily nested child containers and renormalizes [[ratios]]
|
||||
*/
|
||||
normalize () {
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
let child = this.children[i]
|
||||
@ -64,6 +82,9 @@ export class SplitContainer {
|
||||
this.ratios = this.ratios.map(x => x / s)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the left/top side offset for the given element index (between 0 and 1)
|
||||
*/
|
||||
getOffsetRatio (index: number): number {
|
||||
let s = 0
|
||||
for (let i = 0; i < index; i++) {
|
||||
@ -90,11 +111,22 @@ export class SplitContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a spanner (draggable border between two split areas)
|
||||
*/
|
||||
export interface SplitSpannerInfo {
|
||||
container: SplitContainer
|
||||
|
||||
/**
|
||||
* Number of the right/bottom split in the container
|
||||
*/
|
||||
index: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Split tab is a tab that contains other tabs and allows further splitting them
|
||||
* You'll mainly encounter it inside [[AppService]].tabs
|
||||
*/
|
||||
@Component({
|
||||
selector: 'split-tab',
|
||||
template: `
|
||||
@ -109,23 +141,43 @@ export interface SplitSpannerInfo {
|
||||
styles: [require('./splitTab.component.scss')],
|
||||
})
|
||||
export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
|
||||
/** @hidden */
|
||||
@ViewChild('vc', { read: ViewContainerRef }) viewContainer: ViewContainerRef
|
||||
|
||||
/**
|
||||
* Top-level split container
|
||||
*/
|
||||
root: SplitContainer
|
||||
|
||||
/** @hidden */
|
||||
_recoveredState: any
|
||||
|
||||
/** @hidden */
|
||||
_spanners: SplitSpannerInfo[] = []
|
||||
|
||||
private focusedTab: BaseTabComponent
|
||||
private hotkeysSubscription: Subscription
|
||||
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
|
||||
|
||||
protected tabAdded = new Subject<BaseTabComponent>()
|
||||
protected tabRemoved = new Subject<BaseTabComponent>()
|
||||
protected splitAdjusted = new Subject<SplitSpannerInfo>()
|
||||
protected focusChanged = new Subject<BaseTabComponent>()
|
||||
private tabAdded = new Subject<BaseTabComponent>()
|
||||
private tabRemoved = new Subject<BaseTabComponent>()
|
||||
private splitAdjusted = new Subject<SplitSpannerInfo>()
|
||||
private focusChanged = new Subject<BaseTabComponent>()
|
||||
|
||||
get tabAdded$ (): Observable<BaseTabComponent> { return this.tabAdded }
|
||||
get tabRemoved$ (): Observable<BaseTabComponent> { return this.tabRemoved }
|
||||
|
||||
/**
|
||||
* Fired when split ratio is changed for a given spanner
|
||||
*/
|
||||
get splitAdjusted$ (): Observable<SplitSpannerInfo> { return this.splitAdjusted }
|
||||
|
||||
/**
|
||||
* Fired when a different sub-tab gains focus
|
||||
*/
|
||||
get focusChanged$ (): Observable<BaseTabComponent> { return this.focusChanged }
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private hotkeys: HotkeysService,
|
||||
private tabsService: TabsService,
|
||||
@ -174,6 +226,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
})
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async ngOnInit () {
|
||||
if (this._recoveredState) {
|
||||
await this.recoverContainer(this.root, this._recoveredState)
|
||||
@ -185,10 +238,12 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
ngOnDestroy () {
|
||||
this.hotkeysSubscription.unsubscribe()
|
||||
}
|
||||
|
||||
/** @returns Flat list of all sub-tabs */
|
||||
getAllTabs () {
|
||||
return this.root.getAllTabs()
|
||||
}
|
||||
@ -211,6 +266,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
this.layout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Focuses the first available tab inside the given [[SplitContainer]]
|
||||
*/
|
||||
focusAnyIn (parent: BaseTabComponent | SplitContainer) {
|
||||
if (!parent) {
|
||||
return
|
||||
@ -222,13 +280,16 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
}
|
||||
}
|
||||
|
||||
addTab (tab: BaseTabComponent, relative: BaseTabComponent, dir: SplitDirection) {
|
||||
/**
|
||||
* Inserts a new `tab` to the `side` of the `relative` tab
|
||||
*/
|
||||
addTab (tab: BaseTabComponent, relative: BaseTabComponent, side: SplitDirection) {
|
||||
let target = this.getParentOf(relative) || this.root
|
||||
let insertIndex = target.children.indexOf(relative)
|
||||
|
||||
if (
|
||||
(target.orientation === 'v' && ['l', 'r'].includes(dir)) ||
|
||||
(target.orientation === 'h' && ['t', 'b'].includes(dir))
|
||||
(target.orientation === 'v' && ['l', 'r'].includes(side)) ||
|
||||
(target.orientation === 'h' && ['t', 'b'].includes(side))
|
||||
) {
|
||||
let newContainer = new SplitContainer()
|
||||
newContainer.orientation = (target.orientation === 'v') ? 'h' : 'v'
|
||||
@ -242,7 +303,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
if (insertIndex === -1) {
|
||||
insertIndex = 0
|
||||
} else {
|
||||
insertIndex += (dir === 'l' || dir === 't') ? 0 : 1
|
||||
insertIndex += (side === 'l' || side === 't') ? 0 : 1
|
||||
}
|
||||
|
||||
for (let i = 0; i < target.children.length; i++) {
|
||||
@ -278,6 +339,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves focus in the given direction
|
||||
*/
|
||||
navigate (dir: SplitDirection) {
|
||||
let rel: BaseTabComponent | SplitContainer = this.focusedTab
|
||||
let parent = this.getParentOf(rel)
|
||||
@ -309,6 +373,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
this.addTab(newTab, tab, dir)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the immediate parent of `tab`
|
||||
*/
|
||||
getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer {
|
||||
root = root || this.root
|
||||
for (let child of root.children) {
|
||||
@ -325,18 +392,22 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
return null
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async canClose (): Promise<boolean> {
|
||||
return !(await Promise.all(this.getAllTabs().map(x => x.canClose()))).some(x => !x)
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
return this.root.serialize()
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async getCurrentProcess (): Promise<BaseTabProcess> {
|
||||
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x)
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
onSpannerAdjusted (spanner: SplitSpannerInfo) {
|
||||
this.layout()
|
||||
this.splitAdjusted.next(spanner)
|
||||
@ -433,6 +504,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
|
||||
async recover (recoveryToken: any): Promise<RecoveredTab> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, Input, HostBinding, ElementRef, Output, EventEmitter } from '@angular/core'
|
||||
import { SplitContainer } from './splitTab.component'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'split-tab-spanner',
|
||||
template: '',
|
||||
|
@ -3,6 +3,7 @@ import { ConfigService } from '../services/config.service'
|
||||
import { HomeBaseService } from '../services/homeBase.service'
|
||||
import { IToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'start-page',
|
||||
template: require('./startPage.component.pug'),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, Input, ViewChild, HostBinding, ViewContainerRef, OnChanges } from '@angular/core'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'tab-body',
|
||||
template: `
|
||||
|
@ -9,6 +9,7 @@ import { ElectronService } from '../services/electron.service'
|
||||
import { AppService } from '../services/app.service'
|
||||
import { HostAppService, Platform } from '../services/hostApp.service'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'tab-header',
|
||||
template: require('./tabHeader.component.pug'),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Component } from '@angular/core'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'title-bar',
|
||||
template: require('./titleBar.component.pug'),
|
||||
|
@ -2,6 +2,7 @@ import { Component } from '@angular/core'
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
import { CheckboxComponent } from './checkbox.component'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'toggle',
|
||||
template: `
|
||||
|
@ -9,7 +9,7 @@ button.btn.btn-secondary.btn-maximize(
|
||||
svg(version='1.1', width='10', height='10')
|
||||
path(d='M 0,0 0,10 10,10 10,0 Z M 1,1 9,1 9,9 1,9 Z')
|
||||
button.btn.btn-secondary.btn-close(
|
||||
(click)='app.closeWindow()'
|
||||
(click)='closeWindow()'
|
||||
)
|
||||
svg(version='1.1', width='10', height='10')
|
||||
path(d='M 0,0 0,0.7 4.3,5 0,9.3 0,10 0.7,10 5,5.7 9.3,10 10,10 10,9.3 5.7,5 10,0.7 10,0 9.3,0 5,4.3 0.7,0 Z')
|
||||
|
@ -2,6 +2,7 @@ import { Component } from '@angular/core'
|
||||
import { HostAppService } from '../services/hostApp.service'
|
||||
import { AppService } from '../services/app.service'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'window-controls',
|
||||
template: require('./windowControls.component.pug'),
|
||||
@ -9,4 +10,9 @@ import { AppService } from '../services/app.service'
|
||||
})
|
||||
export class WindowControlsComponent {
|
||||
constructor (public hostApp: HostAppService, public app: AppService) { }
|
||||
|
||||
async closeWindow () {
|
||||
await this.app.closeAllTabs()
|
||||
this.hostApp.closeWindow()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ConfigProvider } from './api/configProvider'
|
||||
import { Platform } from './services/hostApp.service'
|
||||
|
||||
/** @hidden */
|
||||
export class CoreConfigProvider extends ConfigProvider {
|
||||
platformDefaults = {
|
||||
[Platform.macOS]: require('./configDefaults.macos.yaml'),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Directive, AfterViewInit, ElementRef } from '@angular/core'
|
||||
|
||||
/** @hidden */
|
||||
@Directive({
|
||||
selector: '[autofocus]'
|
||||
})
|
||||
|
117
terminus-core/src/hotkeys.ts
Normal file
117
terminus-core/src/hotkeys.ts
Normal file
@ -0,0 +1,117 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { IHotkeyDescription, HotkeyProvider } from './api/hotkeyProvider'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class AppHotkeyProvider extends HotkeyProvider {
|
||||
hotkeys: IHotkeyDescription[] = [
|
||||
{
|
||||
id: 'new-window',
|
||||
name: 'New window',
|
||||
},
|
||||
{
|
||||
id: 'toggle-window',
|
||||
name: 'Toggle terminal window',
|
||||
},
|
||||
{
|
||||
id: 'toggle-fullscreen',
|
||||
name: 'Toggle fullscreen mode',
|
||||
},
|
||||
{
|
||||
id: 'rename-tab',
|
||||
name: 'Rename Tab',
|
||||
},
|
||||
{
|
||||
id: 'close-tab',
|
||||
name: 'Close tab',
|
||||
},
|
||||
{
|
||||
id: 'toggle-last-tab',
|
||||
name: 'Toggle last tab',
|
||||
},
|
||||
{
|
||||
id: 'next-tab',
|
||||
name: 'Next tab',
|
||||
},
|
||||
{
|
||||
id: 'previous-tab',
|
||||
name: 'Previous tab',
|
||||
},
|
||||
{
|
||||
id: 'tab-1',
|
||||
name: 'Tab 1',
|
||||
},
|
||||
{
|
||||
id: 'tab-2',
|
||||
name: 'Tab 2',
|
||||
},
|
||||
{
|
||||
id: 'tab-3',
|
||||
name: 'Tab 3',
|
||||
},
|
||||
{
|
||||
id: 'tab-4',
|
||||
name: 'Tab 4',
|
||||
},
|
||||
{
|
||||
id: 'tab-5',
|
||||
name: 'Tab 5',
|
||||
},
|
||||
{
|
||||
id: 'tab-6',
|
||||
name: 'Tab 6',
|
||||
},
|
||||
{
|
||||
id: 'tab-7',
|
||||
name: 'Tab 7',
|
||||
},
|
||||
{
|
||||
id: 'tab-8',
|
||||
name: 'Tab 8',
|
||||
},
|
||||
{
|
||||
id: 'tab-9',
|
||||
name: 'Tab 9',
|
||||
},
|
||||
{
|
||||
id: 'tab-10',
|
||||
name: 'Tab 10',
|
||||
},
|
||||
{
|
||||
id: 'split-right',
|
||||
name: 'Split to the right',
|
||||
},
|
||||
{
|
||||
id: 'split-bottom',
|
||||
name: 'Split to the bottom',
|
||||
},
|
||||
{
|
||||
id: 'split-left',
|
||||
name: 'Split to the left',
|
||||
},
|
||||
{
|
||||
id: 'split-top',
|
||||
name: 'Split to the top',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-up',
|
||||
name: 'Focus the pane above',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-down',
|
||||
name: 'Focus the pane below',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-left',
|
||||
name: 'Focus the pane on the left',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-right',
|
||||
name: 'Focus the pane on the right',
|
||||
},
|
||||
]
|
||||
|
||||
async provide (): Promise<IHotkeyDescription[]> {
|
||||
return this.hotkeys
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar'
|
||||
import { DndModule } from 'ng2-dnd'
|
||||
|
||||
import { AppHotkeyProvider } from './services/hotkeys.service'
|
||||
|
||||
import { AppRootComponent } from './components/appRoot.component'
|
||||
import { CheckboxComponent } from './components/checkbox.component'
|
||||
import { TabBodyComponent } from './components/tabBody.component'
|
||||
@ -31,6 +29,7 @@ import { TabRecoveryProvider } from './api/tabRecovery'
|
||||
|
||||
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
|
||||
import { CoreConfigProvider } from './config'
|
||||
import { AppHotkeyProvider } from './hotkeys'
|
||||
import { TaskCompletionContextMenu, CommonOptionsContextMenu, CloseContextMenu } from './tabContextMenu'
|
||||
|
||||
import 'perfect-scrollbar/css/perfect-scrollbar.css'
|
||||
@ -49,6 +48,7 @@ const PROVIDERS = [
|
||||
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } }
|
||||
]
|
||||
|
||||
/** @hidden */
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -3,7 +3,6 @@ import { takeUntil } from 'rxjs/operators'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { SplitTabComponent } from '../components/splitTab.component'
|
||||
import { Logger, LogService } from './log.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { HostAppService } from './hostApp.service'
|
||||
import { TabRecoveryService } from './tabRecovery.service'
|
||||
@ -39,9 +38,11 @@ class CompletionObserver {
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AppService {
|
||||
tabs: BaseTabComponent[] = []
|
||||
activeTab: BaseTabComponent
|
||||
lastTabIndex = 0
|
||||
logger: Logger
|
||||
|
||||
get activeTab (): BaseTabComponent { return this._activeTab }
|
||||
|
||||
private lastTabIndex = 0
|
||||
private _activeTab: BaseTabComponent
|
||||
|
||||
private activeTabChange = new Subject<BaseTabComponent>()
|
||||
private tabsChanged = new Subject<void>()
|
||||
@ -55,19 +56,17 @@ export class AppService {
|
||||
get tabOpened$ (): Observable<BaseTabComponent> { return this.tabOpened }
|
||||
get tabsChanged$ (): Observable<void> { return this.tabsChanged }
|
||||
get tabClosed$ (): Observable<BaseTabComponent> { return this.tabClosed }
|
||||
|
||||
/** Fires once when the app is ready */
|
||||
get ready$ (): Observable<void> { return this.ready }
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
private tabRecovery: TabRecoveryService,
|
||||
private tabsService: TabsService,
|
||||
log: LogService,
|
||||
) {
|
||||
this.logger = log.create('app')
|
||||
|
||||
this.hostApp.windowCloseRequest$.subscribe(() => this.closeWindow())
|
||||
|
||||
this.tabRecovery.recoverTabs().then(tabs => {
|
||||
for (let tab of tabs) {
|
||||
this.openNewTabRaw(tab.type, tab.options)
|
||||
@ -82,7 +81,7 @@ export class AppService {
|
||||
})
|
||||
}
|
||||
|
||||
addTabRaw (tab: BaseTabComponent) {
|
||||
private addTabRaw (tab: BaseTabComponent) {
|
||||
this.tabs.push(tab)
|
||||
this.selectTab(tab)
|
||||
this.tabsChanged.next()
|
||||
@ -93,7 +92,7 @@ export class AppService {
|
||||
})
|
||||
|
||||
tab.titleChange$.subscribe(title => {
|
||||
if (tab === this.activeTab) {
|
||||
if (tab === this._activeTab) {
|
||||
this.hostApp.setTitle(title)
|
||||
}
|
||||
})
|
||||
@ -101,7 +100,7 @@ export class AppService {
|
||||
tab.destroyed$.subscribe(() => {
|
||||
let newIndex = Math.max(0, this.tabs.indexOf(tab) - 1)
|
||||
this.tabs = this.tabs.filter((x) => x !== tab)
|
||||
if (tab === this.activeTab) {
|
||||
if (tab === this._activeTab) {
|
||||
this.selectTab(this.tabs[newIndex])
|
||||
}
|
||||
this.tabsChanged.next()
|
||||
@ -109,12 +108,20 @@ export class AppService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tab **without** wrapping it in a SplitTabComponent
|
||||
* @param inputs Properties to be assigned on the new tab component instance
|
||||
*/
|
||||
openNewTabRaw (type: TabComponentType, inputs?: any): BaseTabComponent {
|
||||
let tab = this.tabsService.create(type, inputs)
|
||||
this.addTabRaw(tab)
|
||||
return tab
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tab while wrapping it in a SplitTabComponent
|
||||
* @param inputs Properties to be assigned on the new tab component instance
|
||||
*/
|
||||
openNewTab (type: TabComponentType, inputs?: any): BaseTabComponent {
|
||||
let splitTab = this.tabsService.create(SplitTabComponent) as SplitTabComponent
|
||||
let tab = this.tabsService.create(type, inputs)
|
||||
@ -124,29 +131,30 @@ export class AppService {
|
||||
}
|
||||
|
||||
selectTab (tab: BaseTabComponent) {
|
||||
if (this.activeTab === tab) {
|
||||
this.activeTab.emitFocused()
|
||||
if (this._activeTab === tab) {
|
||||
this._activeTab.emitFocused()
|
||||
return
|
||||
}
|
||||
if (this.tabs.includes(this.activeTab)) {
|
||||
this.lastTabIndex = this.tabs.indexOf(this.activeTab)
|
||||
if (this.tabs.includes(this._activeTab)) {
|
||||
this.lastTabIndex = this.tabs.indexOf(this._activeTab)
|
||||
} else {
|
||||
this.lastTabIndex = null
|
||||
}
|
||||
if (this.activeTab) {
|
||||
this.activeTab.clearActivity()
|
||||
this.activeTab.emitBlurred()
|
||||
if (this._activeTab) {
|
||||
this._activeTab.clearActivity()
|
||||
this._activeTab.emitBlurred()
|
||||
}
|
||||
this.activeTab = tab
|
||||
this._activeTab = tab
|
||||
this.activeTabChange.next(tab)
|
||||
if (this.activeTab) {
|
||||
if (this._activeTab) {
|
||||
setImmediate(() => {
|
||||
this.activeTab.emitFocused()
|
||||
this._activeTab.emitFocused()
|
||||
})
|
||||
this.hostApp.setTitle(this.activeTab.title)
|
||||
this.hostApp.setTitle(this._activeTab.title)
|
||||
}
|
||||
}
|
||||
|
||||
/** Switches between the current tab and the previously active one */
|
||||
toggleLastTab () {
|
||||
if (!this.lastTabIndex || this.lastTabIndex >= this.tabs.length) {
|
||||
this.lastTabIndex = 0
|
||||
@ -156,7 +164,7 @@ export class AppService {
|
||||
|
||||
nextTab () {
|
||||
if (this.tabs.length > 1) {
|
||||
let tabIndex = this.tabs.indexOf(this.activeTab)
|
||||
let tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex < this.tabs.length - 1) {
|
||||
this.selectTab(this.tabs[tabIndex + 1])
|
||||
} else if (this.config.store.appearance.cycleTabs) {
|
||||
@ -167,7 +175,7 @@ export class AppService {
|
||||
|
||||
previousTab () {
|
||||
if (this.tabs.length > 1) {
|
||||
let tabIndex = this.tabs.indexOf(this.activeTab)
|
||||
let tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex > 0) {
|
||||
this.selectTab(this.tabs[tabIndex - 1])
|
||||
} else if (this.config.store.appearance.cycleTabs) {
|
||||
@ -176,6 +184,7 @@ export class AppService {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
emitTabsChanged () {
|
||||
this.tabsChanged.next()
|
||||
}
|
||||
@ -197,7 +206,7 @@ export class AppService {
|
||||
}
|
||||
}
|
||||
|
||||
async closeWindow () {
|
||||
async closeAllTabs () {
|
||||
for (let tab of this.tabs) {
|
||||
if (!await tab.canClose()) {
|
||||
return
|
||||
@ -206,15 +215,19 @@ export class AppService {
|
||||
for (let tab of this.tabs) {
|
||||
tab.destroy()
|
||||
}
|
||||
this.hostApp.closeWindow()
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
emitReady () {
|
||||
this.ready.next(null)
|
||||
this.ready.complete()
|
||||
this.hostApp.emitReady()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable that fires once
|
||||
* the tab's internal "process" (see [[BaseTabProcess]]) completes
|
||||
*/
|
||||
observeTabCompletion (tab: BaseTabComponent): Observable<void> {
|
||||
if (!this.completionObservers.has(tab)) {
|
||||
let observer = new CompletionObserver(tab)
|
||||
|
@ -18,6 +18,7 @@ function isNonStructuralObjectMember (v) {
|
||||
return v instanceof Object && !(v instanceof Array) && v.__nonStructural
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
export class ConfigProxy {
|
||||
constructor (real: any, defaults: any) {
|
||||
for (let key in defaults) {
|
||||
@ -76,9 +77,21 @@ export class ConfigProxy {
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ConfigService {
|
||||
/**
|
||||
* Contains the actual config values
|
||||
*/
|
||||
store: any
|
||||
|
||||
/**
|
||||
* Whether an app restart is required due to recent changes
|
||||
*/
|
||||
restartRequested: boolean
|
||||
|
||||
/**
|
||||
* Full config file path
|
||||
*/
|
||||
path: string
|
||||
|
||||
private changed = new Subject<void>()
|
||||
private _store: any
|
||||
private defaults: any
|
||||
@ -86,6 +99,7 @@ export class ConfigService {
|
||||
|
||||
get changed$ (): Observable<void> { return this.changed }
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
@ -129,10 +143,16 @@ export class ConfigService {
|
||||
this.hostApp.broadcastConfigChange()
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads config YAML as string
|
||||
*/
|
||||
readRaw (): string {
|
||||
return yaml.safeDump(this._store)
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes config YAML as string
|
||||
*/
|
||||
writeRaw (data: string): void {
|
||||
this._store = yaml.safeLoad(data)
|
||||
this.save()
|
||||
@ -140,7 +160,7 @@ export class ConfigService {
|
||||
this.emitChange()
|
||||
}
|
||||
|
||||
emitChange (): void {
|
||||
private emitChange (): void {
|
||||
this.changed.next()
|
||||
}
|
||||
|
||||
@ -148,6 +168,12 @@ export class ConfigService {
|
||||
this.restartRequested = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a list of Angular services to only include those provided
|
||||
* by plugins that are enabled
|
||||
*
|
||||
* @typeparam T Base provider type
|
||||
*/
|
||||
enabledServices<T> (services: T[]): T[] {
|
||||
if (!this.servicesCache) {
|
||||
this.servicesCache = {}
|
||||
|
@ -10,6 +10,7 @@ export interface IScreen {
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class DockingService {
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private electron: ElectronService,
|
||||
private config: ConfigService,
|
||||
@ -78,7 +79,7 @@ export class DockingService {
|
||||
})
|
||||
}
|
||||
|
||||
repositionWindow () {
|
||||
private repositionWindow () {
|
||||
let [x, y] = this.hostApp.getWindow().getPosition()
|
||||
for (let screen of this.electron.screen.getAllDisplays()) {
|
||||
let bounds = screen.bounds
|
||||
|
@ -24,6 +24,7 @@ export class ElectronService {
|
||||
MenuItem: typeof MenuItem
|
||||
private electron: any
|
||||
|
||||
/** @hidden */
|
||||
constructor () {
|
||||
this.electron = require('electron')
|
||||
this.remote = this.electron.remote
|
||||
@ -42,18 +43,9 @@ export class ElectronService {
|
||||
this.MenuItem = this.remote.MenuItem
|
||||
}
|
||||
|
||||
remoteRequire (name: string): any {
|
||||
return this.remote.require(name)
|
||||
}
|
||||
|
||||
remoteRequirePluginModule (plugin: string, module: string, globals: any): any {
|
||||
return this.remoteRequire(this.remoteResolvePluginModule(plugin, module, globals))
|
||||
}
|
||||
|
||||
remoteResolvePluginModule (plugin: string, module: string, globals: any): any {
|
||||
return globals.require.resolve(`${plugin}/node_modules/${module}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes OS focus from Terminus' window
|
||||
*/
|
||||
loseFocus () {
|
||||
if (process.platform === 'darwin') {
|
||||
this.remote.Menu.sendActionToFirstResponder('hide:')
|
||||
|
@ -9,6 +9,7 @@ import uuidv4 = require('uuid/v4')
|
||||
export class HomeBaseService {
|
||||
appVersion: string
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private electron: ElectronService,
|
||||
private config: ConfigService,
|
||||
|
@ -16,12 +16,19 @@ export interface Bounds {
|
||||
height: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides interaction with the main process
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HostAppService {
|
||||
platform: Platform
|
||||
nodePlatform: string
|
||||
|
||||
/**
|
||||
* Fired once the window is visible
|
||||
*/
|
||||
shown = new EventEmitter<any>()
|
||||
isFullScreen = false
|
||||
|
||||
private preferencesMenu = new Subject<void>()
|
||||
private secondInstance = new Subject<void>()
|
||||
private cliOpenDirectory = new Subject<string>()
|
||||
@ -35,29 +42,62 @@ export class HostAppService {
|
||||
private logger: Logger
|
||||
private windowId: number
|
||||
|
||||
/**
|
||||
* Fired when Preferences is selected in the macOS menu
|
||||
*/
|
||||
get preferencesMenu$ (): Observable<void> { return this.preferencesMenu }
|
||||
|
||||
/**
|
||||
* Fired when a second instance of Terminus is launched
|
||||
*/
|
||||
get secondInstance$ (): Observable<void> { return this.secondInstance }
|
||||
|
||||
/**
|
||||
* Fired for the `terminus open` CLI command
|
||||
*/
|
||||
get cliOpenDirectory$ (): Observable<string> { return this.cliOpenDirectory }
|
||||
|
||||
/**
|
||||
* Fired for the `terminus run` CLI command
|
||||
*/
|
||||
get cliRunCommand$ (): Observable<string[]> { return this.cliRunCommand }
|
||||
|
||||
/**
|
||||
* Fired for the `terminus paste` CLI command
|
||||
*/
|
||||
get cliPaste$ (): Observable<string> { return this.cliPaste }
|
||||
|
||||
/**
|
||||
* Fired for the `terminus profile` CLI command
|
||||
*/
|
||||
get cliOpenProfile$ (): Observable<string> { return this.cliOpenProfile }
|
||||
|
||||
/**
|
||||
* Fired when another window modified the config file
|
||||
*/
|
||||
get configChangeBroadcast$ (): Observable<void> { return this.configChangeBroadcast }
|
||||
|
||||
/**
|
||||
* Fired when the window close button is pressed
|
||||
*/
|
||||
get windowCloseRequest$ (): Observable<void> { return this.windowCloseRequest }
|
||||
|
||||
get windowMoved$ (): Observable<void> { return this.windowMoved }
|
||||
|
||||
get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private zone: NgZone,
|
||||
private electron: ElectronService,
|
||||
log: LogService,
|
||||
) {
|
||||
this.logger = log.create('hostApp')
|
||||
this.nodePlatform = require('os').platform()
|
||||
this.platform = {
|
||||
win32: Platform.Windows,
|
||||
darwin: Platform.macOS,
|
||||
linux: Platform.Linux
|
||||
}[this.nodePlatform]
|
||||
}[process.platform]
|
||||
|
||||
this.windowId = parseInt(location.search.substring(1))
|
||||
this.logger.info('Window ID:', this.windowId)
|
||||
@ -117,6 +157,9 @@ export class HostAppService {
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current remote [[BrowserWindow]]
|
||||
*/
|
||||
getWindow () {
|
||||
return this.electron.BrowserWindow.fromId(this.windowId)
|
||||
}
|
||||
@ -125,18 +168,6 @@ export class HostAppService {
|
||||
this.electron.ipcRenderer.send('app:new-window')
|
||||
}
|
||||
|
||||
getShell () {
|
||||
return this.electron.shell
|
||||
}
|
||||
|
||||
getAppPath () {
|
||||
return this.electron.app.getAppPath()
|
||||
}
|
||||
|
||||
getPath (type: string) {
|
||||
return this.electron.app.getPath(type)
|
||||
}
|
||||
|
||||
toggleFullscreen () {
|
||||
let window = this.getWindow()
|
||||
window.setFullScreen(!this.isFullScreen)
|
||||
@ -174,6 +205,11 @@ export class HostAppService {
|
||||
this.electron.ipcRenderer.send('window-set-always-on-top', flag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets window vibrancy mode (Windows, macOS)
|
||||
*
|
||||
* @param type `null`, or `fluent` when supported (Windowd only)
|
||||
*/
|
||||
setVibrancy (enable: boolean, type: string) {
|
||||
document.body.classList.toggle('vibrant', enable)
|
||||
if (this.platform === Platform.macOS) {
|
||||
@ -196,6 +232,9 @@ export class HostAppService {
|
||||
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies other windows of config file changes
|
||||
*/
|
||||
broadcastConfigChange () {
|
||||
this.electron.ipcRenderer.send('app:config-change')
|
||||
}
|
||||
|
@ -5,16 +5,16 @@ import { ConfigService } from '../services/config.service'
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
|
||||
export interface PartialHotkeyMatch {
|
||||
id: string,
|
||||
strokes: string[],
|
||||
matchedLength: number,
|
||||
id: string
|
||||
strokes: string[]
|
||||
matchedLength: number
|
||||
}
|
||||
|
||||
const KEY_TIMEOUT = 2000
|
||||
|
||||
interface EventBufferEntry {
|
||||
event: NativeKeyEvent,
|
||||
time: number,
|
||||
event: NativeKeyEvent
|
||||
time: number
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@ -26,6 +26,7 @@ export class HotkeysService {
|
||||
private disabledLevel = 0
|
||||
private hotkeyDescriptions: IHotkeyDescription[] = []
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private zone: NgZone,
|
||||
private electron: ElectronService,
|
||||
@ -51,11 +52,20 @@ export class HotkeysService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new key event to the buffer
|
||||
*
|
||||
* @param name DOM event name
|
||||
* @param nativeEvent event object
|
||||
*/
|
||||
pushKeystroke (name, nativeEvent) {
|
||||
nativeEvent.event = name
|
||||
this.currentKeystrokes.push({ event: nativeEvent, time: performance.now() })
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the buffer for new complete keystrokes
|
||||
*/
|
||||
processKeystrokes () {
|
||||
if (this.isEnabled()) {
|
||||
this.zone.run(() => {
|
||||
@ -84,7 +94,7 @@ export class HotkeysService {
|
||||
return stringifyKeySequence(this.currentKeystrokes.map(x => x.event))
|
||||
}
|
||||
|
||||
registerGlobalHotkey () {
|
||||
private registerGlobalHotkey () {
|
||||
this.electron.globalShortcut.unregisterAll()
|
||||
let value = this.config.store.hotkeys['toggle-window'] || []
|
||||
if (typeof value === 'string') {
|
||||
@ -103,11 +113,11 @@ export class HotkeysService {
|
||||
})
|
||||
}
|
||||
|
||||
getHotkeysConfig () {
|
||||
private getHotkeysConfig () {
|
||||
return this.getHotkeysConfigRecursive(this.config.store.hotkeys)
|
||||
}
|
||||
|
||||
getHotkeysConfigRecursive (branch) {
|
||||
private getHotkeysConfigRecursive (branch) {
|
||||
let keys = {}
|
||||
for (let key in branch) {
|
||||
let value = branch[key]
|
||||
@ -129,7 +139,7 @@ export class HotkeysService {
|
||||
return keys
|
||||
}
|
||||
|
||||
getCurrentFullyMatchedHotkey (): string {
|
||||
private getCurrentFullyMatchedHotkey (): string {
|
||||
let currentStrokes = this.getCurrentKeystrokes()
|
||||
let config = this.getHotkeysConfig()
|
||||
for (let id in config) {
|
||||
@ -199,117 +209,3 @@ export class HotkeysService {
|
||||
).reduce((a, b) => a.concat(b))
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AppHotkeyProvider extends HotkeyProvider {
|
||||
hotkeys: IHotkeyDescription[] = [
|
||||
{
|
||||
id: 'new-window',
|
||||
name: 'New window',
|
||||
},
|
||||
{
|
||||
id: 'toggle-window',
|
||||
name: 'Toggle terminal window',
|
||||
},
|
||||
{
|
||||
id: 'toggle-fullscreen',
|
||||
name: 'Toggle fullscreen mode',
|
||||
},
|
||||
{
|
||||
id: 'rename-tab',
|
||||
name: 'Rename Tab',
|
||||
},
|
||||
{
|
||||
id: 'close-tab',
|
||||
name: 'Close tab',
|
||||
},
|
||||
{
|
||||
id: 'toggle-last-tab',
|
||||
name: 'Toggle last tab',
|
||||
},
|
||||
{
|
||||
id: 'next-tab',
|
||||
name: 'Next tab',
|
||||
},
|
||||
{
|
||||
id: 'previous-tab',
|
||||
name: 'Previous tab',
|
||||
},
|
||||
{
|
||||
id: 'tab-1',
|
||||
name: 'Tab 1',
|
||||
},
|
||||
{
|
||||
id: 'tab-2',
|
||||
name: 'Tab 2',
|
||||
},
|
||||
{
|
||||
id: 'tab-3',
|
||||
name: 'Tab 3',
|
||||
},
|
||||
{
|
||||
id: 'tab-4',
|
||||
name: 'Tab 4',
|
||||
},
|
||||
{
|
||||
id: 'tab-5',
|
||||
name: 'Tab 5',
|
||||
},
|
||||
{
|
||||
id: 'tab-6',
|
||||
name: 'Tab 6',
|
||||
},
|
||||
{
|
||||
id: 'tab-7',
|
||||
name: 'Tab 7',
|
||||
},
|
||||
{
|
||||
id: 'tab-8',
|
||||
name: 'Tab 8',
|
||||
},
|
||||
{
|
||||
id: 'tab-9',
|
||||
name: 'Tab 9',
|
||||
},
|
||||
{
|
||||
id: 'tab-10',
|
||||
name: 'Tab 10',
|
||||
},
|
||||
{
|
||||
id: 'split-right',
|
||||
name: 'Split to the right',
|
||||
},
|
||||
{
|
||||
id: 'split-bottom',
|
||||
name: 'Split to the bottom',
|
||||
},
|
||||
{
|
||||
id: 'split-left',
|
||||
name: 'Split to the left',
|
||||
},
|
||||
{
|
||||
id: 'split-top',
|
||||
name: 'Split to the top',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-up',
|
||||
name: 'Focus the pane above',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-down',
|
||||
name: 'Focus the pane below',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-left',
|
||||
name: 'Focus the pane on the left',
|
||||
},
|
||||
{
|
||||
id: 'split-nav-right',
|
||||
name: 'Focus the pane on the right',
|
||||
},
|
||||
]
|
||||
|
||||
async provide (): Promise<IHotkeyDescription[]> {
|
||||
return this.hotkeys
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ export const altKeyName = {
|
||||
}[process.platform]
|
||||
|
||||
export interface NativeKeyEvent {
|
||||
event?: string,
|
||||
altKey: boolean,
|
||||
ctrlKey: boolean,
|
||||
metaKey: boolean,
|
||||
shiftKey: boolean,
|
||||
key: string,
|
||||
keyCode: string,
|
||||
event?: string
|
||||
altKey: boolean
|
||||
ctrlKey: boolean
|
||||
metaKey: boolean
|
||||
shiftKey: boolean
|
||||
key: string
|
||||
keyCode: string
|
||||
}
|
||||
|
||||
export function stringifyKeySequence (events: NativeKeyEvent[]): string[] {
|
||||
|
@ -39,7 +39,7 @@ export class Logger {
|
||||
private name: string,
|
||||
) {}
|
||||
|
||||
doLog (level: string, ...args: any[]) {
|
||||
private doLog (level: string, ...args: any[]) {
|
||||
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
|
||||
if (this.winstonLogger) {
|
||||
this.winstonLogger[level](...args)
|
||||
@ -57,6 +57,7 @@ export class Logger {
|
||||
export class LogService {
|
||||
private log: any
|
||||
|
||||
/** @hidden */
|
||||
constructor (electron: ElectronService) {
|
||||
this.log = initializeWinston(electron)
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ export class ShellIntegrationService {
|
||||
this.updatePaths()
|
||||
}
|
||||
|
||||
async updatePaths (): Promise<void> {
|
||||
private async updatePaths (): Promise<void> {
|
||||
// Update paths in case of an update
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
if (await this.isInstalled()) {
|
||||
|
@ -4,6 +4,7 @@ import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { Logger, LogService } from '../services/log.service'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TabRecoveryService {
|
||||
logger: Logger
|
||||
|
@ -6,12 +6,16 @@ export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TabsService {
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
private tabRecovery: TabRecoveryService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Instantiates a tab component and assigns given inputs
|
||||
*/
|
||||
create (type: TabComponentType, inputs?: any): BaseTabComponent {
|
||||
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(type)
|
||||
let componentRef = componentFactory.create(this.injector)
|
||||
@ -21,6 +25,9 @@ export class TabsService {
|
||||
return tab
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an existing tab instance (using the tab recovery system)
|
||||
*/
|
||||
async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent> {
|
||||
let token = await tab.getRecoveryToken()
|
||||
if (!token) {
|
||||
@ -32,5 +39,4 @@ export class TabsService {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { Theme } from '../api/theme'
|
||||
export class ThemesService {
|
||||
private styleElement: HTMLElement = null
|
||||
|
||||
/** @hidden */
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
@Inject(Theme) private themes: Theme[],
|
||||
@ -34,7 +35,7 @@ export class ThemesService {
|
||||
document.querySelector('style#custom-css').innerHTML = this.config.store.appearance.css
|
||||
}
|
||||
|
||||
applyCurrentTheme (): void {
|
||||
private applyCurrentTheme (): void {
|
||||
this.applyTheme(this.findCurrentTheme())
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { ElectronService } from './electron.service'
|
||||
import { HostAppService, Platform } from './hostApp.service'
|
||||
import { IToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TouchbarService {
|
||||
private tabsSegmentedControl: TouchBarSegmentedControl
|
||||
|
@ -6,6 +6,7 @@ import { ElectronService } from './electron.service'
|
||||
|
||||
const UPDATES_URL = 'https://api.github.com/repos/eugeny/terminus/releases/latest'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class UpdaterService {
|
||||
private logger: Logger
|
||||
|
@ -4,6 +4,7 @@ import { BaseTabComponent } from './components/baseTab.component'
|
||||
import { TabHeaderComponent } from './components/tabHeader.component'
|
||||
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CloseContextMenu extends TabContextMenuItemProvider {
|
||||
weight = -5
|
||||
@ -61,6 +62,7 @@ const COLORS = [
|
||||
{ name: 'Yellow', value: '#ffd500' },
|
||||
]
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
weight = -1
|
||||
@ -98,6 +100,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
constructor (
|
||||
@ -121,7 +124,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
type: 'checkbox',
|
||||
checked: (tab as any).__completionNotificationEnabled,
|
||||
click: () => this.zone.run(() => {
|
||||
;(tab as any).__completionNotificationEnabled = !(tab as any).__completionNotificationEnabled
|
||||
(tab as any).__completionNotificationEnabled = !(tab as any).__completionNotificationEnabled
|
||||
|
||||
if ((tab as any).__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Theme } from './api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class StandardTheme extends Theme {
|
||||
name = 'Standard'
|
||||
@ -8,6 +9,7 @@ export class StandardTheme extends Theme {
|
||||
terminalBackground = '#222a33'
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class StandardCompactTheme extends Theme {
|
||||
name = 'Compact'
|
||||
@ -15,6 +17,7 @@ export class StandardCompactTheme extends Theme {
|
||||
terminalBackground = '#222a33'
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class PaperTheme extends Theme {
|
||||
name = 'Paper'
|
||||
|
@ -3,7 +3,7 @@ import { debounceTime, distinctUntilChanged, first, tap, flatMap } from 'rxjs/op
|
||||
import * as semver from 'semver'
|
||||
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { ConfigService, HostAppService, ElectronService } from 'terminus-core'
|
||||
import { ConfigService, ElectronService } from 'terminus-core'
|
||||
import { IPluginInfo, PluginManagerService } from '../services/pluginManager.service'
|
||||
|
||||
enum BusyState { Installing, Uninstalling }
|
||||
@ -25,7 +25,6 @@ export class PluginsSettingsTabComponent {
|
||||
constructor (
|
||||
private electron: ElectronService,
|
||||
private config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
public pluginManager: PluginManagerService
|
||||
) {
|
||||
}
|
||||
@ -51,7 +50,7 @@ export class PluginsSettingsTabComponent {
|
||||
}
|
||||
|
||||
openPluginsFolder (): void {
|
||||
this.hostApp.getShell().openItem(this.pluginManager.userPluginsPath)
|
||||
this.electron.shell.openItem(this.pluginManager.userPluginsPath)
|
||||
}
|
||||
|
||||
searchAvailable (query: string) {
|
||||
|
7
typedoc.js
Normal file
7
typedoc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
ignoreCompilerErrors: true,
|
||||
excludeNotExported: true,
|
||||
excludePrivate: true,
|
||||
excludeExternals: true,
|
||||
mode: 'file'
|
||||
}
|
159
yarn.lock
159
yarn.lock
@ -39,6 +39,18 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/electron-debug/-/electron-debug-1.1.0.tgz#b9203bad33dccc5a4ea180a89a9dbcf1961f4c3c"
|
||||
integrity sha1-uSA7rTPczFpOoYComp288ZYfTDw=
|
||||
|
||||
"@types/events@*":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
||||
|
||||
"@types/fs-extra@^5.0.3":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.5.tgz#080d90a792f3fa2c5559eb44bd8ef840aae9104b"
|
||||
integrity sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/fs-promise@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-promise/-/fs-promise-1.0.1.tgz#a77e18c055d7757d44a34c1ed7e8bb505992f783"
|
||||
@ -47,11 +59,47 @@
|
||||
"@types/mz" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@*":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||
integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
|
||||
dependencies:
|
||||
"@types/events" "*"
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/handlebars@^4.0.38":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.1.0.tgz#3fcce9bf88f85fe73dc932240ab3fb682c624850"
|
||||
integrity sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==
|
||||
dependencies:
|
||||
handlebars "*"
|
||||
|
||||
"@types/highlight.js@^9.12.3":
|
||||
version "9.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca"
|
||||
integrity sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==
|
||||
|
||||
"@types/js-yaml@^3.11.2":
|
||||
version "3.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.11.2.tgz#699ad86054cc20043c30d66a6fcde30bbf5d3d5e"
|
||||
integrity sha512-JRDtMPEqXrzfuYAdqbxLot1GvAr/QvicIZAnOAigZaj8xVMhuSJTg/xsv9E1TvyL+wujYhRLx9ZsQ0oFOSmwyA==
|
||||
|
||||
"@types/lodash@^4.14.110":
|
||||
version "4.14.122"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.122.tgz#3e31394c38cf1e5949fb54c1192cbc406f152c6c"
|
||||
integrity sha512-9IdED8wU93ty8gP06ninox+42SBSJHp2IAamsSYMUY76mshRTeUsid/gtbl8ovnOwy8im41ib4cxTiIYMXGKew==
|
||||
|
||||
"@types/marked@^0.4.0":
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.4.2.tgz#64a89e53ea37f61cc0f3ee1732c555c2dbf6452f"
|
||||
integrity sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==
|
||||
|
||||
"@types/minimatch@*", "@types/minimatch@3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||
|
||||
"@types/mz@*":
|
||||
version "0.0.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.32.tgz#e8248b4e41424c052edc1725dd33650c313a3659"
|
||||
@ -69,6 +117,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.26.tgz#2dec19f1f7981c95cb54bab8f618ecb5dc983d0e"
|
||||
integrity sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg==
|
||||
|
||||
"@types/shelljs@^0.8.0":
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.3.tgz#f713f312dbae49ab5025290007e71ea32998e9a9"
|
||||
integrity sha512-miY41hqc5SkRlsZDod3heDa4OS9xv8G77EMBQuSpqq86HBn66l7F+f8y9YKm+1PIuwC8QEZVwN8YxOOG7Y67fA==
|
||||
dependencies:
|
||||
"@types/glob" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/webpack-env@1.13.0":
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.0.tgz#3044381647e11ee973c5af2e925323930f691d80"
|
||||
@ -649,6 +705,13 @@ async@^2.0.0:
|
||||
dependencies:
|
||||
lodash "^4.17.10"
|
||||
|
||||
async@^2.5.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
|
||||
integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
|
||||
dependencies:
|
||||
lodash "^4.17.11"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
@ -3051,6 +3114,17 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||
|
||||
handlebars@*, handlebars@^4.0.6:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a"
|
||||
integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==
|
||||
dependencies:
|
||||
async "^2.5.0"
|
||||
optimist "^0.6.1"
|
||||
source-map "^0.6.1"
|
||||
optionalDependencies:
|
||||
uglify-js "^3.1.4"
|
||||
|
||||
har-schema@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
|
||||
@ -3181,6 +3255,11 @@ he@1.1.x:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
|
||||
|
||||
highlight.js@^9.13.1:
|
||||
version "9.15.6"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.6.tgz#72d4d8d779ec066af9a17cb14360c3def0aa57c4"
|
||||
integrity sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
@ -4135,7 +4214,7 @@ lodash.without@~4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
|
||||
integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
|
||||
|
||||
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
|
||||
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
@ -4242,6 +4321,11 @@ map-visit@^1.0.0:
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
marked@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.4.0.tgz#9ad2c2a7a1791f10a852e0112f77b571dce10c66"
|
||||
integrity sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==
|
||||
|
||||
math-expression-evaluator@^1.2.14:
|
||||
version "1.2.17"
|
||||
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
|
||||
@ -4388,6 +4472,11 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
|
||||
resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minimist@~0.0.1:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
|
||||
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
|
||||
|
||||
minipass@^2.2.1, minipass@^2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957"
|
||||
@ -5066,6 +5155,14 @@ opener@~1.4.3:
|
||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
||||
integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
|
||||
|
||||
optimist@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
|
||||
dependencies:
|
||||
minimist "~0.0.1"
|
||||
wordwrap "~0.0.2"
|
||||
|
||||
ora@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-1.4.0.tgz#884458215b3a5d4097592285f93321bb7a79e2e5"
|
||||
@ -5709,6 +5806,11 @@ progress-stream@^1.1.0:
|
||||
speedometer "~0.1.2"
|
||||
through2 "~0.2.3"
|
||||
|
||||
progress@^2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
||||
|
||||
promise-inflight@^1.0.1, promise-inflight@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
|
||||
@ -6671,6 +6773,15 @@ shelljs@0.7.7:
|
||||
interpret "^1.0.0"
|
||||
rechoir "^0.6.2"
|
||||
|
||||
shelljs@^0.8.2:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
|
||||
integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
interpret "^1.0.0"
|
||||
rechoir "^0.6.2"
|
||||
|
||||
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
@ -7472,6 +7583,39 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typedoc-default-themes@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz#6dc2433e78ed8bea8e887a3acde2f31785bd6227"
|
||||
integrity sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=
|
||||
|
||||
typedoc@^0.14.2:
|
||||
version "0.14.2"
|
||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.14.2.tgz#769f457f4f9e4bdb8b5f3b177c86b6a31d8c3dc3"
|
||||
integrity sha512-aEbgJXV8/KqaVhcedT7xG6d2r+mOvB5ep3eIz1KuB5sc4fDYXcepEEMdU7XSqLFO5hVPu0nllHi1QxX2h/QlpQ==
|
||||
dependencies:
|
||||
"@types/fs-extra" "^5.0.3"
|
||||
"@types/handlebars" "^4.0.38"
|
||||
"@types/highlight.js" "^9.12.3"
|
||||
"@types/lodash" "^4.14.110"
|
||||
"@types/marked" "^0.4.0"
|
||||
"@types/minimatch" "3.0.3"
|
||||
"@types/shelljs" "^0.8.0"
|
||||
fs-extra "^7.0.0"
|
||||
handlebars "^4.0.6"
|
||||
highlight.js "^9.13.1"
|
||||
lodash "^4.17.10"
|
||||
marked "^0.4.0"
|
||||
minimatch "^3.0.0"
|
||||
progress "^2.0.0"
|
||||
shelljs "^0.8.2"
|
||||
typedoc-default-themes "^0.5.0"
|
||||
typescript "3.2.x"
|
||||
|
||||
typescript@3.2.x:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
|
||||
integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
|
||||
|
||||
typescript@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5"
|
||||
@ -7495,6 +7639,14 @@ uglify-js@^2.6.1:
|
||||
optionalDependencies:
|
||||
uglify-to-browserify "~1.0.0"
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.4.9"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
||||
integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==
|
||||
dependencies:
|
||||
commander "~2.17.1"
|
||||
source-map "~0.6.1"
|
||||
|
||||
uglify-to-browserify@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
|
||||
@ -7881,6 +8033,11 @@ wordwrap@0.0.2:
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
|
||||
integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
|
||||
|
||||
wordwrap@~0.0.2:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
|
||||
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
|
||||
|
||||
worker-farm@^1.5.2:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
|
||||
|
Loading…
Reference in New Issue
Block a user