Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
Tabby
提交
57c7e48b
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,发现更多精彩内容 >>
提交
57c7e48b
编写于
6月 07, 2021
作者:
E
Eugene Pankov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
finished transfers menu
上级
49369873
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
221 addition
and
108 deletion
+221
-108
terminus-core/src/api/index.ts
terminus-core/src/api/index.ts
+1
-1
terminus-core/src/api/platform.ts
terminus-core/src/api/platform.ts
+23
-2
terminus-core/src/components/appRoot.component.pug
terminus-core/src/components/appRoot.component.pug
+11
-16
terminus-core/src/components/appRoot.component.scss
terminus-core/src/components/appRoot.component.scss
+0
-22
terminus-core/src/components/appRoot.component.ts
terminus-core/src/components/appRoot.component.ts
+8
-1
terminus-core/src/components/transfersMenu.component.pug
terminus-core/src/components/transfersMenu.component.pug
+13
-0
terminus-core/src/components/transfersMenu.component.scss
terminus-core/src/components/transfersMenu.component.scss
+31
-0
terminus-core/src/components/transfersMenu.component.ts
terminus-core/src/components/transfersMenu.component.ts
+38
-0
terminus-core/src/icons/download-solid.svg
terminus-core/src/icons/download-solid.svg
+1
-0
terminus-core/src/icons/download.svg
terminus-core/src/icons/download.svg
+1
-1
terminus-core/src/icons/upload.svg
terminus-core/src/icons/upload.svg
+1
-0
terminus-core/src/index.ts
terminus-core/src/index.ts
+2
-0
terminus-core/src/services/config.service.ts
terminus-core/src/services/config.service.ts
+1
-1
terminus-core/src/theme.scss
terminus-core/src/theme.scss
+8
-1
terminus-core/src/theme.vars.scss
terminus-core/src/theme.vars.scss
+1
-1
terminus-electron/src/services/platform.service.ts
terminus-electron/src/services/platform.service.ts
+55
-20
terminus-terminal/src/features/debug.ts
terminus-terminal/src/features/debug.ts
+12
-22
terminus-terminal/src/features/zmodem.ts
terminus-terminal/src/features/zmodem.ts
+14
-20
未找到文件。
terminus-core/src/api/index.ts
浏览文件 @
57c7e48b
...
...
@@ -10,7 +10,7 @@ export { Theme } from './theme'
export
{
TabContextMenuItemProvider
}
from
'
./tabContextMenuProvider
'
export
{
SelectorOption
}
from
'
./selector
'
export
{
CLIHandler
,
CLIEvent
}
from
'
./cli
'
export
{
PlatformService
,
ClipboardContent
,
MessageBoxResult
,
MessageBoxOptions
,
FileDownload
,
FileUpload
,
FileTransfer
}
from
'
./platform
'
export
{
PlatformService
,
ClipboardContent
,
MessageBoxResult
,
MessageBoxOptions
,
FileDownload
,
FileUpload
,
FileTransfer
,
FileUploadOptions
}
from
'
./platform
'
export
{
MenuItemOptions
}
from
'
./menu
'
export
{
BootstrapData
,
BOOTSTRAP_DATA
}
from
'
./mainProcess
'
export
{
HostWindowService
}
from
'
./hostWindow
'
...
...
terminus-core/src/api/platform.ts
浏览文件 @
57c7e48b
import
{
MenuItemOptions
}
from
'
./menu
'
import
{
Subject
,
Observable
}
from
'
rxjs
'
/* eslint-disable @typescript-eslint/no-unused-vars */
export
interface
ClipboardContent
{
...
...
@@ -54,18 +55,38 @@ export abstract class FileDownload extends FileTransfer {
export
abstract
class
FileUpload
extends
FileTransfer
{
abstract
read
():
Promise
<
Buffer
>
async
readAll
():
Promise
<
Buffer
>
{
const
buffers
:
Buffer
[]
=
[]
while
(
true
)
{
const
buf
=
await
this
.
read
()
if
(
!
buf
.
length
)
{
break
}
buffers
.
push
(
Buffer
.
from
(
buf
))
}
return
Buffer
.
concat
(
buffers
)
}
}
export
interface
FileUploadOptions
{
multiple
:
boolean
}
export
abstract
class
PlatformService
{
supportsWindowControls
=
false
get
fileTransferStarted$
():
Observable
<
FileTransfer
>
{
return
this
.
fileTransferStarted
}
protected
fileTransferStarted
=
new
Subject
<
FileTransfer
>
()
abstract
readClipboard
():
string
abstract
setClipboard
(
content
:
ClipboardContent
):
void
abstract
loadConfig
():
Promise
<
string
>
abstract
saveConfig
(
content
:
string
):
Promise
<
void
>
abstract
startDownload
(
name
:
string
,
size
:
number
):
Promise
<
FileDownload
>
abstract
startUpload
():
Promise
<
FileUpload
[]
>
abstract
startDownload
(
name
:
string
,
size
:
number
):
Promise
<
FileDownload
|
null
>
abstract
startUpload
(
options
?:
FileUploadOptions
):
Promise
<
FileUpload
[]
>
getConfigPath
():
string
|
null
{
return
null
...
...
terminus-core/src/components/appRoot.component.pug
浏览文件 @
57c7e48b
...
...
@@ -57,6 +57,17 @@ title-bar(
)
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
.d-flex(
*ngIf='activeTransfers.length > 0',
ngbDropdown,
[(open)]='activeTransfersDropdownOpen'
)
button.btn.btn-secondary.btn-tab-bar(
title='File transfers',
ngbDropdownToggle
) !{require('../icons/download-solid.svg')}
transfers-menu(ngbDropdownMenu, [(transfers)]='activeTransfers')
.drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
.btn-group.background
...
...
@@ -83,22 +94,6 @@ title-bar(
)
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
.d-flex(ngbDropdown)
button.btn.btn-secondary.btn-tab-bar(
title='File transfers',
ngbDropdownToggle
) !{require('../icons/download.svg')}
.transfers-dropdown-menu(ngbDropdownMenu)
.dropdown-header File transfers
.dropdown-item.transfer
.mr-3 !{require('../icons/download.svg')}
.main
label file.bin
.progress
.progress-bar.w-25
small 25%
button.btn.btn-link !{require('../icons/times.svg')}
button.btn.btn-secondary.btn-tab-bar.btn-update(
*ngIf='updatesAvailable',
title='Update available - Click to install',
...
...
terminus-core/src/components/appRoot.component.scss
浏览文件 @
57c7e48b
...
...
@@ -178,25 +178,3 @@ hotkey-hint {
::ng-deep
.btn-update
svg
{
fill
:
cyan
;
}
.transfers-dropdown-menu
{
min-width
:
300px
;
.transfer
{
display
:
flex
;
align-items
:
center
;
padding
:
5px
0
5px
25px
;
.main
{
margin-right
:
auto
;
label
{
margin-bottom
:
5px
;
}
}
>
i
{
margin-right
:
10px
;
}
}
}
terminus-core/src/components/appRoot.component.ts
浏览文件 @
57c7e48b
...
...
@@ -12,7 +12,7 @@ import { UpdaterService } from '../services/updater.service'
import
{
BaseTabComponent
}
from
'
./baseTab.component
'
import
{
SafeModeModalComponent
}
from
'
./safeModeModal.component
'
import
{
AppService
,
HostWindowService
,
PlatformService
,
ToolbarButton
,
ToolbarButtonProvider
}
from
'
../api
'
import
{
AppService
,
FileTransfer
,
HostWindowService
,
PlatformService
,
ToolbarButton
,
ToolbarButtonProvider
}
from
'
../api
'
/** @hidden */
@
Component
({
...
...
@@ -60,6 +60,8 @@ export class AppRootComponent {
tabsDragging
=
false
unsortedTabs
:
BaseTabComponent
[]
=
[]
updatesAvailable
=
false
activeTransfers
:
FileTransfer
[]
=
[]
activeTransfersDropdownOpen
=
false
private
logger
:
Logger
private
constructor
(
...
...
@@ -131,6 +133,11 @@ export class AppRootComponent {
this
.
noTabs
=
app
.
tabs
.
length
===
0
})
platform
.
fileTransferStarted$
.
subscribe
(
transfer
=>
{
this
.
activeTransfers
.
push
(
transfer
)
this
.
activeTransfersDropdownOpen
=
true
})
config
.
ready$
.
toPromise
().
then
(()
=>
{
this
.
leftToolbarButtons
=
this
.
getToolbarButtons
(
false
)
this
.
rightToolbarButtons
=
this
.
getToolbarButtons
(
true
)
...
...
terminus-core/src/components/transfersMenu.component.pug
0 → 100644
浏览文件 @
57c7e48b
.dropdown-header File transfers
.dropdown-item.transfer(*ngFor='let transfer of transfers', (click)='showTransfer(transfer)')
.icon(*ngIf='isDownload(transfer)') !{require('../icons/download.svg')}
.icon(*ngIf='!isDownload(transfer)') !{require('../icons/upload.svg')}
.main
label {{transfer.getName()}}
.status(*ngIf='transfer.isComplete()')
ngb-progressbar(type='success', [value]='100')
.status(*ngIf='transfer.isCancelled()')
ngb-progressbar(type='danger', [value]='100')
.status(*ngIf='!transfer.isComplete() && !transfer.isCancelled()')
ngb-progressbar(type='info', [value]='getProgress(transfer)')
button.btn.btn-link((click)='removeTransfer(transfer); $event.stopPropagation()') !{require('../icons/times.svg')}
terminus-core/src/components/transfersMenu.component.scss
0 → 100644
浏览文件 @
57c7e48b
:host
{
min-width
:
300px
;
}
.transfer
{
display
:
flex
;
align-items
:
center
;
padding
:
5px
0
5px
25px
;
.icon
{
padding
:
4px
10px
;
width
:
36px
;
height
:
32px
;
background
:
rgba
(
0
,
0
,
0
,.
25
);
margin-right
:
12px
;
}
.main
{
width
:
100%
;
margin-right
:
auto
;
margin-bottom
:
7px
;
label
{
margin
:
0
;
}
}
>
i
{
margin-right
:
10px
;
}
}
terminus-core/src/components/transfersMenu.component.ts
0 → 100644
浏览文件 @
57c7e48b
import
{
Component
,
Input
,
Output
,
EventEmitter
}
from
'
@angular/core
'
import
{
FileDownload
,
FileTransfer
,
PlatformService
}
from
'
../api/platform
'
/** @hidden */
@
Component
({
selector
:
'
transfers-menu
'
,
template
:
require
(
'
./transfersMenu.component.pug
'
),
styles
:
[
require
(
'
./transfersMenu.component.scss
'
)],
})
export
class
TransfersMenuComponent
{
@
Input
()
transfers
:
FileTransfer
[]
@
Output
()
transfersChange
=
new
EventEmitter
<
FileTransfer
[]
>
()
constructor
(
private
platform
:
PlatformService
)
{
}
isDownload
(
transfer
:
FileTransfer
):
boolean
{
return
transfer
instanceof
FileDownload
}
getProgress
(
transfer
:
FileTransfer
):
number
{
return
Math
.
round
(
100
*
transfer
.
getCompletedBytes
()
/
transfer
.
getSize
())
}
showTransfer
(
transfer
:
FileTransfer
):
void
{
const
fp
=
transfer
[
'
filePath
'
]
if
(
fp
)
{
this
.
platform
.
showItemInFolder
(
fp
)
}
}
removeTransfer
(
transfer
:
FileTransfer
):
void
{
if
(
!
transfer
.
isComplete
())
{
transfer
.
cancel
()
}
this
.
transfers
=
this
.
transfers
.
filter
(
x
=>
x
!==
transfer
)
this
.
transfersChange
.
emit
(
this
.
transfers
)
}
}
terminus-core/src/icons/download-solid.svg
0 → 100644
浏览文件 @
57c7e48b
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 512 512"
><path
d=
"M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z"
></path></svg>
terminus-core/src/icons/download.svg
浏览文件 @
57c7e48b
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 576 512"
><path
d=
"M528 288h-92.1l46.1-46.1c30.1-30.1 8.8-81.9-33.9-81.9h-64V48c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v112h-64c-42.6 0-64.2 51.7-33.9 81.9l46.1 46.1H48c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V336c0-26.5-21.5-48-48-48zm-400-80h112V48h96v160h112L288 368 128 208zm400 256H48V336h140.1l65.9 65.9c18.8 18.8 49.1 18.7 67.9 0l65.9-65.9H528v128zm-88-64c0-13.3 10.7-24 24-24s24 10.7 24 24-10.7 24-24 24-24-10.7-24-24z"
></path
></svg>
<svg
aria-hidden=
"true"
focusable=
"false"
data-prefix=
"fad"
data-icon=
"download"
class=
"svg-inline--fa fa-download fa-w-16"
role=
"img"
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 512 512"
><g
class=
"fa-group"
><path
class=
"fa-secondary"
fill=
"currentColor"
d=
"M320 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3a19.37 19.37 0 0 1-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24a23.94 23.94 0 0 1 24-24h80a23.94 23.94 0 0 1 24 24z"
opacity=
"0.4"
></path><path
class=
"fa-primary"
fill=
"currentColor"
d=
"M488 352H341.3l-49 49a51.24 51.24 0 0 1-72.6 0l-49-49H24a23.94 23.94 0 0 0-24 24v112a23.94 23.94 0 0 0 24 24h464a23.94 23.94 0 0 0 24-24V376a23.94 23.94 0 0 0-24-24zm-120 96a16 16 0 1 1 16-16 16 16 0 0 1-16 16zm64 0a16 16 0 1 1 16-16 16 16 0 0 1-16 16z"
></path></g
></svg>
\ No newline at end of file
terminus-core/src/icons/upload.svg
0 → 100644
浏览文件 @
57c7e48b
<svg
aria-hidden=
"true"
focusable=
"false"
data-prefix=
"fad"
data-icon=
"upload"
class=
"svg-inline--fa fa-upload fa-w-16"
role=
"img"
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 512 512"
><g
class=
"fa-group"
><path
class=
"fa-secondary"
fill=
"currentColor"
d=
"M488 351.92H352v8a56 56 0 0 1-56 56h-80a56 56 0 0 1-56-56v-8H24a23.94 23.94 0 0 0-24 24v112a23.94 23.94 0 0 0 24 24h464a23.94 23.94 0 0 0 24-24v-112a23.94 23.94 0 0 0-24-24zm-120 132a20 20 0 1 1 20-20 20.06 20.06 0 0 1-20 20zm64 0a20 20 0 1 1 20-20 20.06 20.06 0 0 1-20 20z"
opacity=
"0.4"
></path><path
class=
"fa-primary"
fill=
"currentColor"
d=
"M192 359.93v-168h-87.7c-17.8 0-26.7-21.5-14.1-34.11L242.3 5.62a19.37 19.37 0 0 1 27.3 0l152.2 152.2c12.6 12.61 3.7 34.11-14.1 34.11H320v168a23.94 23.94 0 0 1-24 24h-80a23.94 23.94 0 0 1-24-24z"
></path></g></svg>
\ No newline at end of file
terminus-core/src/index.ts
浏览文件 @
57c7e48b
...
...
@@ -21,6 +21,7 @@ import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitT
import
{
SplitTabSpannerComponent
}
from
'
./components/splitTabSpanner.component
'
import
{
UnlockVaultModalComponent
}
from
'
./components/unlockVaultModal.component
'
import
{
WelcomeTabComponent
}
from
'
./components/welcomeTab.component
'
import
{
TransfersMenuComponent
}
from
'
./components/transfersMenu.component
'
import
{
AutofocusDirective
}
from
'
./directives/autofocus.directive
'
import
{
FastHtmlBindDirective
}
from
'
./directives/fastHtmlBind.directive
'
...
...
@@ -81,6 +82,7 @@ const PROVIDERS = [
SplitTabSpannerComponent
,
UnlockVaultModalComponent
,
WelcomeTabComponent
,
TransfersMenuComponent
,
],
entryComponents
:
[
RenameTabModalComponent
,
...
...
terminus-core/src/services/config.service.ts
浏览文件 @
57c7e48b
...
...
@@ -242,7 +242,7 @@ export class ConfigService {
private
migrate
(
config
)
{
config
.
version
??=
0
if
(
config
.
version
<
1
)
{
for
(
const
connection
of
config
.
ssh
?.
connections
)
{
for
(
const
connection
of
config
.
ssh
?.
connections
??
[]
)
{
if
(
connection
.
privateKey
)
{
connection
.
privateKeys
=
[
connection
.
privateKey
]
delete
connection
.
privateKey
...
...
terminus-core/src/theme.scss
浏览文件 @
57c7e48b
...
...
@@ -43,7 +43,10 @@ app-root {
.btn-tab-bar
{
background
:
transparent
;
&
:hover
{
background
:
rgba
(
0
,
0
,
0
,
.25
)
!
important
;
}
&
:active
{
background
:
rgba
(
0
,
0
,
0
,
.5
)
!
important
;
}
&
:active
,
&
[
aria-expanded-true
]
{
background
:
rgba
(
0
,
0
,
0
,
.5
)
!
important
;
}
&
:focus
{
box-shadow
:
none
;
}
&
::after
{
display
:
none
;
...
...
@@ -386,3 +389,7 @@ search-panel {
hr
{
border-color
:
$list-group-border-color
;
}
.dropdown-menu
{
box-shadow
:
$dropdown-box-shadow
;
}
terminus-core/src/theme.vars.scss
浏览文件 @
57c7e48b
...
...
@@ -191,5 +191,5 @@ $modal-footer-border-color: #222;
$modal-footer-border-width
:
1px
;
$modal-content-border-width
:
0
;
$progress-b
ar-b
g
:
$table-bg
;
$progress-bg
:
$table-bg
;
$progress-height
:
3px
;
terminus-electron/src/services/platform.service.ts
浏览文件 @
57c7e48b
...
...
@@ -4,8 +4,8 @@ import * as fsSync from 'fs'
import
*
as
os
from
'
os
'
import
promiseIpc
from
'
electron-promise-ipc
'
import
{
execFile
}
from
'
mz/child_process
'
import
{
Injectable
}
from
'
@angular/core
'
import
{
PlatformService
,
ClipboardContent
,
HostAppService
,
Platform
,
ElectronService
,
MenuItemOptions
,
MessageBoxOptions
,
MessageBoxResult
,
FileUpload
}
from
'
terminus-core
'
import
{
Injectable
,
NgZone
}
from
'
@angular/core
'
import
{
PlatformService
,
ClipboardContent
,
HostAppService
,
Platform
,
ElectronService
,
MenuItemOptions
,
MessageBoxOptions
,
MessageBoxResult
,
FileUpload
,
FileDownload
,
FileUploadOptions
}
from
'
terminus-core
'
const
fontManager
=
require
(
'
fontmanager-redux
'
)
// eslint-disable-line
/* eslint-disable block-scoped-var */
...
...
@@ -26,6 +26,7 @@ export class ElectronPlatformService extends PlatformService {
constructor
(
private
hostApp
:
HostAppService
,
private
electron
:
ElectronService
,
private
zone
:
NgZone
,
)
{
super
()
this
.
configPath
=
path
.
join
(
electron
.
app
.
getPath
(
'
userData
'
),
'
config.yaml
'
)
...
...
@@ -159,24 +160,58 @@ export class ElectronPlatformService extends PlatformService {
this
.
electron
.
app
.
exit
(
0
)
}
async
startUpload
():
Promise
<
FileUpload
[]
>
{
async
startUpload
(
options
?:
FileUploadOptions
):
Promise
<
FileUpload
[]
>
{
options
??=
{
multiple
:
false
}
const
properties
:
any
[]
=
[
'
openFile
'
,
'
treatPackageAsDirectory
'
]
if
(
options
.
multiple
)
{
properties
.
push
(
'
multiSelections
'
)
}
const
result
=
await
this
.
electron
.
dialog
.
showOpenDialog
(
this
.
hostApp
.
getWindow
(),
{
buttonLabel
:
'
Select
'
,
properties
:
[
'
multiSelections
'
,
'
openFile
'
,
'
treatPackageAsDirectory
'
]
,
properties
,
},
)
if
(
result
.
canceled
)
{
return
[]
}
return
Promise
.
all
(
result
.
filePaths
.
map
(
async
path
=>
{
const
t
=
new
ElectronFileUpload
(
path
)
await
t
.
open
()
return
t
return
Promise
.
all
(
result
.
filePaths
.
map
(
async
p
=>
{
const
transfer
=
new
ElectronFileUpload
(
p
)
await
this
.
wrapPromise
(
transfer
.
open
())
this
.
fileTransferStarted
.
next
(
transfer
)
return
transfer
}))
}
async
startDownload
(
name
:
string
,
size
:
number
):
Promise
<
FileDownload
|
null
>
{
const
result
=
await
this
.
electron
.
dialog
.
showSaveDialog
(
this
.
hostApp
.
getWindow
(),
{
defaultPath
:
name
,
},
)
if
(
!
result
.
filePath
)
{
return
null
}
const
transfer
=
new
ElectronFileDownload
(
result
.
filePath
,
size
)
await
this
.
wrapPromise
(
transfer
.
open
())
this
.
fileTransferStarted
.
next
(
transfer
)
return
transfer
}
private
wrapPromise
<
T
>
(
promise
:
Promise
<
T
>
):
Promise
<
T
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
promise
.
then
(
result
=>
{
this
.
zone
.
run
(()
=>
resolve
(
result
))
}).
catch
(
error
=>
{
this
.
zone
.
run
(()
=>
reject
(
error
))
})
})
}
}
class
ElectronFileUpload
extends
FileUpload
{
...
...
@@ -205,7 +240,6 @@ class ElectronFileUpload extends FileUpload {
async
read
():
Promise
<
Buffer
>
{
const
result
=
await
this
.
file
.
read
(
this
.
buffer
,
0
,
this
.
buffer
.
length
,
null
)
this
.
increaseProgress
(
result
.
bytesRead
)
console
.
log
(
result
)
return
this
.
buffer
.
slice
(
0
,
result
.
bytesRead
)
}
...
...
@@ -215,18 +249,17 @@ class ElectronFileUpload extends FileUpload {
}
class
ElectronFileDownload
extends
FileDownload
{
private
size
:
number
private
file
:
fs
.
FileHandle
private
buffer
:
Buffer
constructor
(
private
filePath
:
string
)
{
constructor
(
private
filePath
:
string
,
private
size
:
number
,
)
{
super
()
this
.
buffer
=
Buffer
.
alloc
(
256
*
1024
)
}
async
open
():
Promise
<
void
>
{
this
.
size
=
(
await
fs
.
stat
(
this
.
filePath
)).
size
this
.
file
=
await
fs
.
open
(
this
.
filePath
,
'
r
'
)
this
.
file
=
await
fs
.
open
(
this
.
filePath
,
'
w
'
)
}
getName
():
string
{
...
...
@@ -237,11 +270,13 @@ class ElectronFileDownload extends FileDownload {
return
this
.
size
}
async
read
():
Promise
<
Buffer
>
{
const
result
=
await
this
.
file
.
read
(
this
.
buffer
,
0
,
this
.
buffer
.
length
,
null
)
this
.
increaseProgress
(
result
.
bytesRead
)
console
.
log
(
result
)
return
this
.
buffer
.
slice
(
0
,
result
.
bytesRead
)
async
write
(
buffer
:
Buffer
):
Promise
<
void
>
{
let
pos
=
0
while
(
pos
<
buffer
.
length
)
{
const
result
=
await
this
.
file
.
write
(
buffer
,
pos
,
buffer
.
length
-
pos
,
null
)
this
.
increaseProgress
(
result
.
bytesWritten
)
pos
+=
result
.
bytesWritten
}
}
close
():
void
{
...
...
terminus-terminal/src/features/debug.ts
浏览文件 @
57c7e48b
import
*
as
fs
from
'
fs
'
import
{
Injectable
}
from
'
@angular/core
'
import
{
TerminalDecorator
}
from
'
../api/decorator
'
import
{
BaseTerminalTabComponent
}
from
'
../api/baseTerminalTab.component
'
import
{
ElectronService
,
HostAppService
,
PlatformService
}
from
'
terminus-core
'
import
{
PlatformService
}
from
'
terminus-core
'
/** @hidden */
@
Injectable
()
export
class
DebugDecorator
extends
TerminalDecorator
{
constructor
(
private
electron
:
ElectronService
,
private
platform
:
PlatformService
,
private
hostApp
:
HostAppService
,
)
{
super
()
}
...
...
@@ -63,28 +60,21 @@ export class DebugDecorator extends TerminalDecorator {
}
private
async
loadFile
():
Promise
<
string
|
null
>
{
const
result
=
await
this
.
electron
.
dialog
.
showOpenDialog
(
this
.
hostApp
.
getWindow
(),
{
buttonLabel
:
'
Load
'
,
properties
:
[
'
openFile
'
,
'
treatPackageAsDirectory
'
],
},
)
if
(
result
.
filePaths
.
length
)
{
return
fs
.
readFileSync
(
result
.
filePaths
[
0
],
{
encoding
:
'
utf-8
'
})
const
transfer
=
await
this
.
platform
.
startUpload
()
if
(
!
transfer
.
length
)
{
return
null
}
return
null
const
data
=
await
transfer
[
0
].
readAll
()
transfer
[
0
].
close
()
return
data
.
toString
()
}
private
async
saveFile
(
content
:
string
,
name
:
string
)
{
const
result
=
await
this
.
electron
.
dialog
.
showSaveDialog
(
this
.
hostApp
.
getWindow
(),
{
defaultPath
:
name
,
},
)
if
(
result
.
filePath
)
{
fs
.
writeFileSync
(
result
.
filePath
,
content
)
const
data
=
Buffer
.
from
(
content
)
const
transfer
=
await
this
.
platform
.
startDownload
(
name
,
data
.
length
)
if
(
transfer
)
{
transfer
.
write
(
data
)
transfer
.
close
()
}
}
...
...
terminus-terminal/src/features/zmodem.ts
浏览文件 @
57c7e48b
import
colors
from
'
ansi-colors
'
import
*
as
ZModem
from
'
zmodem.js
'
import
*
as
fs
from
'
fs
'
import
{
Observable
}
from
'
rxjs
'
import
{
filter
}
from
'
rxjs/operators
'
import
{
filter
,
first
}
from
'
rxjs/operators
'
import
{
Injectable
}
from
'
@angular/core
'
import
{
TerminalDecorator
}
from
'
../api/decorator
'
import
{
BaseTerminalTabComponent
}
from
'
../api/baseTerminalTab.component
'
import
{
LogService
,
Logger
,
ElectronService
,
HostAppService
,
HotkeysService
,
PlatformService
,
FileUpload
}
from
'
terminus-core
'
import
{
LogService
,
Logger
,
HotkeysService
,
PlatformService
,
FileUpload
}
from
'
terminus-core
'
const
SPACER
=
'
'
...
...
@@ -20,8 +19,6 @@ export class ZModemDecorator extends TerminalDecorator {
constructor
(
log
:
LogService
,
hotkeys
:
HotkeysService
,
private
electron
:
ElectronService
,
private
hostApp
:
HostAppService
,
private
platform
:
PlatformService
,
)
{
super
()
...
...
@@ -87,7 +84,7 @@ export class ZModemDecorator extends TerminalDecorator {
this
.
logger
.
info
(
'
new session
'
,
zsession
)
if
(
zsession
.
type
===
'
send
'
)
{
const
transfers
=
await
this
.
platform
.
startUpload
()
const
transfers
=
await
this
.
platform
.
startUpload
(
{
multiple
:
true
}
)
let
filesRemaining
=
transfers
.
length
let
sizeRemaining
=
transfers
.
reduce
((
a
,
b
)
=>
a
+
b
.
getSize
(),
0
)
for
(
const
transfer
of
transfers
)
{
...
...
@@ -116,20 +113,14 @@ export class ZModemDecorator extends TerminalDecorator {
}
=
xfer
.
get_details
()
this
.
showMessage
(
terminal
,
colors
.
bgYellow
.
black
(
'
Offered
'
)
+
'
'
+
details
.
name
,
true
)
this
.
logger
.
info
(
'
offered
'
,
xfer
)
const
result
=
await
this
.
electron
.
dialog
.
showSaveDialog
(
this
.
hostApp
.
getWindow
(),
{
defaultPath
:
details
.
name
,
},
)
if
(
!
result
.
filePath
)
{
const
transfer
=
await
this
.
platform
.
startDownload
(
details
.
name
,
details
.
size
)
if
(
!
transfer
)
{
this
.
showMessage
(
terminal
,
colors
.
bgRed
.
black
(
'
Rejected
'
)
+
'
'
+
details
.
name
)
xfer
.
skip
()
return
}
const
stream
=
fs
.
createWriteStream
(
result
.
filePath
)
let
bytesSent
=
0
let
canceled
=
false
const
cancelSubscription
=
this
.
cancelEvent
.
subscribe
(()
=>
{
if
(
terminal
.
hasFocus
)
{
...
...
@@ -147,18 +138,19 @@ export class ZModemDecorator extends TerminalDecorator {
if
(
canceled
)
{
return
}
stream
.
write
(
Buffer
.
from
(
chunk
))
bytesSent
+=
chunk
.
length
this
.
showMessage
(
terminal
,
colors
.
bgYellow
.
black
(
'
'
+
Math
.
round
(
100
*
bytesSent
/
details
.
size
).
toString
().
padStart
(
3
,
'
'
)
+
'
%
'
)
+
'
'
+
details
.
name
,
true
)
transfer
.
write
(
Buffer
.
from
(
chunk
))
this
.
showMessage
(
terminal
,
colors
.
bgYellow
.
black
(
'
'
+
Math
.
round
(
100
*
transfer
.
getCompletedBytes
()
/
details
.
size
).
toString
().
padStart
(
3
,
'
'
)
+
'
%
'
)
+
'
'
+
details
.
name
,
true
)
},
}),
this
.
cancelEvent
.
toPromise
(),
this
.
cancelEvent
.
pipe
(
first
()).
toPromise
(),
])
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if
(
canceled
)
{
transfer
.
cancel
()
this
.
showMessage
(
terminal
,
colors
.
bgRed
.
black
(
'
Canceled
'
)
+
'
'
+
details
.
name
)
}
else
{
transfer
.
close
()
this
.
showMessage
(
terminal
,
colors
.
bgGreen
.
black
(
'
Received
'
)
+
'
'
+
details
.
name
)
}
}
catch
{
...
...
@@ -166,7 +158,6 @@ export class ZModemDecorator extends TerminalDecorator {
}
cancelSubscription
.
unsubscribe
()
stream
.
end
()
}
private
async
sendFile
(
terminal
,
zsession
,
transfer
:
FileUpload
,
filesRemaining
,
sizeRemaining
)
{
...
...
@@ -191,6 +182,7 @@ export class ZModemDecorator extends TerminalDecorator {
while
(
true
)
{
const
chunk
=
await
transfer
.
read
()
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if
(
canceled
||
!
chunk
.
length
)
{
break
}
...
...
@@ -199,6 +191,7 @@ export class ZModemDecorator extends TerminalDecorator {
this
.
showMessage
(
terminal
,
colors
.
bgYellow
.
black
(
'
'
+
Math
.
round
(
100
*
transfer
.
getCompletedBytes
()
/
offer
.
size
).
toString
().
padStart
(
3
,
'
'
)
+
'
%
'
)
+
offer
.
name
,
true
)
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if
(
canceled
)
{
transfer
.
cancel
()
}
else
{
...
...
@@ -216,6 +209,7 @@ export class ZModemDecorator extends TerminalDecorator {
cancelSubscription
.
unsubscribe
()
}
else
{
transfer
.
cancel
()
this
.
showMessage
(
terminal
,
colors
.
bgRed
.
black
(
'
Rejected
'
)
+
'
'
+
offer
.
name
)
this
.
logger
.
warn
(
'
rejected by the other side
'
)
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录