Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
d00f117c
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d00f117c
编写于
2月 21, 2020
作者:
R
rebornix
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Mimetype picker first cut.
上级
09a81431
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
508 addition
and
165 deletion
+508
-165
extensions/notebook-renderers/package.json
extensions/notebook-renderers/package.json
+13
-0
extensions/notebook-renderers/src/extension.ts
extensions/notebook-renderers/src/extension.ts
+1
-0
extensions/notebook-test/package.json
extensions/notebook-test/package.json
+13
-0
extensions/notebook-test/src/extension.ts
extensions/notebook-test/src/extension.ts
+19
-0
src/vs/vscode.proposed.d.ts
src/vs/vscode.proposed.d.ts
+1
-1
src/vs/workbench/api/browser/mainThreadNotebook.ts
src/vs/workbench/api/browser/mainThreadNotebook.ts
+2
-2
src/vs/workbench/api/common/extHost.api.impl.ts
src/vs/workbench/api/common/extHost.api.impl.ts
+2
-2
src/vs/workbench/api/common/extHost.protocol.ts
src/vs/workbench/api/common/extHost.protocol.ts
+1
-1
src/vs/workbench/api/common/extHostNotebook.ts
src/vs/workbench/api/common/extHostNotebook.ts
+39
-20
src/vs/workbench/contrib/notebook/browser/extensionPoint.ts
src/vs/workbench/contrib/notebook/browser/extensionPoint.ts
+63
-14
src/vs/workbench/contrib/notebook/browser/notebook.css
src/vs/workbench/contrib/notebook/browser/notebook.css
+10
-0
src/vs/workbench/contrib/notebook/browser/notebookService.ts
src/vs/workbench/contrib/notebook/browser/notebookService.ts
+54
-8
src/vs/workbench/contrib/notebook/browser/output/outputRenderer.ts
...rkbench/contrib/notebook/browser/output/outputRenderer.ts
+2
-2
src/vs/workbench/contrib/notebook/browser/output/transforms/richTransform.ts
...ntrib/notebook/browser/output/transforms/richTransform.ts
+145
-105
src/vs/workbench/contrib/notebook/browser/renderers/cellRenderer.ts
...kbench/contrib/notebook/browser/renderers/cellRenderer.ts
+1
-1
src/vs/workbench/contrib/notebook/browser/renderers/codeCell.ts
.../workbench/contrib/notebook/browser/renderers/codeCell.ts
+107
-5
src/vs/workbench/contrib/notebook/common/notebookCommon.ts
src/vs/workbench/contrib/notebook/common/notebookCommon.ts
+5
-4
src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts
...rkbench/contrib/notebook/common/notebookOutputRenderer.ts
+30
-0
未找到文件。
extensions/notebook-renderers/package.json
浏览文件 @
d00f117c
...
...
@@ -22,6 +22,19 @@
"*"
],
"contributes"
:
{
"notebookOutputRenderer"
:
[
{
"viewType"
:
"nteract"
,
"displayName"
:
"nteract renderer for notebook"
,
"mimeTypes"
:
[
"text/latex"
,
"text/markdown"
,
"application/json"
,
"application/vnd.plotly.v1+json"
,
"application/vnd.vega.v5+json"
]
}
]
},
"scripts"
:
{
"compile"
:
"tsc -p ./"
,
...
...
extensions/notebook-renderers/src/extension.ts
浏览文件 @
d00f117c
...
...
@@ -10,6 +10,7 @@ export function activate(context: vscode.ExtensionContext) {
console
.
log
(
context
.
extensionPath
);
context
.
subscriptions
.
push
(
vscode
.
window
.
registerNotebookOutputRenderer
(
'
nteract
'
,
{
type
:
'
display_data
'
,
subTypes
:
[
...
...
extensions/notebook-test/package.json
浏览文件 @
d00f117c
...
...
@@ -49,6 +49,19 @@
}
]
}
],
"notebookOutputRenderer"
:
[
{
"viewType"
:
"kerneltest"
,
"displayName"
:
"kernel test renderer for notebook"
,
"mimeTypes"
:
[
"text/latex"
,
"text/markdown"
,
"application/json"
,
"application/vnd.plotly.v1+json"
,
"application/vnd.vega.v5+json"
]
}
]
},
"scripts"
:
{
...
...
extensions/notebook-test/src/extension.ts
浏览文件 @
d00f117c
...
...
@@ -14,6 +14,25 @@ export function activate(context: vscode.ExtensionContext) {
context
.
subscriptions
.
push
(
vscode
.
window
.
registerNotebookProvider
(
'
jupyter
'
,
new
NotebookProvider
(
context
.
extensionPath
,
true
)));
context
.
subscriptions
.
push
(
vscode
.
window
.
registerNotebookProvider
(
'
jupytertest
'
,
new
NotebookProvider
(
context
.
extensionPath
,
false
)));
context
.
subscriptions
.
push
(
vscode
.
window
.
registerNotebookOutputRenderer
(
'
kerneltest
'
,
{
type
:
'
display_data
'
,
subTypes
:
[
'
text/latex
'
,
'
text/markdown
'
,
'
application/json
'
,
'
application/vnd.plotly.v1+json
'
,
'
application/vnd.vega.v5+json
'
]
},
{
render
:
()
=>
{
return
'
<h1>kernel test renderer</h1>
'
;
}
}
));
vscode
.
commands
.
registerCommand
(
'
notebook.saveToMarkdown
'
,
()
=>
{
if
(
vscode
.
window
.
activeNotebookDocument
)
{
let
document
=
vscode
.
window
.
activeNotebookDocument
;
...
...
src/vs/vscode.proposed.d.ts
浏览文件 @
d00f117c
...
...
@@ -1443,7 +1443,7 @@ declare module 'vscode' {
provider
:
NotebookProvider
):
Disposable
;
export
function
registerNotebookOutputRenderer
(
outputSelector
:
NotebookOutputSelector
,
renderer
:
NotebookOutputRenderer
):
Disposable
;
export
function
registerNotebookOutputRenderer
(
type
:
string
,
outputSelector
:
NotebookOutputSelector
,
renderer
:
NotebookOutputRenderer
):
Disposable
;
export
let
activeNotebookDocument
:
NotebookDocument
|
undefined
;
}
...
...
src/vs/workbench/api/browser/mainThreadNotebook.ts
浏览文件 @
d00f117c
...
...
@@ -228,8 +228,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
});
}
async
$registerNotebookRenderer
(
extension
:
NotebookExtensionDescription
,
selectors
:
INotebookMimeTypeSelector
,
handle
:
number
,
preloads
:
UriComponents
[]):
Promise
<
void
>
{
this
.
_notebookService
.
registerNotebookRenderer
(
handle
,
extension
,
selectors
,
preloads
.
map
(
uri
=>
URI
.
revive
(
uri
)));
async
$registerNotebookRenderer
(
extension
:
NotebookExtensionDescription
,
type
:
string
,
selectors
:
INotebookMimeTypeSelector
,
handle
:
number
,
preloads
:
UriComponents
[]):
Promise
<
void
>
{
this
.
_notebookService
.
registerNotebookRenderer
(
handle
,
extension
,
type
,
selectors
,
preloads
.
map
(
uri
=>
URI
.
revive
(
uri
)));
}
async
$unregisterNotebookRenderer
(
handle
:
number
):
Promise
<
void
>
{
...
...
src/vs/workbench/api/common/extHost.api.impl.ts
浏览文件 @
d00f117c
...
...
@@ -583,8 +583,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerNotebookProvider
:
(
viewType
:
string
,
provider
:
vscode
.
NotebookProvider
)
=>
{
return
extHostNotebook
.
registerNotebookProvider
(
extension
,
viewType
,
provider
);
},
registerNotebookOutputRenderer
:
(
outputFilter
:
vscode
.
NotebookOutputSelector
,
renderer
:
vscode
.
NotebookOutputRenderer
)
=>
{
return
extHostNotebook
.
registerNotebookOutputRenderer
(
extension
,
outputFilter
,
renderer
);
registerNotebookOutputRenderer
:
(
type
:
string
,
outputFilter
:
vscode
.
NotebookOutputSelector
,
renderer
:
vscode
.
NotebookOutputRenderer
)
=>
{
return
extHostNotebook
.
registerNotebookOutputRenderer
(
type
,
extension
,
outputFilter
,
renderer
);
},
get
activeNotebookDocument
():
vscode
.
NotebookDocument
|
undefined
{
return
extHostNotebook
.
activeNotebookDocument
;
...
...
src/vs/workbench/api/common/extHost.protocol.ts
浏览文件 @
d00f117c
...
...
@@ -654,7 +654,7 @@ export type NotebookCellOutputsSplice = [
export
interface
MainThreadNotebookShape
extends
IDisposable
{
$registerNotebookProvider
(
extension
:
NotebookExtensionDescription
,
viewType
:
string
):
Promise
<
void
>
;
$unregisterNotebookProvider
(
viewType
:
string
):
Promise
<
void
>
;
$registerNotebookRenderer
(
extension
:
NotebookExtensionDescription
,
selectors
:
INotebookMimeTypeSelector
,
handle
:
number
,
preloads
:
UriComponents
[]):
Promise
<
void
>
;
$registerNotebookRenderer
(
extension
:
NotebookExtensionDescription
,
type
:
string
,
selectors
:
INotebookMimeTypeSelector
,
handle
:
number
,
preloads
:
UriComponents
[]):
Promise
<
void
>
;
$unregisterNotebookRenderer
(
handle
:
number
):
Promise
<
void
>
;
$createNotebookDocument
(
handle
:
number
,
viewType
:
string
,
resource
:
UriComponents
):
Promise
<
void
>
;
$updateNotebookLanguages
(
viewType
:
string
,
resource
:
UriComponents
,
languages
:
string
[]):
Promise
<
void
>
;
...
...
src/vs/workbench/api/common/extHostNotebook.ts
浏览文件 @
d00f117c
...
...
@@ -239,20 +239,23 @@ export class ExtHostNotebookDocument implements vscode.NotebookDocument {
outputs
=
outputs
.
map
(
output
=>
{
let
richestMimeType
:
string
|
undefined
=
undefined
;
if
(
this
.
renderingHandler
.
outputDisplayOrder
?.
userOrder
||
this
.
_parsedDisplayOrder
.
length
>
0
)
{
if
(
this
.
renderingHandler
.
outputDisplayOrder
?.
defaultOrder
||
this
.
renderingHandler
.
outputDisplayOrder
?.
userOrder
||
this
.
_parsedDisplayOrder
.
length
>
0
)
{
richestMimeType
=
this
.
findRichestMimeType
(
output
);
}
output
.
pickedMimeType
=
richestMimeType
;
let
transformedOutput
:
vscode
.
CellOutput
|
undefined
=
undefined
;
if
(
richestMimeType
)
{
let
handler
=
this
.
renderingHandler
.
findBestMatchedRenderer
(
richestMimeType
);
if
(
handler
)
{
renderers
.
add
(
handler
.
handle
);
transformedOutput
=
handler
?
.
render
(
this
,
cell
,
output
);
if
(
handler
.
length
)
{
renderers
.
add
(
handler
[
0
]
.
handle
);
transformedOutput
=
handler
[
0
]
.
render
(
this
,
cell
,
output
);
output
=
transformedOutput
;
output
.
pickedMimeType
=
richestMimeType
;
output
.
pickedRenderer
=
handler
[
0
].
handle
;
// output.transformedOutput = transformedOutput;
output
.
transformedOutput
=
{
richestMimeType
:
transformedOutput
};
}
}
...
...
@@ -289,20 +292,23 @@ export class ExtHostNotebookDocument implements vscode.NotebookDocument {
outputs
=
outputs
.
map
(
output
=>
{
let
richestMimeType
:
string
|
undefined
=
undefined
;
if
(
this
.
renderingHandler
.
outputDisplayOrder
?.
userOrder
||
this
.
_parsedDisplayOrder
.
length
>
0
)
{
if
(
this
.
renderingHandler
.
outputDisplayOrder
?.
defaultOrder
||
this
.
renderingHandler
.
outputDisplayOrder
?.
userOrder
||
this
.
_parsedDisplayOrder
.
length
>
0
)
{
richestMimeType
=
this
.
findRichestMimeType
(
output
);
}
(
<
IGenericOutput
>
output
).
pickedMimeType
=
richestMimeType
;
let
transformedOutput
:
vscode
.
CellOutput
|
undefined
=
undefined
;
if
(
richestMimeType
)
{
let
handler
=
this
.
renderingHandler
.
findBestMatchedRenderer
(
richestMimeType
);
if
(
handler
)
{
renderers
.
add
(
handler
.
handle
);
transformedOutput
=
handler
?.
render
(
this
,
cell
,
output
);
if
(
handler
.
length
)
{
let
pickedHandler
=
handler
[
0
];
renderers
.
add
(
pickedHandler
.
handle
);
transformedOutput
=
pickedHandler
.
render
(
this
,
cell
,
output
);
(
<
IGenericOutput
>
output
).
pickedRenderer
=
pickedHandler
.
handle
;
(
<
IGenericOutput
>
output
).
transformedOutput
=
{
richestMimeType
:
transformedOutput
};
output
=
transformedOutput
;
(
<
IGenericOutput
>
output
).
pickedMimeType
=
richestMimeType
;
}
}
...
...
@@ -383,6 +389,16 @@ export class ExtHostNotebookDocument implements vscode.NotebookDocument {
order
++
;
}
let
defaultOrder
=
coreDisplayOrder
.
defaultOrder
;
for
(
let
i
=
0
;
i
<
defaultOrder
.
length
;
i
++
)
{
if
(
defaultOrder
[
i
](
mimeType
))
{
return
order
;
}
order
++
;
}
}
return
order
;
...
...
@@ -486,8 +502,9 @@ export class ExtHostNotebookOutputRenderer {
readonly
handle
=
ExtHostNotebookOutputRenderer
.
_handlePool
++
;
constructor
(
private
filter
:
vscode
.
NotebookOutputSelector
,
private
renderer
:
vscode
.
NotebookOutputRenderer
public
type
:
string
,
public
filter
:
vscode
.
NotebookOutputSelector
,
public
renderer
:
vscode
.
NotebookOutputRenderer
)
{
}
...
...
@@ -517,7 +534,7 @@ export class ExtHostNotebookOutputRenderer {
export
interface
ExtHostNotebookOutputRenderingHandler
{
outputDisplayOrder
:
ExtHostOutputDisplayOrder
|
undefined
;
findBestMatchedRenderer
(
mimeType
:
string
):
ExtHostNotebookOutputRenderer
|
undefined
;
findBestMatchedRenderer
(
mimeType
:
string
):
ExtHostNotebookOutputRenderer
[]
;
}
export
class
ExtHostNotebookController
implements
ExtHostNotebookShape
,
ExtHostNotebookOutputRenderingHandler
{
...
...
@@ -545,27 +562,29 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
registerNotebookOutputRenderer
(
type
:
string
,
extension
:
IExtensionDescription
,
filter
:
vscode
.
NotebookOutputSelector
,
renderer
:
vscode
.
NotebookOutputRenderer
):
vscode
.
Disposable
{
let
extHostRenderer
=
new
ExtHostNotebookOutputRenderer
(
filter
,
renderer
);
let
extHostRenderer
=
new
ExtHostNotebookOutputRenderer
(
type
,
filter
,
renderer
);
this
.
_notebookOutputRenderers
.
set
(
extHostRenderer
.
handle
,
extHostRenderer
);
this
.
_proxy
.
$registerNotebookRenderer
({
id
:
extension
.
identifier
,
location
:
extension
.
extensionLocation
},
filter
,
extHostRenderer
.
handle
,
renderer
.
preloads
||
[]);
this
.
_proxy
.
$registerNotebookRenderer
({
id
:
extension
.
identifier
,
location
:
extension
.
extensionLocation
},
type
,
filter
,
extHostRenderer
.
handle
,
renderer
.
preloads
||
[]);
return
new
VSCodeDisposable
(()
=>
{
this
.
_notebookOutputRenderers
.
delete
(
extHostRenderer
.
handle
);
this
.
_proxy
.
$unregisterNotebookRenderer
(
extHostRenderer
.
handle
);
});
}
findBestMatchedRenderer
(
mimeType
:
string
):
ExtHostNotebookOutputRenderer
|
undefined
{
findBestMatchedRenderer
(
mimeType
:
string
):
ExtHostNotebookOutputRenderer
[]
{
let
matches
:
ExtHostNotebookOutputRenderer
[]
=
[];
for
(
let
renderer
of
this
.
_notebookOutputRenderers
)
{
if
(
renderer
[
1
].
matches
(
mimeType
))
{
return
renderer
[
1
]
;
matches
.
push
(
renderer
[
1
])
;
}
}
return
;
return
matches
;
}
registerNotebookProvider
(
...
...
src/vs/workbench/contrib/notebook/browser/extensionPoint.ts
浏览文件 @
d00f117c
...
...
@@ -6,7 +6,6 @@
import
{
IJSONSchema
}
from
'
vs/base/common/jsonSchema
'
;
import
*
as
nls
from
'
vs/nls
'
;
import
{
ExtensionsRegistry
}
from
'
vs/workbench/services/extensions/common/extensionsRegistry
'
;
import
{
languagesExtPoint
}
from
'
vs/workbench/services/mode/common/workbenchModeService
'
;
import
{
NotebookSelector
}
from
'
vs/workbench/contrib/notebook/common/notebookProvider
'
;
namespace
NotebookEditorContribution
{
...
...
@@ -15,15 +14,28 @@ namespace NotebookEditorContribution {
export
const
selector
=
'
selector
'
;
}
interface
INotebookEditorContribution
{
readonly
[
NotebookEditorContribution
.
viewType
]:
string
;
readonly
[
NotebookEditorContribution
.
displayName
]:
string
;
readonly
[
NotebookEditorContribution
.
selector
]?:
readonly
NotebookSelector
[];
}
const
notebookContribution
:
IJSONSchema
=
{
description
:
nls
.
localize
(
'
contributes.notebook
'
,
'
Contributes notebook.
'
),
namespace
NotebookRendererContribution
{
export
const
viewType
=
'
viewType
'
;
export
const
displayName
=
'
displayName
'
;
export
const
mimeTypes
=
'
mimeTypes
'
;
}
interface
INotebookRendererContribution
{
readonly
[
NotebookRendererContribution
.
viewType
]:
string
;
readonly
[
NotebookRendererContribution
.
displayName
]:
string
;
readonly
[
NotebookRendererContribution
.
mimeTypes
]?:
readonly
string
[];
}
const
notebookProviderContribution
:
IJSONSchema
=
{
description
:
nls
.
localize
(
'
contributes.notebook.provider
'
,
'
Contributes notebook document provider.
'
),
type
:
'
array
'
,
defaultSnippets
:
[{
body
:
[{
viewType
:
''
,
displayName
:
''
}]
}],
items
:
{
...
...
@@ -36,25 +48,25 @@ const notebookContribution: IJSONSchema = {
properties
:
{
[
NotebookEditorContribution
.
viewType
]:
{
type
:
'
string
'
,
description
:
nls
.
localize
(
'
contributes.notebook.viewType
'
,
'
Unique identifier of the notebook.
'
),
description
:
nls
.
localize
(
'
contributes.notebook.
provider.
viewType
'
,
'
Unique identifier of the notebook.
'
),
},
[
NotebookEditorContribution
.
displayName
]:
{
type
:
'
string
'
,
description
:
nls
.
localize
(
'
contributes.notebook.displayName
'
,
'
Human readable name of the notebook.
'
),
description
:
nls
.
localize
(
'
contributes.notebook.
provider.
displayName
'
,
'
Human readable name of the notebook.
'
),
},
[
NotebookEditorContribution
.
selector
]:
{
type
:
'
array
'
,
description
:
nls
.
localize
(
'
contributes.notebook.selector
'
,
'
Set of globs that the notebook is for.
'
),
description
:
nls
.
localize
(
'
contributes.notebook.
provider.
selector
'
,
'
Set of globs that the notebook is for.
'
),
items
:
{
type
:
'
object
'
,
properties
:
{
filenamePattern
:
{
type
:
'
string
'
,
description
:
nls
.
localize
(
'
contributes.notebook.selector.filenamePattern
'
,
'
Glob that the notebook is enabled for.
'
),
description
:
nls
.
localize
(
'
contributes.notebook.
provider.
selector.filenamePattern
'
,
'
Glob that the notebook is enabled for.
'
),
},
excludeFileNamePattern
:
{
type
:
'
string
'
,
description
:
nls
.
localize
(
'
contributes.notebook.selector.excludeFileNamePattern
'
,
'
Glob that the notebook is disabled for.
'
)
description
:
nls
.
localize
(
'
contributes.notebook.selector.
provider.
excludeFileNamePattern
'
,
'
Glob that the notebook is disabled for.
'
)
}
}
}
...
...
@@ -63,8 +75,45 @@ const notebookContribution: IJSONSchema = {
}
};
export
const
notebookExtensionPoint
=
ExtensionsRegistry
.
registerExtensionPoint
<
INotebookEditorContribution
[]
>
({
extensionPoint
:
'
notebookProvider
'
,
deps
:
[
languagesExtPoint
],
jsonSchema
:
notebookContribution
});
const
notebookRendererContribution
:
IJSONSchema
=
{
description
:
nls
.
localize
(
'
contributes.notebook.renderer
'
,
'
Contributes notebook output renderer provider.
'
),
type
:
'
array
'
,
defaultSnippets
:
[{
body
:
[{
viewType
:
''
,
displayName
:
''
,
mimeTypes
:
[
''
]
}]
}],
items
:
{
type
:
'
object
'
,
required
:
[
NotebookRendererContribution
.
viewType
,
NotebookRendererContribution
.
displayName
,
NotebookRendererContribution
.
mimeTypes
,
],
properties
:
{
[
NotebookRendererContribution
.
viewType
]:
{
type
:
'
string
'
,
description
:
nls
.
localize
(
'
contributes.notebook.renderer.viewType
'
,
'
Unique identifier of the notebook output renderer.
'
),
},
[
NotebookRendererContribution
.
displayName
]:
{
type
:
'
string
'
,
description
:
nls
.
localize
(
'
contributes.notebook.renderer.displayName
'
,
'
Human readable name of the notebook output renderer.
'
),
},
[
NotebookRendererContribution
.
mimeTypes
]:
{
type
:
'
array
'
,
description
:
nls
.
localize
(
'
contributes.notebook.selector
'
,
'
Set of globs that the notebook is for.
'
),
items
:
{
type
:
'
string
'
}
}
}
}
};
export
const
notebookProviderExtensionPoint
=
ExtensionsRegistry
.
registerExtensionPoint
<
INotebookEditorContribution
[]
>
(
{
extensionPoint
:
'
notebookProvider
'
,
jsonSchema
:
notebookProviderContribution
});
export
const
notebookRendererExtensionPoint
=
ExtensionsRegistry
.
registerExtensionPoint
<
INotebookRendererContribution
[]
>
(
{
extensionPoint
:
'
notebookOutputRenderer
'
,
jsonSchema
:
notebookRendererContribution
});
src/vs/workbench/contrib/notebook/browser/notebook.css
浏览文件 @
d00f117c
...
...
@@ -37,6 +37,7 @@
padding-right
:
8px
;
user-select
:
text
;
transform
:
translate3d
(
0px
,
0px
,
0px
);
cursor
:
auto
;
}
.monaco-workbench
.part.editor
>
.content
.notebook-editor
.output
p
{
...
...
@@ -45,6 +46,15 @@
margin
:
0px
;
}
.monaco-workbench
.part.editor
>
.content
.notebook-editor
.output
.multi-mimetype-output
{
position
:
absolute
;
top
:
4px
;
left
:
-24px
;
width
:
16px
;
height
:
16px
;
cursor
:
pointer
;
}
.monaco-workbench
.part.editor
>
.content
.notebook-editor
.output
.error_message
{
color
:
red
;
}
...
...
src/vs/workbench/contrib/notebook/browser/notebookService.ts
浏览文件 @
d00f117c
...
...
@@ -6,12 +6,13 @@
import
{
Disposable
,
IDisposable
,
DisposableStore
}
from
'
vs/base/common/lifecycle
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
notebookExtensionPoint
}
from
'
vs/workbench/contrib/notebook/browser/extensionPoint
'
;
import
{
notebook
ProviderExtensionPoint
,
notebookRenderer
ExtensionPoint
}
from
'
vs/workbench/contrib/notebook/browser/extensionPoint
'
;
import
{
NotebookProviderInfo
}
from
'
vs/workbench/contrib/notebook/common/notebookProvider
'
;
import
{
NotebookExtensionDescription
}
from
'
vs/workbench/api/common/extHost.protocol
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
INotebook
,
ICell
,
INotebookMimeTypeSelector
}
from
'
vs/workbench/contrib/notebook/common/notebookCommon
'
;
import
{
IExtensionService
}
from
'
vs/workbench/services/extensions/common/extensions
'
;
import
{
NotebookOutputRendererInfo
}
from
'
vs/workbench/contrib/notebook/common/notebookOutputRenderer
'
;
function
MODEL_ID
(
resource
:
URI
):
string
{
return
resource
.
toString
();
...
...
@@ -35,7 +36,7 @@ export interface INotebookService {
onDidChangeActiveEditor
:
Event
<
{
viewType
:
string
,
uri
:
URI
}
>
;
registerNotebookController
(
viewType
:
string
,
extensionData
:
NotebookExtensionDescription
,
controller
:
IMainNotebookController
):
void
;
unregisterNotebookProvider
(
viewType
:
string
):
void
;
registerNotebookRenderer
(
handle
:
number
,
extensionData
:
NotebookExtensionDescription
,
selectors
:
INotebookMimeTypeSelector
,
preloads
:
URI
[]):
void
;
registerNotebookRenderer
(
handle
:
number
,
extensionData
:
NotebookExtensionDescription
,
type
:
string
,
selectors
:
INotebookMimeTypeSelector
,
preloads
:
URI
[]):
void
;
unregisterNotebookRenderer
(
handle
:
number
):
void
;
getRendererPreloads
(
handle
:
number
):
URI
[];
resolveNotebook
(
viewType
:
string
,
uri
:
URI
):
Promise
<
INotebook
|
undefined
>
;
...
...
@@ -50,7 +51,7 @@ export interface INotebookService {
updateActiveNotebookDocument
(
viewType
:
string
,
resource
:
URI
):
void
;
}
export
class
NotebookInfoStore
{
export
class
Notebook
Provider
InfoStore
{
private
readonly
contributedEditors
=
new
Map
<
string
,
NotebookProviderInfo
>
();
clear
()
{
...
...
@@ -75,6 +76,31 @@ export class NotebookInfoStore {
}
}
export
class
NotebookOutputRendererInfoStore
{
private
readonly
contributedRenderers
=
new
Map
<
string
,
NotebookOutputRendererInfo
>
();
clear
()
{
this
.
contributedRenderers
.
clear
();
}
get
(
viewType
:
string
):
NotebookOutputRendererInfo
|
undefined
{
return
this
.
contributedRenderers
.
get
(
viewType
);
}
add
(
info
:
NotebookOutputRendererInfo
):
void
{
if
(
this
.
contributedRenderers
.
has
(
info
.
id
))
{
console
.
log
(
`Custom notebook output renderer with id '
${
info
.
id
}
' already registered`
);
return
;
}
this
.
contributedRenderers
.
set
(
info
.
id
,
info
);
}
getContributedRenderer
(
mimeType
:
string
):
readonly
NotebookOutputRendererInfo
[]
{
return
Array
.
from
(
this
.
contributedRenderers
.
values
()).
filter
(
customEditor
=>
customEditor
.
matches
(
mimeType
));
}
}
class
ModelData
implements
IDisposable
{
private
readonly
_modelEventListeners
=
new
DisposableStore
();
...
...
@@ -94,8 +120,9 @@ class ModelData implements IDisposable {
export
class
NotebookService
extends
Disposable
implements
INotebookService
{
_serviceBrand
:
undefined
;
private
readonly
_notebookProviders
=
new
Map
<
string
,
{
controller
:
IMainNotebookController
,
extensionData
:
NotebookExtensionDescription
}
>
();
private
readonly
_notebookRenderers
=
new
Map
<
number
,
{
extensionData
:
NotebookExtensionDescription
,
selectors
:
INotebookMimeTypeSelector
,
preloads
:
URI
[]
}
>
();
notebookProviderInfoStore
:
NotebookInfoStore
=
new
NotebookInfoStore
();
private
readonly
_notebookRenderers
=
new
Map
<
number
,
{
extensionData
:
NotebookExtensionDescription
,
type
:
string
,
selectors
:
INotebookMimeTypeSelector
,
preloads
:
URI
[]
}
>
();
notebookProviderInfoStore
:
NotebookProviderInfoStore
=
new
NotebookProviderInfoStore
();
notebookRenderersInfoStore
:
NotebookOutputRendererInfoStore
=
new
NotebookOutputRendererInfoStore
();
private
readonly
_models
:
{
[
modelId
:
string
]:
ModelData
;
};
private
_onDidChangeActiveEditor
=
new
Emitter
<
{
viewType
:
string
,
uri
:
URI
}
>
();
onDidChangeActiveEditor
:
Event
<
{
viewType
:
string
,
uri
:
URI
}
>
=
this
.
_onDidChangeActiveEditor
.
event
;
...
...
@@ -107,7 +134,7 @@ export class NotebookService extends Disposable implements INotebookService {
super
();
this
.
_models
=
{};
notebookExtensionPoint
.
setHandler
((
extensions
)
=>
{
notebook
Provider
ExtensionPoint
.
setHandler
((
extensions
)
=>
{
this
.
notebookProviderInfoStore
.
clear
();
for
(
const
extension
of
extensions
)
{
...
...
@@ -122,6 +149,21 @@ export class NotebookService extends Disposable implements INotebookService {
// console.log(this._notebookProviderInfoStore);
});
notebookRendererExtensionPoint
.
setHandler
((
renderers
)
=>
{
this
.
notebookRenderersInfoStore
.
clear
();
for
(
const
extension
of
renderers
)
{
for
(
const
notebookContribution
of
extension
.
value
)
{
this
.
notebookRenderersInfoStore
.
add
(
new
NotebookOutputRendererInfo
({
id
:
notebookContribution
.
viewType
,
displayName
:
notebookContribution
.
displayName
,
mimeTypes
:
notebookContribution
.
mimeTypes
||
[]
}));
}
}
// console.log(this.notebookRenderersInfoStore);
});
}
async
canResolve
(
viewType
:
string
):
Promise
<
void
>
{
...
...
@@ -151,8 +193,8 @@ export class NotebookService extends Disposable implements INotebookService {
this
.
_notebookProviders
.
delete
(
viewType
);
}
registerNotebookRenderer
(
handle
:
number
,
extensionData
:
NotebookExtensionDescription
,
selectors
:
INotebookMimeTypeSelector
,
preloads
:
URI
[])
{
this
.
_notebookRenderers
.
set
(
handle
,
{
extensionData
,
selectors
,
preloads
});
registerNotebookRenderer
(
handle
:
number
,
extensionData
:
NotebookExtensionDescription
,
type
:
string
,
selectors
:
INotebookMimeTypeSelector
,
preloads
:
URI
[])
{
this
.
_notebookRenderers
.
set
(
handle
,
{
extensionData
,
type
,
selectors
,
preloads
});
}
unregisterNotebookRenderer
(
handle
:
number
)
{
...
...
@@ -234,6 +276,10 @@ export class NotebookService extends Disposable implements INotebookService {
return
this
.
notebookProviderInfoStore
.
getContributedNotebook
(
resource
);
}
getContributedNotebookOutputRenderers
(
mimeType
:
string
):
readonly
NotebookOutputRendererInfo
[]
{
return
this
.
notebookRenderersInfoStore
.
getContributedRenderer
(
mimeType
);
}
getNotebookProviderResourceRoots
():
URI
[]
{
let
ret
:
URI
[]
=
[];
this
.
_notebookProviders
.
forEach
(
val
=>
{
...
...
src/vs/workbench/contrib/notebook/browser/output/outputRenderer.ts
浏览文件 @
d00f117c
...
...
@@ -45,11 +45,11 @@ export class OutputRenderer {
};
}
render
(
output
:
IOutput
,
container
:
HTMLElement
):
IRenderOutput
{
render
(
output
:
IOutput
,
container
:
HTMLElement
,
preferredMimeType
:
string
|
undefined
):
IRenderOutput
{
let
transform
=
this
.
_mimeTypeMapping
[
output
.
output_type
];
if
(
transform
)
{
return
transform
.
render
(
output
,
container
);
return
transform
.
render
(
output
,
container
,
preferredMimeType
);
}
else
{
return
this
.
renderNoop
(
output
,
container
);
}
...
...
src/vs/workbench/contrib/notebook/browser/output/transforms/richTransform.ts
浏览文件 @
d00f117c
...
...
@@ -18,6 +18,7 @@ import { URI } from 'vs/base/common/uri';
class
RichRenderer
implements
IOutputTransformContribution
{
private
_mdRenderer
:
marked
.
Renderer
=
new
marked
.
Renderer
({
gfm
:
true
});;
private
_richMimeTypeRenderers
=
new
Map
<
string
,
(
output
:
any
,
container
:
HTMLElement
)
=>
IRenderOutput
>
();
constructor
(
public
notebookEditor
:
INotebookEditor
,
...
...
@@ -25,119 +26,158 @@ class RichRenderer implements IOutputTransformContribution {
@
IModelService
private
readonly
modelService
:
IModelService
,
@
IModeService
private
readonly
modeService
:
IModeService
)
{
this
.
_richMimeTypeRenderers
.
set
(
'
application/json
'
,
this
.
renderJSON
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
application/javascript
'
,
this
.
renderJavaScript
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
text/html
'
,
this
.
renderHTML
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
image/svg+xml
'
,
this
.
renderSVG
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
text/markdown
'
,
this
.
renderMarkdown
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
image/png
'
,
this
.
renderPNG
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
image/jpeg
'
,
this
.
renderJavaScript
.
bind
(
this
));
this
.
_richMimeTypeRenderers
.
set
(
'
text/plain
'
,
this
.
renderPlainText
.
bind
(
this
));
}
render
(
output
:
any
,
container
:
HTMLElement
):
IRenderOutput
{
let
hasDynamicHeight
=
false
;
if
(
output
.
data
)
{
if
(
output
.
data
[
'
application/json
'
])
{
let
data
=
output
.
data
[
'
application/json
'
];
let
str
=
JSON
.
stringify
(
data
,
null
,
'
\t
'
);
const
editor
=
this
.
instantiationService
.
createInstance
(
CodeEditorWidget
,
container
,
{
...
getJSONSimpleEditorOptions
(),
dimension
:
{
width
:
0
,
height
:
0
}
},
{
isSimpleWidget
:
true
});
let
mode
=
this
.
modeService
.
create
(
'
json
'
);
let
resource
=
URI
.
parse
(
`notebook-output-
${
Date
.
now
()}
.json`
);
const
textModel
=
this
.
modelService
.
createModel
(
str
,
mode
,
resource
,
false
);
editor
.
setModel
(
textModel
);
let
width
=
this
.
notebookEditor
.
getListDimension
()
!
.
width
;
let
fontInfo
=
this
.
notebookEditor
.
getFontInfo
();
let
height
=
Math
.
min
(
textModel
.
getLineCount
(),
16
)
*
(
fontInfo
?.
lineHeight
||
18
);
editor
.
layout
({
height
,
width
});
container
.
style
.
height
=
`
${
height
+
16
}
px`
;
return
{
hasDynamicHeight
:
true
};
}
else
if
(
output
.
data
[
'
application/javascript
'
])
{
let
data
=
output
.
data
[
'
application/javascript
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
let
scriptVal
=
`<script type="application/javascript">
${
str
}
</script>`
;
hasDynamicHeight
=
false
;
return
{
shadowContent
:
scriptVal
,
hasDynamicHeight
};
}
else
if
(
output
.
data
[
'
text/html
'
])
{
let
data
=
output
.
data
[
'
text/html
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
hasDynamicHeight
=
false
;
return
{
shadowContent
:
str
,
hasDynamicHeight
};
}
else
if
(
output
.
data
[
'
image/svg+xml
'
])
{
let
data
=
output
.
data
[
'
image/svg+xml
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
hasDynamicHeight
=
false
;
return
{
shadowContent
:
str
,
hasDynamicHeight
};
}
else
if
(
output
.
data
[
'
text/markdown
'
])
{
let
data
=
output
.
data
[
'
text/markdown
'
];
const
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
const
mdOutput
=
document
.
createElement
(
'
div
'
);
mdOutput
.
innerHTML
=
marked
(
str
,
{
renderer
:
this
.
_mdRenderer
});
container
.
appendChild
(
mdOutput
);
hasDynamicHeight
=
true
;
}
else
if
(
output
.
data
[
'
image/png
'
])
{
const
image
=
document
.
createElement
(
'
img
'
);
image
.
src
=
`data:image/png;base64,
${
output
.
data
[
'
image/png
'
]}
`
;
const
display
=
document
.
createElement
(
'
div
'
);
DOM
.
addClasses
(
display
,
'
display
'
);
display
.
appendChild
(
image
);
container
.
appendChild
(
display
);
hasDynamicHeight
=
true
;
}
else
if
(
output
.
data
[
'
image/jpeg
'
])
{
const
image
=
document
.
createElement
(
'
img
'
);
image
.
src
=
`data:image/jpeg;base64,
${
output
.
data
[
'
image/jpeg
'
]}
`
;
const
display
=
document
.
createElement
(
'
div
'
);
DOM
.
addClasses
(
display
,
'
display
'
);
display
.
appendChild
(
image
);
container
.
appendChild
(
display
);
hasDynamicHeight
=
true
;
}
else
if
(
output
.
data
[
'
text/plain
'
])
{
let
data
=
output
.
data
[
'
text/plain
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
const
contentNode
=
document
.
createElement
(
'
p
'
);
contentNode
.
innerText
=
str
;
container
.
appendChild
(
contentNode
);
}
else
{
const
contentNode
=
document
.
createElement
(
'
p
'
);
let
mimeTypes
=
[];
for
(
const
property
in
output
.
data
)
{
mimeTypes
.
push
(
property
);
}
let
mimeTypesMessage
=
mimeTypes
.
join
(
'
,
'
);
contentNode
.
innerText
=
`No renderer could be found for output. It has the following MIME types:
${
mimeTypesMessage
}
`
;
container
.
appendChild
(
contentNode
);
}
}
else
{
render
(
output
:
any
,
container
:
HTMLElement
,
preferredMimeType
:
string
|
undefined
):
IRenderOutput
{
if
(
!
output
.
data
)
{
const
contentNode
=
document
.
createElement
(
'
p
'
);
contentNode
.
innerText
=
`No data could be found for output.`
;
container
.
appendChild
(
contentNode
);
return
{
hasDynamicHeight
:
false
};
}
if
(
!
preferredMimeType
||
!
this
.
_richMimeTypeRenderers
.
has
(
preferredMimeType
))
{
const
contentNode
=
document
.
createElement
(
'
p
'
);
let
mimeTypes
=
[];
for
(
const
property
in
output
.
data
)
{
mimeTypes
.
push
(
property
);
}
let
mimeTypesMessage
=
mimeTypes
.
join
(
'
,
'
);
contentNode
.
innerText
=
`No renderer could be found for output. It has the following MIME types:
${
mimeTypesMessage
}
`
;
container
.
appendChild
(
contentNode
);
return
{
hasDynamicHeight
:
false
};
}
let
renderer
=
this
.
_richMimeTypeRenderers
.
get
(
preferredMimeType
);
return
renderer
!
(
output
,
container
);
}
renderJSON
(
output
:
any
,
container
:
HTMLElement
)
{
let
data
=
output
.
data
[
'
application/json
'
];
let
str
=
JSON
.
stringify
(
data
,
null
,
'
\t
'
);
const
editor
=
this
.
instantiationService
.
createInstance
(
CodeEditorWidget
,
container
,
{
...
getJSONSimpleEditorOptions
(),
dimension
:
{
width
:
0
,
height
:
0
}
},
{
isSimpleWidget
:
true
});
let
mode
=
this
.
modeService
.
create
(
'
json
'
);
let
resource
=
URI
.
parse
(
`notebook-output-
${
Date
.
now
()}
.json`
);
const
textModel
=
this
.
modelService
.
createModel
(
str
,
mode
,
resource
,
false
);
editor
.
setModel
(
textModel
);
let
width
=
this
.
notebookEditor
.
getListDimension
()
!
.
width
;
let
fontInfo
=
this
.
notebookEditor
.
getFontInfo
();
let
height
=
Math
.
min
(
textModel
.
getLineCount
(),
16
)
*
(
fontInfo
?.
lineHeight
||
18
);
editor
.
layout
({
height
,
width
});
container
.
style
.
height
=
`
${
height
+
16
}
px`
;
return
{
hasDynamicHeight
:
true
};
}
renderJavaScript
(
output
:
any
,
container
:
HTMLElement
)
{
let
data
=
output
.
data
[
'
application/javascript
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
let
scriptVal
=
`<script type="application/javascript">
${
str
}
</script>`
;
return
{
shadowContent
:
scriptVal
,
hasDynamicHeight
:
false
};
}
renderHTML
(
output
:
any
,
container
:
HTMLElement
)
{
let
data
=
output
.
data
[
'
text/html
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
return
{
shadowContent
:
str
,
hasDynamicHeight
:
false
};
}
renderSVG
(
output
:
any
,
container
:
HTMLElement
)
{
let
data
=
output
.
data
[
'
image/svg+xml
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
return
{
shadowContent
:
str
,
hasDynamicHeight
:
false
};
}
renderMarkdown
(
output
:
any
,
container
:
HTMLElement
)
{
let
data
=
output
.
data
[
'
text/markdown
'
];
const
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
const
mdOutput
=
document
.
createElement
(
'
div
'
);
mdOutput
.
innerHTML
=
marked
(
str
,
{
renderer
:
this
.
_mdRenderer
});
container
.
appendChild
(
mdOutput
);
return
{
hasDynamicHeight
:
true
};
}
renderPNG
(
output
:
any
,
container
:
HTMLElement
)
{
const
image
=
document
.
createElement
(
'
img
'
);
image
.
src
=
`data:image/png;base64,
${
output
.
data
[
'
image/png
'
]}
`
;
const
display
=
document
.
createElement
(
'
div
'
);
DOM
.
addClasses
(
display
,
'
display
'
);
display
.
appendChild
(
image
);
container
.
appendChild
(
display
);
return
{
hasDynamicHeight
:
true
};
}
renderJPEG
(
output
:
any
,
container
:
HTMLElement
)
{
const
image
=
document
.
createElement
(
'
img
'
);
image
.
src
=
`data:image/jpeg;base64,
${
output
.
data
[
'
image/jpeg
'
]}
`
;
const
display
=
document
.
createElement
(
'
div
'
);
DOM
.
addClasses
(
display
,
'
display
'
);
display
.
appendChild
(
image
);
container
.
appendChild
(
display
);
return
{
hasDynamicHeight
:
true
};
}
renderPlainText
(
output
:
any
,
container
:
HTMLElement
)
{
let
data
=
output
.
data
[
'
text/plain
'
];
let
str
=
isArray
(
data
)
?
data
.
join
(
''
)
:
data
;
const
contentNode
=
document
.
createElement
(
'
p
'
);
contentNode
.
innerText
=
str
;
container
.
appendChild
(
contentNode
);
return
{
hasDynamicHeight
hasDynamicHeight
:
false
};
}
...
...
src/vs/workbench/contrib/notebook/browser/renderers/cellRenderer.ts
浏览文件 @
d00f117c
...
...
@@ -331,7 +331,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
this
.
showContextMenu
(
listIndex
,
element
,
e
.
posx
,
top
+
height
);
}));
elementDisposable
?.
add
(
new
CodeCell
(
this
.
notebookEditor
,
element
,
templateData
));
elementDisposable
?.
add
(
this
.
instantiationService
.
createInstance
(
CodeCell
,
this
.
notebookEditor
,
element
,
templateData
));
this
.
renderedEditors
.
set
(
element
,
templateData
.
editor
);
}
...
...
src/vs/workbench/contrib/notebook/browser/renderers/codeCell.ts
浏览文件 @
d00f117c
...
...
@@ -3,21 +3,25 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Disposable
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
*
as
nls
from
'
vs/nls
'
;
import
*
as
DOM
from
'
vs/base/browser/dom
'
;
import
{
Disposable
,
DisposableStore
}
from
'
vs/base/common/lifecycle
'
;
import
{
CellViewModel
}
from
'
vs/workbench/contrib/notebook/browser/renderers/cellViewModel
'
;
import
{
getResizesObserver
}
from
'
vs/workbench/contrib/notebook/browser/renderers/sizeObserver
'
;
import
{
CELL_MARGIN
,
IOutput
}
from
'
vs/workbench/contrib/notebook/common/notebookCommon
'
;
import
{
CELL_MARGIN
,
IOutput
,
IDisplayOutput
}
from
'
vs/workbench/contrib/notebook/common/notebookCommon
'
;
import
{
CellRenderTemplate
,
INotebookEditor
}
from
'
vs/workbench/contrib/notebook/browser/notebookBrowser
'
;
import
{
raceCancellation
}
from
'
vs/base/common/async
'
;
import
{
CancellationTokenSource
}
from
'
vs/base/common/cancellation
'
;
import
{
IQuickInputService
,
IQuickPickItem
}
from
'
vs/platform/quickinput/common/quickInput
'
;
export
class
CodeCell
extends
Disposable
{
private
outputResizeListeners
=
new
Map
<
IOutput
,
IDisposabl
e
>
();
private
outputResizeListeners
=
new
Map
<
IOutput
,
DisposableStor
e
>
();
private
outputElements
=
new
Map
<
IOutput
,
HTMLElement
>
();
constructor
(
private
notebookEditor
:
INotebookEditor
,
private
viewCell
:
CellViewModel
,
private
templateData
:
CellRenderTemplate
,
@
IQuickInputService
private
readonly
quickInputService
:
IQuickInputService
)
{
super
();
...
...
@@ -65,6 +69,10 @@ export class CodeCell extends Disposable {
viewCell
.
editorHeight
=
realContentHeight
;
}
if
(
this
.
notebookEditor
.
getActiveCell
()
===
this
.
viewCell
)
{
templateData
.
editor
?.
focus
();
}
}
});
...
...
@@ -187,8 +195,44 @@ export class CodeCell extends Disposable {
}
renderOutput
(
currOutput
:
IOutput
,
index
:
number
,
beforeElement
?:
HTMLElement
)
{
if
(
!
this
.
outputResizeListeners
.
has
(
currOutput
))
{
this
.
outputResizeListeners
.
set
(
currOutput
,
new
DisposableStore
());
}
let
outputItemDiv
=
document
.
createElement
(
'
div
'
);
let
result
=
this
.
notebookEditor
.
getOutputRenderer
().
render
(
currOutput
,
outputItemDiv
);
let
transformedOutput
:
IOutput
;
let
transformedMimeType
:
string
;
if
(
currOutput
.
pickedMimeType
)
{
if
(
currOutput
.
transformedOutput
&&
currOutput
.
transformedOutput
!
[
currOutput
.
pickedMimeType
])
{
// currently, transformed output is always text/html
transformedMimeType
=
'
text/html
'
;
transformedOutput
=
currOutput
.
transformedOutput
!
[
currOutput
.
pickedMimeType
];
}
else
{
// otherwise
transformedMimeType
=
currOutput
.
pickedMimeType
;
transformedOutput
=
currOutput
;
}
}
else
{
transformedOutput
=
currOutput
;
}
if
(
currOutput
.
output_type
===
'
display_data
'
||
currOutput
.
output_type
===
'
execute_result
'
)
{
let
mimeTypes
=
Object
.
keys
((
currOutput
!
as
IDisplayOutput
).
data
);
if
(
mimeTypes
.
length
>
1
)
{
outputItemDiv
.
style
.
position
=
'
relative
'
;
const
mimeTypePicker
=
DOM
.
$
(
'
.multi-mimetype-output
'
);
DOM
.
addClasses
(
mimeTypePicker
,
'
codicon
'
,
'
codicon-list-selection
'
);
outputItemDiv
.
appendChild
(
mimeTypePicker
);
this
.
outputResizeListeners
.
get
(
currOutput
)
!
.
add
(
DOM
.
addStandardDisposableListener
(
mimeTypePicker
,
'
mousedown
'
,
async
e
=>
{
e
.
preventDefault
();
e
.
stopPropagation
();
await
this
.
pickActiveMimeType
(
currOutput
,
mimeTypes
);
}));
}
}
let
result
=
this
.
notebookEditor
.
getOutputRenderer
().
render
(
transformedOutput
!
,
outputItemDiv
,
currOutput
.
pickedMimeType
);
if
(
!
result
)
{
this
.
viewCell
.
updateOutputHeight
(
index
,
0
);
...
...
@@ -239,7 +283,7 @@ export class CodeCell extends Disposable {
}
});
elementSizeObserver
.
startObserving
();
this
.
outputResizeListeners
.
set
(
currOutput
,
elementSizeObserver
);
this
.
outputResizeListeners
.
get
(
currOutput
)
!
.
add
(
elementSizeObserver
);
this
.
viewCell
.
updateOutputHeight
(
index
,
clientHeight
);
}
else
{
if
(
result
.
shadowContent
)
{
...
...
@@ -254,6 +298,64 @@ export class CodeCell extends Disposable {
}
}
async
pickActiveMimeType
(
output
:
IOutput
,
mimeTypes
:
string
[])
{
const
sorted
=
mimeTypes
.
sort
((
a
,
b
)
=>
{
if
(
a
===
output
.
pickedMimeType
)
{
return
-
1
;
}
else
{
return
0
;
}
});
const
items
=
sorted
.
map
((
mimeType
):
IQuickPickItem
=>
({
label
:
mimeType
,
id
:
mimeType
,
description
:
mimeType
===
output
.
pickedMimeType
?
nls
.
localize
(
'
curruentActiveMimeType
'
,
"
Currently Active
"
)
:
undefined
,
// buttons: resourceExt ? [{
// iconClass: 'codicon-settings-gear',
// tooltip: nls.localize('promptOpenWith.setDefaultTooltip', "Set as default editor for '{0}' files", resourceExt)
// }] : undefined
}));
const
picker
=
this
.
quickInputService
.
createQuickPick
();
picker
.
items
=
items
;
picker
.
placeholder
=
nls
.
localize
(
'
promptChooseMimeType.placeHolder
'
,
"
Select output mimetype to render for current output
"
);
const
pick
=
await
new
Promise
<
string
|
undefined
>
(
resolve
=>
{
picker
.
onDidAccept
(()
=>
{
resolve
(
picker
.
selectedItems
.
length
===
1
?
picker
.
selectedItems
[
0
].
id
:
undefined
);
picker
.
dispose
();
});
picker
.
show
();
});
if
(
!
pick
)
{
return
;
}
if
(
pick
!==
output
.
pickedMimeType
)
{
// user chooses another mimetype
let
index
=
this
.
viewCell
.
outputs
.
indexOf
(
output
);
let
nextElement
=
index
+
1
<
this
.
viewCell
.
outputs
.
length
?
this
.
outputElements
.
get
(
this
.
viewCell
.
outputs
[
index
+
1
])
:
undefined
;
this
.
outputResizeListeners
.
get
(
output
)?.
clear
();
let
element
=
this
.
outputElements
.
get
(
output
);
if
(
element
)
{
this
.
templateData
?.
outputContainer
?.
removeChild
(
element
);
this
.
notebookEditor
.
removeInset
(
output
);
}
output
.
pickedMimeType
=
pick
;
this
.
renderOutput
(
output
,
index
,
nextElement
);
let
editorHeight
=
this
.
viewCell
.
editorHeight
;
let
totalOutputHeight
=
this
.
viewCell
.
getOutputTotalHeight
();
this
.
notebookEditor
.
layoutNotebookCell
(
this
.
viewCell
,
editorHeight
+
32
+
totalOutputHeight
);
}
}
dispose
()
{
this
.
outputResizeListeners
.
forEach
((
value
)
=>
{
value
.
dispose
();
...
...
src/vs/workbench/contrib/notebook/common/notebookCommon.ts
浏览文件 @
d00f117c
...
...
@@ -69,11 +69,11 @@ export interface IErrorOutput {
* @internal
*/
export
interface
IDisplayOutput
{
output_type
:
'
display_data
'
;
output_type
:
'
display_data
'
|
'
execute_result
'
;
/**
* { mime_type: value }
*/
data
:
{
string
:
string
};
data
:
{
[
key
:
string
]:
any
;
}
}
/**
...
...
@@ -82,7 +82,8 @@ export interface IDisplayOutput {
export
interface
IGenericOutput
{
output_type
:
string
;
pickedMimeType
?:
string
;
// transformedOutput?: IGenericOutput;
pickedRenderer
?:
number
;
transformedOutput
?:
{
[
key
:
string
]:
IDisplayOutput
};
}
/**
...
...
@@ -146,7 +147,7 @@ export interface IOutputTransformContribution {
*/
dispose
():
void
;
render
(
output
:
IOutput
,
container
:
HTMLElement
):
IRenderOutput
;
render
(
output
:
IOutput
,
container
:
HTMLElement
,
preferredMimeType
:
string
|
undefined
):
IRenderOutput
;
}
...
...
src/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts
0 → 100644
浏览文件 @
d00f117c
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
glob
from
'
vs/base/common/glob
'
;
export
class
NotebookOutputRendererInfo
{
readonly
id
:
string
;
readonly
displayName
:
string
;
readonly
mimeTypes
:
readonly
string
[];
readonly
mimeTypeGlobs
:
glob
.
ParsedPattern
[];
constructor
(
descriptor
:
{
readonly
id
:
string
;
readonly
displayName
:
string
;
readonly
mimeTypes
:
readonly
string
[];
})
{
this
.
id
=
descriptor
.
id
;
this
.
displayName
=
descriptor
.
displayName
;
this
.
mimeTypes
=
descriptor
.
mimeTypes
;
this
.
mimeTypeGlobs
=
this
.
mimeTypes
.
map
(
pattern
=>
glob
.
parse
(
pattern
));
}
matches
(
mimeType
:
string
)
{
let
matched
=
this
.
mimeTypeGlobs
.
find
(
pattern
=>
pattern
(
mimeType
));
return
matched
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录