Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
bcacd2fe
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,发现更多精彩内容 >>
提交
bcacd2fe
编写于
2月 26, 2018
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix #34367
上级
d80bc665
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
117 addition
and
67 deletion
+117
-67
src/vs/base/browser/htmlContentRenderer.ts
src/vs/base/browser/htmlContentRenderer.ts
+1
-10
src/vs/platform/notification/common/notification.ts
src/vs/platform/notification/common/notification.ts
+3
-7
src/vs/workbench/browser/parts/notifications/notificationsViewer.ts
...kbench/browser/parts/notifications/notificationsViewer.ts
+49
-33
src/vs/workbench/common/notifications.ts
src/vs/workbench/common/notifications.ts
+49
-16
src/vs/workbench/test/common/notifications.test.ts
src/vs/workbench/test/common/notifications.test.ts
+15
-1
未找到文件。
src/vs/base/browser/htmlContentRenderer.ts
浏览文件 @
bcacd2fe
...
...
@@ -9,9 +9,8 @@ import * as DOM from 'vs/base/browser/dom';
import
{
defaultGenerator
}
from
'
vs/base/common/idGenerator
'
;
import
{
escape
}
from
'
vs/base/common/strings
'
;
import
{
removeMarkdownEscapes
,
IMarkdownString
}
from
'
vs/base/common/htmlContent
'
;
import
{
marked
,
Marked
Renderer
,
Marked
Options
}
from
'
vs/base/common/marked/marked
'
;
import
{
marked
,
MarkedOptions
}
from
'
vs/base/common/marked/marked
'
;
import
{
IMouseEvent
}
from
'
vs/base/browser/mouseEvent
'
;
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
export
interface
IContentActionHandler
{
...
...
@@ -25,7 +24,6 @@ export interface RenderOptions {
actionHandler
?:
IContentActionHandler
;
codeBlockRenderer
?:
(
modeId
:
string
,
value
:
string
)
=>
Thenable
<
string
>
;
codeBlockRenderCallback
?:
()
=>
void
;
joinRendererConfiguration
?:
(
renderer
:
MarkedRenderer
)
=>
MarkedOptions
;
}
function
createElement
(
options
:
RenderOptions
):
HTMLElement
{
...
...
@@ -166,13 +164,6 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions
renderer
};
if
(
options
.
joinRendererConfiguration
)
{
const
additionalMarkedOptions
=
options
.
joinRendererConfiguration
(
renderer
);
if
(
additionalMarkedOptions
)
{
assign
(
markedOptions
,
additionalMarkedOptions
);
}
}
element
.
innerHTML
=
marked
(
markdown
.
value
,
markedOptions
);
signalInnerHTML
();
...
...
src/vs/platform/notification/common/notification.ts
浏览文件 @
bcacd2fe
...
...
@@ -8,7 +8,6 @@
import
Severity
from
'
vs/base/common/severity
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IMarkdownString
}
from
'
vs/base/common/htmlContent
'
;
import
{
IAction
}
from
'
vs/base/common/actions
'
;
import
Event
,
{
Emitter
}
from
'
vs/base/common/event
'
;
...
...
@@ -16,7 +15,7 @@ export import Severity = Severity;
export
const
INotificationService
=
createDecorator
<
INotificationService
>
(
'
notificationService
'
);
export
type
NotificationMessage
=
string
|
IMarkdownString
|
Error
;
export
type
NotificationMessage
=
string
|
Error
;
export
interface
INotification
{
...
...
@@ -26,11 +25,8 @@ export interface INotification {
severity
:
Severity
;
/**
* The message of the notification. This can either be a `string`, `Error`
* or `IMarkdownString`.
*
* **Note:** Currently only links are supported in notifications. Links to commands can
* be embedded provided that the `IMarkdownString` is trusted.
* The message of the notification. This can either be a `string` or `Error`. Messages
* can optionally include links in the format: `[text](link)`
*/
message
:
NotificationMessage
;
...
...
src/vs/workbench/browser/parts/notifications/notificationsViewer.ts
浏览文件 @
bcacd2fe
...
...
@@ -6,8 +6,7 @@
'
use strict
'
;
import
{
IDelegate
,
IRenderer
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
renderMarkdown
,
IContentActionHandler
}
from
'
vs/base/browser/htmlContentRenderer
'
;
import
{
clearNode
,
addClass
,
removeClass
,
toggleClass
}
from
'
vs/base/browser/dom
'
;
import
{
clearNode
,
addClass
,
removeClass
,
toggleClass
,
addDisposableListener
}
from
'
vs/base/browser/dom
'
;
import
{
IOpenerService
}
from
'
vs/platform/opener/common/opener
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
onUnexpectedError
}
from
'
vs/base/common/errors
'
;
...
...
@@ -15,17 +14,15 @@ import { localize } from 'vs/nls';
import
{
ButtonGroup
}
from
'
vs/base/browser/ui/button/button
'
;
import
{
attachButtonStyler
,
attachProgressBarStyler
}
from
'
vs/platform/theme/common/styler
'
;
import
{
IThemeService
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
IMarkdownString
}
from
'
vs/base/common/htmlContent
'
;
import
{
ActionBar
}
from
'
vs/base/browser/ui/actionbar/actionbar
'
;
import
{
IAction
,
IActionRunner
}
from
'
vs/base/common/actions
'
;
import
{
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
IContextMenuService
}
from
'
vs/platform/contextview/browser/contextView
'
;
import
{
DropdownMenuActionItem
}
from
'
vs/base/browser/ui/dropdown/dropdown
'
;
import
{
INotificationViewItem
,
NotificationViewItem
,
NotificationViewItemLabelKind
}
from
'
vs/workbench/common/notifications
'
;
import
{
INotificationViewItem
,
NotificationViewItem
,
NotificationViewItemLabelKind
,
INotificationMessage
}
from
'
vs/workbench/common/notifications
'
;
import
{
ClearNotificationAction
,
ExpandNotificationAction
,
CollapseNotificationAction
,
ConfigureNotificationAction
}
from
'
vs/workbench/browser/parts/notifications/notificationsActions
'
;
import
{
IKeybindingService
}
from
'
vs/platform/keybinding/common/keybinding
'
;
import
{
MarkedOptions
}
from
'
vs/base/common/marked/marked
'
;
import
{
ProgressBar
}
from
'
vs/base/browser/ui/progressbar/progressbar
'
;
import
{
Severity
}
from
'
vs/platform/notification/common/notification
'
;
...
...
@@ -92,8 +89,8 @@ export class NotificationsListDelegate implements IDelegate<INotificationViewIte
}
this
.
offsetHelper
.
style
.
width
=
`calc(100% -
${
10
/* padding */
+
24
/* severity icon */
+
(
actions
*
24
)
/* 24px per action */
}
px)`
;
// Render message
markdown
into offset helper
const
renderedMessage
=
NotificationMessage
Markdown
Renderer
.
render
(
notification
.
message
);
// Render message into offset helper
const
renderedMessage
=
NotificationMessageRenderer
.
render
(
notification
.
message
);
this
.
offsetHelper
.
appendChild
(
renderedMessage
);
// Compute height
...
...
@@ -131,30 +128,49 @@ export interface INotificationTemplateData {
renderer
:
NotificationTemplateRenderer
;
}
class
NotificationMessageMarkdownRenderer
{
interface
IMessageActionHandler
{
callback
:
(
href
:
string
)
=>
void
;
disposeables
:
IDisposable
[];
}
private
static
readonly
MARKED_NOOP
=
(
text
?:
string
)
=>
text
||
''
;
private
static
readonly
MARKED_NOOP_TARGETS
=
[
'
blockquote
'
,
'
br
'
,
'
code
'
,
'
codespan
'
,
'
del
'
,
'
em
'
,
'
heading
'
,
'
hr
'
,
'
html
'
,
'
image
'
,
'
list
'
,
'
listitem
'
,
'
paragraph
'
,
'
strong
'
,
'
table
'
,
'
tablecell
'
,
'
tablerow
'
];
class
NotificationMessageRenderer
{
public
static
render
(
markdown
:
IMarkdownString
,
actionHandler
?:
IContentActionHandler
):
HTMLElement
{
return
renderMarkdown
(
markdown
,
{
inline
:
true
,
joinRendererConfiguration
:
renderer
=>
{
public
static
render
(
message
:
INotificationMessage
,
actionHandler
?:
IMessageActionHandler
):
HTMLElement
{
const
messageContainer
=
document
.
createElement
(
'
span
'
);
// Overwrite markdown render functions as no-ops
NotificationMessageMarkdownRenderer
.
MARKED_NOOP_TARGETS
.
forEach
(
fn
=>
renderer
[
fn
]
=
NotificationMessageMarkdownRenderer
.
MARKED_NOOP
);
// Message has no links
if
(
message
.
links
.
length
===
0
)
{
messageContainer
.
textContent
=
message
.
value
;
}
return
{
gfm
:
false
,
// disable GitHub style markdown,
smartypants
:
false
// disable some text transformations
}
as
MarkedOptions
;
},
actionHandler
});
// Message has links
else
{
let
index
=
0
;
let
textBefore
:
string
;
for
(
let
i
=
0
;
i
<
message
.
links
.
length
;
i
++
)
{
const
link
=
message
.
links
[
i
];
textBefore
=
message
.
value
.
substring
(
index
,
link
.
offset
);
if
(
textBefore
)
{
messageContainer
.
appendChild
(
document
.
createTextNode
(
textBefore
));
}
const
anchor
=
document
.
createElement
(
'
a
'
);
anchor
.
textContent
=
link
.
name
;
anchor
.
title
=
link
.
href
;
anchor
.
href
=
link
.
href
;
if
(
actionHandler
)
{
actionHandler
.
disposeables
.
push
(
addDisposableListener
(
anchor
,
'
click
'
,
()
=>
actionHandler
.
callback
(
link
.
href
)));
}
messageContainer
.
appendChild
(
anchor
);
index
=
link
.
offset
+
link
.
length
;
}
}
return
messageContainer
;
}
}
...
...
@@ -340,8 +356,8 @@ export class NotificationTemplateRenderer {
private
renderMessage
(
notification
:
INotificationViewItem
):
boolean
{
clearNode
(
this
.
template
.
message
);
this
.
template
.
message
.
appendChild
(
NotificationMessage
Markdown
Renderer
.
render
(
notification
.
message
,
{
callback
:
(
content
:
string
)
=>
this
.
openerService
.
open
(
URI
.
parse
(
content
)).
then
(
void
0
,
onUnexpectedError
),
this
.
template
.
message
.
appendChild
(
NotificationMessageRenderer
.
render
(
notification
.
message
,
{
callback
:
link
=>
this
.
openerService
.
open
(
URI
.
parse
(
link
)).
then
(
void
0
,
onUnexpectedError
),
disposeables
:
this
.
inputDisposeables
}));
...
...
src/vs/workbench/common/notifications.ts
浏览文件 @
bcacd2fe
...
...
@@ -5,7 +5,6 @@
'
use strict
'
;
import
{
IMarkdownString
}
from
'
vs/base/common/htmlContent
'
;
import
{
INotification
,
INotificationHandle
,
INotificationActions
,
INotificationProgress
,
NoOpNotification
,
Severity
,
NotificationMessage
}
from
'
vs/platform/notification/common/notification
'
;
import
{
toErrorMessage
}
from
'
vs/base/common/errorMessage
'
;
import
Event
,
{
Emitter
,
once
}
from
'
vs/base/common/event
'
;
...
...
@@ -184,7 +183,7 @@ export class NotificationsModel implements INotificationsModel {
export
interface
INotificationViewItem
{
readonly
severity
:
Severity
;
readonly
message
:
I
MarkdownString
;
readonly
message
:
I
NotificationMessage
;
readonly
source
:
string
;
readonly
actions
:
INotificationActions
;
readonly
progress
:
INotificationViewItemProgress
;
...
...
@@ -320,10 +319,27 @@ export class NotificationViewItemProgress implements INotificationViewItemProgre
}
}
export
interface
IMessageLink
{
name
:
string
;
href
:
string
;
offset
:
number
;
length
:
number
;
}
export
interface
INotificationMessage
{
raw
:
string
;
value
:
string
;
links
:
IMessageLink
[];
}
export
class
NotificationViewItem
implements
INotificationViewItem
{
private
static
MAX_MESSAGE_LENGTH
=
1000
;
// Example link: "Some message with [link text](http://link.href)."
// RegEx: [, anything not ], ], (, http:|https:, //, no whitespace)
private
static
LINK_REGEX
=
/
\[([^\]]
+
)\]\((
https
?
:
\/\/[^\)\s]
+
)\)
/gi
;
private
_expanded
:
boolean
;
private
toDispose
:
IDisposable
[];
...
...
@@ -346,15 +362,11 @@ export class NotificationViewItem implements INotificationViewItem {
severity
=
Severity
.
Info
;
}
const
message
=
NotificationViewItem
.
toMarkdownString
(
notification
.
message
);
const
message
=
NotificationViewItem
.
parseNotificationMessage
(
notification
.
message
);
if
(
!
message
)
{
return
null
;
// we need a message to show
}
if
(
message
.
value
.
length
>
NotificationViewItem
.
MAX_MESSAGE_LENGTH
)
{
message
.
value
=
`
${
message
.
value
.
substr
(
0
,
NotificationViewItem
.
MAX_MESSAGE_LENGTH
)}
...`
;
}
let
actions
:
INotificationActions
;
if
(
notification
.
actions
)
{
actions
=
notification
.
actions
;
...
...
@@ -365,21 +377,42 @@ export class NotificationViewItem implements INotificationViewItem {
return
new
NotificationViewItem
(
severity
,
message
,
notification
.
source
,
actions
);
}
private
static
toMarkdownString
(
input
:
NotificationMessage
):
IMarkdownString
{
let
message
:
IMarkdownS
tring
;
private
static
parseNotificationMessage
(
input
:
NotificationMessage
):
INotificationMessage
{
let
message
:
s
tring
;
if
(
input
instanceof
Error
)
{
message
=
{
value
:
toErrorMessage
(
input
,
false
),
isTrusted
:
false
}
;
message
=
toErrorMessage
(
input
,
false
)
;
}
else
if
(
typeof
input
===
'
string
'
)
{
message
=
{
value
:
input
,
isTrusted
:
false
};
}
else
if
(
input
.
value
&&
typeof
input
.
value
===
'
string
'
)
{
message
=
input
;
}
return
message
;
if
(
!
message
)
{
return
null
;
// we need a message to show
}
const
raw
=
message
;
// Make sure message is in the limits
if
(
message
.
length
>
NotificationViewItem
.
MAX_MESSAGE_LENGTH
)
{
message
=
`
${
message
.
substr
(
0
,
NotificationViewItem
.
MAX_MESSAGE_LENGTH
)}
...`
;
}
// Remove newlines from messages as we do not support that and it makes link parsing hard
message
=
message
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
'
'
).
trim
();
// Parse Links
const
links
:
IMessageLink
[]
=
[];
message
.
replace
(
NotificationViewItem
.
LINK_REGEX
,
(
matchString
:
string
,
name
:
string
,
href
:
string
,
offset
:
number
)
=>
{
links
.
push
({
name
,
href
,
offset
,
length
:
matchString
.
length
});
return
matchString
;
});
return
{
raw
,
value
:
message
,
links
};
}
private
constructor
(
private
_severity
:
Severity
,
private
_message
:
I
MarkdownString
,
private
_source
:
string
,
actions
?:
INotificationActions
)
{
private
constructor
(
private
_severity
:
Severity
,
private
_message
:
I
NotificationMessage
,
private
_source
:
string
,
actions
?:
INotificationActions
)
{
this
.
toDispose
=
[];
this
.
setActions
(
actions
);
...
...
@@ -452,7 +485,7 @@ export class NotificationViewItem implements INotificationViewItem {
return
this
.
_progress
;
}
public
get
message
():
I
MarkdownString
{
public
get
message
():
I
NotificationMessage
{
return
this
.
_message
;
}
...
...
@@ -470,7 +503,7 @@ export class NotificationViewItem implements INotificationViewItem {
}
public
updateMessage
(
input
:
NotificationMessage
):
void
{
const
message
=
NotificationViewItem
.
toMarkdownString
(
input
);
const
message
=
NotificationViewItem
.
parseNotificationMessage
(
input
);
if
(
!
message
)
{
return
;
}
...
...
src/vs/workbench/test/common/notifications.test.ts
浏览文件 @
bcacd2fe
...
...
@@ -18,7 +18,6 @@ suite('Notifications', () => {
// Invalid
assert
.
ok
(
!
NotificationViewItem
.
create
({
severity
:
Severity
.
Error
,
message
:
''
}));
assert
.
ok
(
!
NotificationViewItem
.
create
({
severity
:
Severity
.
Error
,
message
:
null
}));
assert
.
ok
(
!
NotificationViewItem
.
create
({
severity
:
Severity
.
Error
,
message
:
{
value
:
''
,
isTrusted
:
true
}
}));
// Duplicates
let
item1
=
NotificationViewItem
.
create
({
severity
:
Severity
.
Error
,
message
:
'
Error Message
'
});
...
...
@@ -107,6 +106,21 @@ suite('Notifications', () => {
// Error with Action
let
item6
=
NotificationViewItem
.
create
({
severity
:
Severity
.
Error
,
message
:
create
(
'
Hello Error
'
,
{
actions
:
[
new
Action
(
'
id
'
,
'
label
'
)]
})
});
assert
.
equal
(
item6
.
actions
.
primary
.
length
,
1
);
// Links
let
item7
=
NotificationViewItem
.
create
({
severity
:
Severity
.
Info
,
message
:
'
Unable to [Link 1](http://link1.com) open [Link 2](https://link2.com) and [Invalid Link3](ftp://link3.com)
'
});
const
links
=
item7
.
message
.
links
;
assert
.
equal
(
links
.
length
,
2
);
assert
.
equal
(
links
[
0
].
name
,
'
Link 1
'
);
assert
.
equal
(
links
[
0
].
href
,
'
http://link1.com
'
);
assert
.
equal
(
links
[
0
].
length
,
'
[Link 1](http://link1.com)
'
.
length
);
assert
.
equal
(
links
[
0
].
offset
,
'
Unable to
'
.
length
);
assert
.
equal
(
links
[
1
].
name
,
'
Link 2
'
);
assert
.
equal
(
links
[
1
].
href
,
'
https://link2.com
'
);
assert
.
equal
(
links
[
1
].
length
,
'
[Link 2](https://link2.com)
'
.
length
);
assert
.
equal
(
links
[
1
].
offset
,
'
Unable to [Link 1](http://link1.com) open
'
.
length
);
});
test
(
'
Model
'
,
()
=>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录