Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
Tabby
提交
3e61630c
T
Tabby
项目概览
后端镜像
/
Tabby
通知
37
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,发现更多精彩内容 >>
未验证
提交
3e61630c
编写于
7月 10, 2021
作者:
E
Eugene Pankov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
added a way to switch a pane's profile - fixes #1007, fixes #2963, fixes #3082, fixes #4151
上级
6f912dc1
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
196 addition
and
85 deletion
+196
-85
tabby-core/src/buttonProvider.ts
tabby-core/src/buttonProvider.ts
+5
-78
tabby-core/src/components/splitTab.component.ts
tabby-core/src/components/splitTab.component.ts
+24
-6
tabby-core/src/configDefaults.linux.yaml
tabby-core/src/configDefaults.linux.yaml
+2
-0
tabby-core/src/configDefaults.macos.yaml
tabby-core/src/configDefaults.macos.yaml
+2
-0
tabby-core/src/configDefaults.windows.yaml
tabby-core/src/configDefaults.windows.yaml
+2
-0
tabby-core/src/hotkeys.ts
tabby-core/src/hotkeys.ts
+4
-0
tabby-core/src/index.ts
tabby-core/src/index.ts
+2
-1
tabby-core/src/services/profiles.service.ts
tabby-core/src/services/profiles.service.ts
+90
-0
tabby-core/src/tabContextMenu.ts
tabby-core/src/tabContextMenu.ts
+65
-0
未找到文件。
tabby-core/src/buttonProvider.ts
浏览文件 @
3e61630c
...
...
@@ -2,26 +2,19 @@
import
{
Injectable
}
from
'
@angular/core
'
import
{
ToolbarButton
,
ToolbarButtonProvider
}
from
'
./api/toolbarButtonProvider
'
import
{
SelectorService
}
from
'
./services/selector.service
'
import
{
HostAppService
,
Platform
}
from
'
./api/hostApp
'
import
{
Profile
}
from
'
./api/profileProvider
'
import
{
ConfigService
}
from
'
./services/config.service
'
import
{
SelectorOption
}
from
'
./api/selector
'
import
{
HotkeysService
}
from
'
./services/hotkeys.service
'
import
{
ProfilesService
}
from
'
./services/profiles.service
'
import
{
AppService
}
from
'
./services/app.service
'
import
{
NotificationsService
}
from
'
./services/notifications.service
'
/** @hidden */
@
Injectable
()
export
class
ButtonProvider
extends
ToolbarButtonProvider
{
constructor
(
private
selector
:
SelectorService
,
private
app
:
AppService
,
private
hostApp
:
HostAppService
,
private
profilesService
s
:
ProfilesService
,
private
profilesService
:
ProfilesService
,
private
config
:
ConfigService
,
private
notifications
:
NotificationsService
,
hotkeys
:
HotkeysService
,
)
{
super
()
...
...
@@ -33,80 +26,14 @@ export class ButtonProvider extends ToolbarButtonProvider {
}
async
activate
()
{
const
recentProfiles
:
Profile
[]
=
this
.
config
.
store
.
recentProfiles
let
options
:
SelectorOption
<
void
>
[]
=
recentProfiles
.
map
(
p
=>
({
...
this
.
profilesServices
.
selectorOptionForProfile
(
p
),
icon
:
'
fas fa-history
'
,
callback
:
async
()
=>
{
if
(
p
.
id
)
{
p
=
(
await
this
.
profilesServices
.
getProfiles
()).
find
(
x
=>
x
.
id
===
p
.
id
)
??
p
}
this
.
launchProfile
(
p
)
},
}))
if
(
recentProfiles
.
length
)
{
options
.
push
({
name
:
'
Clear recent connections
'
,
icon
:
'
fas fa-eraser
'
,
callback
:
async
()
=>
{
this
.
config
.
store
.
recentProfiles
=
[]
this
.
config
.
save
()
},
})
}
let
profiles
=
await
this
.
profilesServices
.
getProfiles
()
if
(
!
this
.
config
.
store
.
terminal
.
showBuiltinProfiles
)
{
profiles
=
profiles
.
filter
(
x
=>
!
x
.
isBuiltin
)
}
profiles
=
profiles
.
filter
(
x
=>
!
x
.
isTemplate
)
options
=
[...
options
,
...
profiles
.
map
((
p
):
SelectorOption
<
void
>
=>
({
...
this
.
profilesServices
.
selectorOptionForProfile
(
p
),
callback
:
()
=>
this
.
launchProfile
(
p
),
}))]
try
{
const
{
SettingsTabComponent
}
=
window
[
'
nodeRequire
'
](
'
tabby-settings
'
)
options
.
push
({
name
:
'
Manage profiles
'
,
icon
:
'
fas fa-window-restore
'
,
callback
:
()
=>
this
.
app
.
openNewTabRaw
({
type
:
SettingsTabComponent
,
inputs
:
{
activeTab
:
'
profiles
'
},
}),
})
}
catch
{
}
if
(
this
.
profilesServices
.
getProviders
().
some
(
x
=>
x
.
supportsQuickConnect
))
{
options
.
push
({
name
:
'
Quick connect
'
,
freeInputPattern
:
'
Connect to "%s"...
'
,
icon
:
'
fas fa-arrow-right
'
,
callback
:
query
=>
this
.
quickConnect
(
query
),
})
}
await
this
.
selector
.
show
(
'
Select profile
'
,
options
)
}
quickConnect
(
query
:
string
)
{
for
(
const
provider
of
this
.
profilesServices
.
getProviders
())
{
if
(
provider
.
supportsQuickConnect
)
{
const
profile
=
provider
.
quickConnect
(
query
)
if
(
profile
)
{
this
.
launchProfile
(
profile
)
return
}
}
const
profile
=
await
this
.
profilesService
.
showProfileSelector
()
if
(
profile
)
{
this
.
launchProfile
(
profile
)
}
this
.
notifications
.
error
(
`Could not parse "
${
query
}
"`
)
}
async
launchProfile
(
profile
:
Profile
)
{
await
this
.
profilesService
s
.
openNewTabForProfile
(
profile
)
await
this
.
profilesService
.
openNewTabForProfile
(
profile
)
let
recentProfiles
=
this
.
config
.
store
.
recentProfiles
recentProfiles
=
recentProfiles
.
filter
(
x
=>
x
.
group
!==
profile
.
group
||
x
.
name
!==
profile
.
name
)
...
...
tabby-core/src/components/splitTab.component.ts
浏览文件 @
3e61630c
...
...
@@ -369,12 +369,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
await
this
.
initialized$
.
toPromise
()
this
.
attachTabView
(
tab
)
setImmediate
(()
=>
{
this
.
layout
()
this
.
tabAdded
.
next
(
tab
)
this
.
focus
(
tab
)
})
this
.
onAfterTabAdded
(
tab
)
}
removeTab
(
tab
:
BaseTabComponent
):
void
{
...
...
@@ -399,6 +394,21 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
}
}
replaceTab
(
tab
:
BaseTabComponent
,
newTab
:
BaseTabComponent
):
void
{
const
parent
=
this
.
getParentOf
(
tab
)
if
(
!
parent
)
{
return
}
const
position
=
parent
.
children
.
indexOf
(
tab
)
parent
.
children
[
position
]
=
newTab
this
.
detachTabView
(
tab
)
this
.
attachTabView
(
newTab
)
tab
.
parent
=
null
newTab
.
parent
=
this
this
.
recoveryStateChangedHint
.
next
()
this
.
onAfterTabAdded
(
newTab
)
}
/**
* Moves focus in the given direction
*/
...
...
@@ -539,6 +549,14 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
}
}
private
onAfterTabAdded
(
tab
:
BaseTabComponent
)
{
setImmediate
(()
=>
{
this
.
layout
()
this
.
tabAdded
.
next
(
tab
)
this
.
focus
(
tab
)
})
}
private
layoutInternal
(
root
:
SplitContainer
,
x
:
number
,
y
:
number
,
w
:
number
,
h
:
number
)
{
const
size
=
root
.
orientation
===
'
v
'
?
h
:
w
const
sizes
=
root
.
ratios
.
map
(
ratio
=>
ratio
*
size
)
...
...
tabby-core/src/configDefaults.linux.yaml
浏览文件 @
3e61630c
...
...
@@ -69,6 +69,8 @@ hotkeys:
pane-maximize
:
-
'
Ctrl-Alt-Enter'
close-pane
:
[]
switch-profile
:
-
'
Ctrl-Alt-T'
profile-selector
:
-
'
Ctrl-Shift-T'
pluginBlacklist
:
[
'
ssh'
]
tabby-core/src/configDefaults.macos.yaml
浏览文件 @
3e61630c
...
...
@@ -70,4 +70,6 @@ hotkeys:
-
'
⌘-Shift-W'
profile-selector
:
-
'
⌘-E'
switch-profile
:
-
'
⌘-Shift-E'
pluginBlacklist
:
[
'
ssh'
]
tabby-core/src/configDefaults.windows.yaml
浏览文件 @
3e61630c
...
...
@@ -70,6 +70,8 @@ hotkeys:
pane-maximize
:
-
'
Ctrl-Alt-Enter'
close-pane
:
[]
switch-profile
:
-
'
Ctrl-Alt-T'
profile-selector
:
-
'
Ctrl-Shift-T'
pluginBlacklist
:
[]
tabby-core/src/hotkeys.ts
浏览文件 @
3e61630c
...
...
@@ -170,6 +170,10 @@ export class AppHotkeyProvider extends HotkeyProvider {
id
:
'
pane-nav-next
'
,
name
:
'
Focus next pane
'
,
},
{
id
:
'
switch-profile
'
,
name
:
'
Switch profile in the active pane
'
,
},
{
id
:
'
close-pane
'
,
name
:
'
Close focused pane
'
,
...
...
tabby-core/src/index.ts
浏览文件 @
3e61630c
...
...
@@ -40,7 +40,7 @@ import { HotkeysService } from './services/hotkeys.service'
import
{
StandardTheme
,
StandardCompactTheme
,
PaperTheme
}
from
'
./theme
'
import
{
CoreConfigProvider
}
from
'
./config
'
import
{
AppHotkeyProvider
}
from
'
./hotkeys
'
import
{
TaskCompletionContextMenu
,
CommonOptionsContextMenu
,
TabManagementContextMenu
}
from
'
./tabContextMenu
'
import
{
TaskCompletionContextMenu
,
CommonOptionsContextMenu
,
TabManagementContextMenu
,
ProfilesContextMenu
}
from
'
./tabContextMenu
'
import
{
LastCLIHandler
,
ProfileCLIHandler
}
from
'
./cli
'
import
{
ButtonProvider
}
from
'
./buttonProvider
'
...
...
@@ -56,6 +56,7 @@ const PROVIDERS = [
{
provide
:
TabContextMenuItemProvider
,
useClass
:
CommonOptionsContextMenu
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
TabManagementContextMenu
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
TaskCompletionContextMenu
,
multi
:
true
},
{
provide
:
TabContextMenuItemProvider
,
useClass
:
ProfilesContextMenu
,
multi
:
true
},
{
provide
:
TabRecoveryProvider
,
useClass
:
SplitTabRecoveryProvider
,
multi
:
true
},
{
provide
:
CLIHandler
,
useClass
:
ProfileCLIHandler
,
multi
:
true
},
{
provide
:
CLIHandler
,
useClass
:
LastCLIHandler
,
multi
:
true
},
...
...
tabby-core/src/services/profiles.service.ts
浏览文件 @
3e61630c
...
...
@@ -5,12 +5,16 @@ import { Profile, ProfileProvider } from '../api/profileProvider'
import
{
SelectorOption
}
from
'
../api/selector
'
import
{
AppService
}
from
'
./app.service
'
import
{
ConfigService
}
from
'
./config.service
'
import
{
NotificationsService
}
from
'
./notifications.service
'
import
{
SelectorService
}
from
'
./selector.service
'
@
Injectable
({
providedIn
:
'
root
'
})
export
class
ProfilesService
{
constructor
(
private
app
:
AppService
,
private
config
:
ConfigService
,
private
notifications
:
NotificationsService
,
private
selector
:
SelectorService
,
@
Inject
(
ProfileProvider
)
private
profileProviders
:
ProfileProvider
[],
)
{
}
...
...
@@ -60,4 +64,90 @@ export class ProfilesService {
description
:
this
.
providerForProfile
(
profile
)?.
getDescription
(
profile
),
}
}
showProfileSelector
():
Promise
<
Profile
|
null
>
{
return
new
Promise
<
Profile
|
null
>
(
async
(
resolve
,
reject
)
=>
{
try
{
const
recentProfiles
:
Profile
[]
=
this
.
config
.
store
.
recentProfiles
let
options
:
SelectorOption
<
void
>
[]
=
recentProfiles
.
map
(
p
=>
({
...
this
.
selectorOptionForProfile
(
p
),
icon
:
'
fas fa-history
'
,
callback
:
async
()
=>
{
if
(
p
.
id
)
{
p
=
(
await
this
.
getProfiles
()).
find
(
x
=>
x
.
id
===
p
.
id
)
??
p
}
resolve
(
p
)
},
}))
if
(
recentProfiles
.
length
)
{
options
.
push
({
name
:
'
Clear recent connections
'
,
icon
:
'
fas fa-eraser
'
,
callback
:
async
()
=>
{
this
.
config
.
store
.
recentProfiles
=
[]
this
.
config
.
save
()
resolve
(
null
)
},
})
}
let
profiles
=
await
this
.
getProfiles
()
if
(
!
this
.
config
.
store
.
terminal
.
showBuiltinProfiles
)
{
profiles
=
profiles
.
filter
(
x
=>
!
x
.
isBuiltin
)
}
profiles
=
profiles
.
filter
(
x
=>
!
x
.
isTemplate
)
options
=
[...
options
,
...
profiles
.
map
((
p
):
SelectorOption
<
void
>
=>
({
...
this
.
selectorOptionForProfile
(
p
),
callback
:
()
=>
resolve
(
p
),
}))]
try
{
const
{
SettingsTabComponent
}
=
window
[
'
nodeRequire
'
](
'
tabby-settings
'
)
options
.
push
({
name
:
'
Manage profiles
'
,
icon
:
'
fas fa-window-restore
'
,
callback
:
()
=>
{
this
.
app
.
openNewTabRaw
({
type
:
SettingsTabComponent
,
inputs
:
{
activeTab
:
'
profiles
'
},
})
resolve
(
null
)
},
})
}
catch
{
}
if
(
this
.
getProviders
().
some
(
x
=>
x
.
supportsQuickConnect
))
{
options
.
push
({
name
:
'
Quick connect
'
,
freeInputPattern
:
'
Connect to "%s"...
'
,
icon
:
'
fas fa-arrow-right
'
,
callback
:
query
=>
{
const
profile
=
this
.
quickConnect
(
query
)
resolve
(
profile
)
},
})
}
await
this
.
selector
.
show
(
'
Select profile
'
,
options
)
}
catch
(
err
)
{
reject
(
err
)
}
})
}
async
quickConnect
(
query
:
string
):
Promise
<
Profile
|
null
>
{
for
(
const
provider
of
this
.
getProviders
())
{
if
(
provider
.
supportsQuickConnect
)
{
const
profile
=
provider
.
quickConnect
(
query
)
if
(
profile
)
{
return
profile
}
}
}
this
.
notifications
.
error
(
`Could not parse "
${
query
}
"`
)
return
null
}
}
tabby-core/src/tabContextMenu.ts
浏览文件 @
3e61630c
...
...
@@ -7,6 +7,9 @@ import { TabHeaderComponent } from './components/tabHeader.component'
import
{
SplitTabComponent
,
SplitDirection
}
from
'
./components/splitTab.component
'
import
{
TabContextMenuItemProvider
}
from
'
./api/tabContextMenuProvider
'
import
{
MenuItemOptions
}
from
'
./api/menu
'
import
{
ProfilesService
}
from
'
./services/profiles.service
'
import
{
TabsService
}
from
'
./services/tabs.service
'
import
{
HotkeysService
}
from
'
./services/hotkeys.service
'
/** @hidden */
@
Injectable
()
...
...
@@ -203,3 +206,65 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
return
items
}
}
/** @hidden */
@
Injectable
()
export
class
ProfilesContextMenu
extends
TabContextMenuItemProvider
{
weight
=
10
constructor
(
private
profilesService
:
ProfilesService
,
private
tabsService
:
TabsService
,
private
app
:
AppService
,
hotkeys
:
HotkeysService
,
)
{
super
()
hotkeys
.
hotkey$
.
subscribe
(
hotkey
=>
{
if
(
hotkey
===
'
switch-profile
'
)
{
let
tab
=
this
.
app
.
activeTab
if
(
tab
instanceof
SplitTabComponent
)
{
tab
=
tab
.
getFocusedTab
()
if
(
tab
)
{
this
.
switchTabProfile
(
tab
)
}
}
}
})
}
async
switchTabProfile
(
tab
:
BaseTabComponent
)
{
const
profile
=
await
this
.
profilesService
.
showProfileSelector
()
if
(
!
profile
)
{
return
}
const
params
=
await
this
.
profilesService
.
newTabParametersForProfile
(
profile
)
if
(
!
params
)
{
return
}
if
(
!
await
tab
.
canClose
())
{
return
}
const
newTab
=
this
.
tabsService
.
create
(
params
)
;(
tab
.
parent
as
SplitTabComponent
).
replaceTab
(
tab
,
newTab
)
tab
.
destroy
()
}
async
getItems
(
tab
:
BaseTabComponent
,
tabHeader
?:
TabHeaderComponent
):
Promise
<
MenuItemOptions
[]
>
{
if
(
!
tabHeader
&&
tab
.
parent
instanceof
SplitTabComponent
&&
tab
.
parent
.
getAllTabs
().
length
>
1
)
{
return
[
{
label
:
'
Switch profile
'
,
click
:
()
=>
this
.
switchTabProfile
(
tab
),
},
]
}
return
[]
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录