Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
Tabby
提交
5b78a5c1
T
Tabby
项目概览
后端镜像
/
Tabby
通知
41
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
Tabby
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
5b78a5c1
编写于
1月 07, 2019
作者:
E
Eugene Pankov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
made tab context menu extensible
上级
91b31885
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
212 addition
and
121 deletion
+212
-121
terminus-core/src/api/index.ts
terminus-core/src/api/index.ts
+1
-0
terminus-core/src/api/tabContextMenuProvider.ts
terminus-core/src/api/tabContextMenuProvider.ts
+8
-0
terminus-core/src/components/tabHeader.component.ts
terminus-core/src/components/tabHeader.component.ts
+14
-104
terminus-core/src/index.ts
terminus-core/src/index.ts
+5
-0
terminus-core/src/tabContextMenu.ts
terminus-core/src/tabContextMenu.ts
+139
-0
terminus-terminal/src/components/terminalTab.component.ts
terminus-terminal/src/components/terminalTab.component.ts
+0
-16
terminus-terminal/src/index.ts
terminus-terminal/src/index.ts
+4
-1
terminus-terminal/src/tabContextMenu.ts
terminus-terminal/src/tabContextMenu.ts
+41
-0
未找到文件。
terminus-core/src/api/index.ts
浏览文件 @
5b78a5c1
...
...
@@ -4,6 +4,7 @@ export { ToolbarButtonProvider, IToolbarButton } from './toolbarButtonProvider'
export
{
ConfigProvider
}
from
'
./configProvider
'
export
{
HotkeyProvider
,
IHotkeyDescription
}
from
'
./hotkeyProvider
'
export
{
Theme
}
from
'
./theme
'
export
{
TabContextMenuItemProvider
}
from
'
./tabContextMenuProvider
'
export
{
AppService
}
from
'
../services/app.service
'
export
{
ConfigService
}
from
'
../services/config.service
'
...
...
terminus-core/src/api/tabContextMenuProvider.ts
0 → 100644
浏览文件 @
5b78a5c1
import
{
BaseTabComponent
}
from
'
../components/baseTab.component
'
import
{
TabHeaderComponent
}
from
'
../components/tabHeader.component
'
export
abstract
class
TabContextMenuItemProvider
{
weight
=
0
abstract
async
getItems
(
tab
:
BaseTabComponent
,
tabHeader
?:
TabHeaderComponent
):
Promise
<
Electron
.
MenuItemConstructorOptions
[]
>
}
terminus-core/src/components/tabHeader.component.ts
浏览文件 @
5b78a5c1
import
{
Component
,
Input
,
HostBinding
,
HostListener
,
NgZone
,
ViewChild
,
ElementRef
}
from
'
@angular/core
'
import
{
Component
,
Input
,
Optional
,
Inject
,
HostBinding
,
HostListener
,
ViewChild
,
ElementRef
}
from
'
@angular/core
'
import
{
SortableComponent
}
from
'
ng2-dnd
'
import
{
NgbModal
}
from
'
@ng-bootstrap/ng-bootstrap
'
import
{
TabContextMenuItemProvider
}
from
'
../api/tabContextMenuProvider
'
import
{
BaseTabComponent
}
from
'
./baseTab.component
'
import
{
RenameTabModalComponent
}
from
'
./renameTabModal.component
'
import
{
HotkeysService
}
from
'
../services/hotkeys.service
'
...
...
@@ -8,16 +9,6 @@ import { ElectronService } from '../services/electron.service'
import
{
AppService
}
from
'
../services/app.service
'
import
{
HostAppService
,
Platform
}
from
'
../services/hostApp.service
'
const
COLORS
=
[
{
name
:
'
No color
'
,
value
:
null
},
{
name
:
'
Blue
'
,
value
:
'
#0275d8
'
},
{
name
:
'
Green
'
,
value
:
'
#5cb85c
'
},
{
name
:
'
Orange
'
,
value
:
'
#f0ad4e
'
},
{
name
:
'
Purple
'
,
value
:
'
#613d7c
'
},
{
name
:
'
Red
'
,
value
:
'
#d9534f
'
},
{
name
:
'
Yellow
'
,
value
:
'
#ffd500
'
},
]
@
Component
({
selector
:
'
tab-header
'
,
template
:
require
(
'
./tabHeader.component.pug
'
),
...
...
@@ -31,16 +22,14 @@ export class TabHeaderComponent {
@
Input
()
progress
:
number
@
ViewChild
(
'
handle
'
)
handle
:
ElementRef
private
completionNotificationEnabled
=
false
constructor
(
public
app
:
AppService
,
private
electron
:
ElectronService
,
private
zone
:
NgZone
,
private
hostApp
:
HostAppService
,
private
ngbModal
:
NgbModal
,
private
hotkeys
:
HotkeysService
,
private
parentDraggable
:
SortableComponent
,
@
Optional
()
@
Inject
(
TabContextMenuItemProvider
)
protected
contextMenuProviders
:
TabContextMenuItemProvider
[],
)
{
this
.
hotkeys
.
matchedHotkey
.
subscribe
((
hotkey
)
=>
{
if
(
this
.
app
.
activeTab
===
this
.
tab
)
{
...
...
@@ -49,6 +38,7 @@ export class TabHeaderComponent {
}
}
})
this
.
contextMenuProviders
.
sort
((
a
,
b
)
=>
a
.
weight
-
b
.
weight
)
}
ngOnInit
()
{
...
...
@@ -69,6 +59,15 @@ export class TabHeaderComponent {
}).
catch
(()
=>
null
)
}
async
buildContextMenu
():
Promise
<
Electron
.
MenuItemConstructorOptions
[]
>
{
let
items
:
Electron
.
MenuItemConstructorOptions
[]
=
[]
for
(
let
section
of
await
Promise
.
all
(
this
.
contextMenuProviders
.
map
(
x
=>
x
.
getItems
(
this
.
tab
,
this
))))
{
items
.
push
({
type
:
'
separator
'
})
items
=
items
.
concat
(
section
)
}
return
items
.
slice
(
1
)
}
@
HostListener
(
'
dblclick
'
)
onDoubleClick
():
void
{
this
.
showRenameTabModal
()
}
...
...
@@ -80,96 +79,7 @@ export class TabHeaderComponent {
if
(
$event
.
which
===
3
)
{
event
.
preventDefault
()
let
contextMenu
=
this
.
electron
.
remote
.
Menu
.
buildFromTemplate
([
{
label
:
'
Close
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
this
.
app
.
closeTab
(
this
.
tab
,
true
)
})
},
{
label
:
'
Close other tabs
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
for
(
let
tab
of
this
.
app
.
tabs
.
filter
(
x
=>
x
!==
this
.
tab
))
{
this
.
app
.
closeTab
(
tab
,
true
)
}
})
},
{
label
:
'
Close tabs to the right
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
for
(
let
tab
of
this
.
app
.
tabs
.
slice
(
this
.
app
.
tabs
.
indexOf
(
this
.
tab
)
+
1
))
{
this
.
app
.
closeTab
(
tab
,
true
)
}
})
},
{
label
:
'
Close tabs to the left
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
for
(
let
tab
of
this
.
app
.
tabs
.
slice
(
0
,
this
.
app
.
tabs
.
indexOf
(
this
.
tab
)))
{
this
.
app
.
closeTab
(
tab
,
true
)
}
})
},
{
label
:
'
Rename
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
this
.
showRenameTabModal
())
},
{
label
:
'
Color
'
,
sublabel
:
COLORS
.
find
(
x
=>
x
.
value
===
this
.
tab
.
color
).
name
,
submenu
:
COLORS
.
map
(
color
=>
({
label
:
color
.
name
,
type
:
'
radio
'
,
checked
:
this
.
tab
.
color
===
color
.
value
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
this
.
tab
.
color
=
color
.
value
}),
})),
}
])
if
((
this
.
tab
as
any
).
saveAsProfile
)
{
contextMenu
.
append
(
new
this
.
electron
.
MenuItem
({
label
:
'
Save as a profile
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
(
this
.
tab
as
any
).
saveAsProfile
())
}))
}
let
process
=
await
this
.
tab
.
getCurrentProcess
()
if
(
process
)
{
contextMenu
.
append
(
new
this
.
electron
.
MenuItem
({
id
:
'
sep
'
,
type
:
'
separator
'
,
}))
contextMenu
.
append
(
new
this
.
electron
.
MenuItem
({
id
:
'
process-name
'
,
enabled
:
false
,
label
:
'
Current process:
'
+
process
.
name
,
}))
contextMenu
.
append
(
new
this
.
electron
.
MenuItem
({
id
:
'
completion
'
,
label
:
'
Notify when done
'
,
type
:
'
checkbox
'
,
checked
:
this
.
completionNotificationEnabled
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
this
.
completionNotificationEnabled
=
!
this
.
completionNotificationEnabled
if
(
this
.
completionNotificationEnabled
)
{
this
.
app
.
observeTabCompletion
(
this
.
tab
).
subscribe
(()
=>
{
new
Notification
(
'
Process completed
'
,
{
body
:
process
.
name
,
}).
addEventListener
(
'
click
'
,
()
=>
{
this
.
app
.
selectTab
(
this
.
tab
)
})
this
.
completionNotificationEnabled
=
false
})
}
else
{
this
.
app
.
stopObservingTabCompletion
(
this
.
tab
)
}
})
}))
}
const
contextMenu
=
this
.
electron
.
remote
.
Menu
.
buildFromTemplate
(
await
this
.
buildContextMenu
())
contextMenu
.
popup
({
x
:
$event
.
pageX
,
...
...
terminus-core/src/index.ts
浏览文件 @
5b78a5c1
...
...
@@ -24,9 +24,11 @@ import { AutofocusDirective } from './directives/autofocus.directive'
import
{
HotkeyProvider
}
from
'
./api/hotkeyProvider
'
import
{
ConfigProvider
}
from
'
./api/configProvider
'
import
{
Theme
}
from
'
./api/theme
'
import
{
TabContextMenuItemProvider
}
from
'
./api/tabContextMenuProvider
'
import
{
StandardTheme
,
StandardCompactTheme
,
PaperTheme
}
from
'
./theme
'
import
{
CoreConfigProvider
}
from
'
./config
'
import
{
TaskCompletionContextMenu
,
CommonOptionsContextMenu
,
CloseContextMenu
}
from
'
./tabContextMenu
'
import
'
perfect-scrollbar/css/perfect-scrollbar.css
'
import
'
ng2-dnd/bundles/style.css
'
...
...
@@ -37,6 +39,9 @@ const PROVIDERS = [
{
provide
:
Theme
,
useClass
:
StandardCompactTheme
,
multi
:
true
},
{
provide
:
Theme
,
useClass
:
PaperTheme
,
multi
:
true
},
{
provide
:
ConfigProvider
,
useClass
:
CoreConfigProvider
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
CommonOptionsContextMenu
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
CloseContextMenu
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
TaskCompletionContextMenu
,
multi
:
true
},
{
provide
:
PERFECT_SCROLLBAR_CONFIG
,
useValue
:
{
suppressScrollX
:
true
}
}
]
...
...
terminus-core/src/tabContextMenu.ts
0 → 100644
浏览文件 @
5b78a5c1
import
{
Injectable
,
NgZone
}
from
'
@angular/core
'
import
{
AppService
}
from
'
./services/app.service
'
import
{
BaseTabComponent
}
from
'
./components/baseTab.component
'
import
{
TabHeaderComponent
}
from
'
./components/tabHeader.component
'
import
{
TabContextMenuItemProvider
}
from
'
./api/tabContextMenuProvider
'
@
Injectable
()
export
class
CloseContextMenu
extends
TabContextMenuItemProvider
{
weight
=
-
5
constructor
(
private
app
:
AppService
,
private
zone
:
NgZone
,
)
{
super
()
}
async
getItems
(
tab
:
BaseTabComponent
):
Promise
<
Electron
.
MenuItemConstructorOptions
[]
>
{
return
[
{
label
:
'
Close
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
this
.
app
.
closeTab
(
tab
,
true
)
})
},
{
label
:
'
Close other tabs
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
for
(
let
t
of
this
.
app
.
tabs
.
filter
(
x
=>
x
!==
tab
))
{
this
.
app
.
closeTab
(
t
,
true
)
}
})
},
{
label
:
'
Close tabs to the right
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
for
(
let
t
of
this
.
app
.
tabs
.
slice
(
this
.
app
.
tabs
.
indexOf
(
tab
)
+
1
))
{
this
.
app
.
closeTab
(
t
,
true
)
}
})
},
{
label
:
'
Close tabs to the left
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
for
(
let
t
of
this
.
app
.
tabs
.
slice
(
0
,
this
.
app
.
tabs
.
indexOf
(
tab
)))
{
this
.
app
.
closeTab
(
t
,
true
)
}
})
},
]
}
}
const
COLORS
=
[
{
name
:
'
No color
'
,
value
:
null
},
{
name
:
'
Blue
'
,
value
:
'
#0275d8
'
},
{
name
:
'
Green
'
,
value
:
'
#5cb85c
'
},
{
name
:
'
Orange
'
,
value
:
'
#f0ad4e
'
},
{
name
:
'
Purple
'
,
value
:
'
#613d7c
'
},
{
name
:
'
Red
'
,
value
:
'
#d9534f
'
},
{
name
:
'
Yellow
'
,
value
:
'
#ffd500
'
},
]
@
Injectable
()
export
class
CommonOptionsContextMenu
extends
TabContextMenuItemProvider
{
weight
=
-
1
constructor
(
private
zone
:
NgZone
,
)
{
super
()
}
async
getItems
(
tab
:
BaseTabComponent
,
tabHeader
?:
TabHeaderComponent
):
Promise
<
Electron
.
MenuItemConstructorOptions
[]
>
{
return
[
{
label
:
'
Rename
'
,
click
:
()
=>
this
.
zone
.
run
(()
=>
tabHeader
.
showRenameTabModal
())
},
{
label
:
'
Color
'
,
sublabel
:
COLORS
.
find
(
x
=>
x
.
value
===
tab
.
color
).
name
,
submenu
:
COLORS
.
map
(
color
=>
({
label
:
color
.
name
,
type
:
'
radio
'
,
checked
:
tab
.
color
===
color
.
value
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
tab
.
color
=
color
.
value
}),
}))
as
Electron
.
MenuItemConstructorOptions
[],
}
]
}
}
@
Injectable
()
export
class
TaskCompletionContextMenu
extends
TabContextMenuItemProvider
{
constructor
(
private
app
:
AppService
,
private
zone
:
NgZone
,
)
{
super
()
}
async
getItems
(
tab
:
BaseTabComponent
):
Promise
<
Electron
.
MenuItemConstructorOptions
[]
>
{
let
process
=
await
tab
.
getCurrentProcess
()
if
(
process
)
{
return
[
{
id
:
'
process-name
'
,
enabled
:
false
,
label
:
'
Current process:
'
+
process
.
name
,
},
{
label
:
'
Notify when done
'
,
type
:
'
checkbox
'
,
checked
:
(
tab
as
any
).
__completionNotificationEnabled
,
click
:
()
=>
this
.
zone
.
run
(()
=>
{
;(
tab
as
any
).
__completionNotificationEnabled
=
!
(
tab
as
any
).
__completionNotificationEnabled
if
((
tab
as
any
).
__completionNotificationEnabled
)
{
this
.
app
.
observeTabCompletion
(
tab
).
subscribe
(()
=>
{
new
Notification
(
'
Process completed
'
,
{
body
:
process
.
name
,
}).
addEventListener
(
'
click
'
,
()
=>
{
this
.
app
.
selectTab
(
tab
)
})
;(
tab
as
any
).
__completionNotificationEnabled
=
false
})
}
else
{
this
.
app
.
stopObservingTabCompletion
(
tab
)
}
})
},
]
}
return
[]
}
}
terminus-terminal/src/components/terminalTab.component.ts
浏览文件 @
5b78a5c1
...
...
@@ -72,20 +72,4 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
}
)).
response
===
1
}
async
saveAsProfile
()
{
let
profile
=
{
sessionOptions
:
{
...
this
.
sessionOptions
,
cwd
:
(
await
this
.
session
.
getWorkingDirectory
())
||
this
.
sessionOptions
.
cwd
,
},
name
:
this
.
sessionOptions
.
command
,
}
this
.
config
.
store
.
terminal
.
profiles
=
[
...
this
.
config
.
store
.
terminal
.
profiles
,
profile
,
]
this
.
config
.
save
()
this
.
toastr
.
info
(
'
Saved
'
)
}
}
terminus-terminal/src/index.ts
浏览文件 @
5b78a5c1
...
...
@@ -6,7 +6,7 @@ import { FormsModule } from '@angular/forms'
import
{
NgbModule
}
from
'
@ng-bootstrap/ng-bootstrap
'
import
{
ToastrModule
}
from
'
ngx-toastr
'
import
TerminusCorePlugin
,
{
HostAppService
,
ToolbarButtonProvider
,
TabRecoveryProvider
,
ConfigProvider
,
HotkeysService
,
HotkeyProvider
,
AppService
,
ConfigService
}
from
'
terminus-core
'
import
TerminusCorePlugin
,
{
HostAppService
,
ToolbarButtonProvider
,
TabRecoveryProvider
,
ConfigProvider
,
HotkeysService
,
HotkeyProvider
,
AppService
,
ConfigService
,
TabContextMenuItemProvider
}
from
'
terminus-core
'
import
{
SettingsTabProvider
}
from
'
terminus-settings
'
import
{
AppearanceSettingsTabComponent
}
from
'
./components/appearanceSettingsTab.component
'
...
...
@@ -32,6 +32,7 @@ import { TerminalConfigProvider } from './config'
import
{
TerminalHotkeyProvider
}
from
'
./hotkeys
'
import
{
HyperColorSchemes
}
from
'
./colorSchemes
'
import
{
NewTabContextMenu
,
CopyPasteContextMenu
}
from
'
./contextMenu
'
import
{
SaveAsProfileContextMenu
}
from
'
./tabContextMenu
'
import
{
CmderShellProvider
}
from
'
./shells/cmder
'
import
{
CustomShellProvider
}
from
'
./shells/custom
'
...
...
@@ -84,6 +85,8 @@ import { hterm } from './hterm'
{
provide
:
TerminalContextMenuItemProvider
,
useClass
:
NewTabContextMenu
,
multi
:
true
},
{
provide
:
TerminalContextMenuItemProvider
,
useClass
:
CopyPasteContextMenu
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
SaveAsProfileContextMenu
,
multi
:
true
},
// For WindowsDefaultShellProvider
PowerShellCoreShellProvider
,
WSLShellProvider
,
...
...
terminus-terminal/src/tabContextMenu.ts
0 → 100644
浏览文件 @
5b78a5c1
import
{
Injectable
,
NgZone
}
from
'
@angular/core
'
import
{
ToastrService
}
from
'
ngx-toastr
'
import
{
ConfigService
,
BaseTabComponent
,
TabContextMenuItemProvider
}
from
'
terminus-core
'
import
{
TerminalTabComponent
}
from
'
./components/terminalTab.component
'
@
Injectable
()
export
class
SaveAsProfileContextMenu
extends
TabContextMenuItemProvider
{
constructor
(
private
config
:
ConfigService
,
private
zone
:
NgZone
,
private
toastr
:
ToastrService
,
)
{
super
()
}
async
getItems
(
tab
:
BaseTabComponent
):
Promise
<
Electron
.
MenuItemConstructorOptions
[]
>
{
if
(
!
(
tab
instanceof
TerminalTabComponent
))
{
return
[]
}
return
[
{
label
:
'
Save as profile
'
,
click
:
()
=>
this
.
zone
.
run
(
async
()
=>
{
let
profile
=
{
sessionOptions
:
{
...
tab
.
sessionOptions
,
cwd
:
(
await
tab
.
session
.
getWorkingDirectory
())
||
tab
.
sessionOptions
.
cwd
,
},
name
:
tab
.
sessionOptions
.
command
,
}
this
.
config
.
store
.
terminal
.
profiles
=
[
...
this
.
config
.
store
.
terminal
.
profiles
,
profile
,
]
this
.
config
.
save
()
this
.
toastr
.
info
(
'
Saved
'
)
})
}
]
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录