Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
79a25127
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,发现更多精彩内容 >>
提交
79a25127
编写于
4月 22, 2018
作者:
R
Ramya Achutha Rao
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Emmet: Allow css completions in style tag/attribute, html completions in script tags with html type
上级
c314388d
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
313 addition
and
65 deletion
+313
-65
extensions/emmet/src/abbreviationActions.ts
extensions/emmet/src/abbreviationActions.ts
+28
-6
extensions/emmet/src/defaultCompletionProvider.ts
extensions/emmet/src/defaultCompletionProvider.ts
+75
-16
extensions/emmet/src/test/abbreviationAction.test.ts
extensions/emmet/src/test/abbreviationAction.test.ts
+156
-28
extensions/emmet/src/test/partialParsingStylesheet.test.ts
extensions/emmet/src/test/partialParsingStylesheet.test.ts
+20
-15
extensions/emmet/src/util.ts
extensions/emmet/src/util.ts
+34
-0
未找到文件。
extensions/emmet/src/abbreviationActions.ts
浏览文件 @
79a25127
...
...
@@ -5,11 +5,11 @@
import
*
as
vscode
from
'
vscode
'
;
import
{
Node
,
HtmlNode
,
Rule
,
Property
,
Stylesheet
}
from
'
EmmetNode
'
;
import
{
getEmmetHelper
,
getNode
,
getInnerRange
,
getMappingForIncludedLanguages
,
parseDocument
,
validate
,
getEmmetConfiguration
,
isStyleSheet
,
getEmmetMode
,
parsePartialStylesheet
}
from
'
./util
'
;
import
{
getEmmetHelper
,
getNode
,
getInnerRange
,
getMappingForIncludedLanguages
,
parseDocument
,
validate
,
getEmmetConfiguration
,
isStyleSheet
,
getEmmetMode
,
parsePartialStylesheet
,
isStyleAttribute
,
getEmbeddedCssNodeIfAny
}
from
'
./util
'
;
const
trimRegex
=
/
[\u
00a0
]
*
[\d
|#|
\-
|
\*
|
\u
2022
]
+
\.?
/
;
const
hexColorRegex
=
/^#
\d
+$/
;
const
allowedMimeTypesInScriptTag
=
[
'
text/html
'
,
'
text/plain
'
,
'
text/x-template
'
,
'
text/template
'
];
const
inlineElements
=
[
'
a
'
,
'
abbr
'
,
'
acronym
'
,
'
applet
'
,
'
b
'
,
'
basefont
'
,
'
bdo
'
,
'
big
'
,
'
br
'
,
'
button
'
,
'
cite
'
,
'
code
'
,
'
del
'
,
'
dfn
'
,
'
em
'
,
'
font
'
,
'
i
'
,
'
iframe
'
,
'
img
'
,
'
input
'
,
'
ins
'
,
'
kbd
'
,
'
label
'
,
'
map
'
,
'
object
'
,
'
q
'
,
...
...
@@ -294,8 +294,24 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
if
(
!
helper
.
isAbbreviationValid
(
syntax
,
abbreviation
))
{
return
;
}
let
currentNode
=
getNode
(
rootNode
,
position
,
true
);
let
validateLocation
=
true
;
let
syntaxToUse
=
syntax
;
if
(
editor
.
document
.
languageId
===
'
html
'
)
{
if
(
isStyleAttribute
(
currentNode
,
position
))
{
syntaxToUse
=
'
css
'
;
validateLocation
=
false
;
}
else
{
const
embeddedCssNode
=
getEmbeddedCssNodeIfAny
(
editor
.
document
,
currentNode
,
position
);
if
(
embeddedCssNode
)
{
currentNode
=
getNode
(
embeddedCssNode
,
position
,
true
);
syntaxToUse
=
'
css
'
;
}
}
}
if
(
!
isValidLocationForEmmetAbbreviation
(
editor
.
document
,
rootNode
,
syntax
,
position
,
rangeToReplace
))
{
if
(
validateLocation
&&
!
isValidLocationForEmmetAbbreviation
(
editor
.
document
,
rootNode
,
currentNode
,
syntaxToUse
,
position
,
rangeToReplace
))
{
return
;
}
...
...
@@ -305,7 +321,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
allAbbreviationsSame
=
false
;
}
abbreviationList
.
push
({
syntax
,
abbreviation
,
rangeToReplace
,
filter
});
abbreviationList
.
push
({
syntax
:
syntaxToUse
,
abbreviation
,
rangeToReplace
,
filter
});
});
return
expandAbbreviationInRange
(
editor
,
abbreviationList
,
allAbbreviationsSame
).
then
(
success
=>
{
...
...
@@ -326,12 +342,12 @@ function fallbackTab(): Thenable<boolean | undefined> {
* Works only on html and css/less/scss syntax
* @param document current Text Document
* @param rootNode parsed document
* @param currentNode current node in the parsed document
* @param syntax syntax of the abbreviation
* @param position position to validate
* @param abbreviationRange The range of the abbreviation for which given position is being validated
*/
export
function
isValidLocationForEmmetAbbreviation
(
document
:
vscode
.
TextDocument
,
rootNode
:
Node
|
undefined
,
syntax
:
string
,
position
:
vscode
.
Position
,
abbreviationRange
:
vscode
.
Range
):
boolean
{
const
currentNode
=
rootNode
?
getNode
(
rootNode
,
position
,
true
)
:
null
;
export
function
isValidLocationForEmmetAbbreviation
(
document
:
vscode
.
TextDocument
,
rootNode
:
Node
|
undefined
,
currentNode
:
Node
|
null
,
syntax
:
string
,
position
:
vscode
.
Position
,
abbreviationRange
:
vscode
.
Range
):
boolean
{
if
(
isStyleSheet
(
syntax
))
{
const
stylesheet
=
<
Stylesheet
>
rootNode
;
if
(
stylesheet
&&
(
stylesheet
.
comments
||
[]).
some
(
x
=>
position
.
isAfterOrEqual
(
x
.
start
)
&&
position
.
isBeforeOrEqual
(
x
.
end
)))
{
...
...
@@ -407,6 +423,12 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
let
start
=
new
vscode
.
Position
(
0
,
0
);
if
(
currentHtmlNode
)
{
if
(
currentHtmlNode
.
name
===
'
script
'
)
{
return
(
currentHtmlNode
.
attributes
&&
currentHtmlNode
.
attributes
.
some
(
x
=>
x
.
name
.
toString
()
===
'
type
'
&&
allowedMimeTypesInScriptTag
.
indexOf
(
x
.
value
.
toString
())
>
-
1
));
}
const
innerRange
=
getInnerRange
(
currentHtmlNode
);
// Fix for https://github.com/Microsoft/vscode/issues/28829
...
...
extensions/emmet/src/defaultCompletionProvider.ts
浏览文件 @
79a25127
...
...
@@ -6,11 +6,39 @@
import
*
as
vscode
from
'
vscode
'
;
import
{
Node
,
Stylesheet
}
from
'
EmmetNode
'
;
import
{
isValidLocationForEmmetAbbreviation
}
from
'
./abbreviationActions
'
;
import
{
getEmmetHelper
,
getMappingForIncludedLanguages
,
parsePartialStylesheet
,
getEmmetConfiguration
,
getEmmetMode
,
isStyleSheet
,
parseDocument
,
}
from
'
./util
'
;
import
{
getEmmetHelper
,
getMappingForIncludedLanguages
,
parsePartialStylesheet
,
getEmmetConfiguration
,
getEmmetMode
,
isStyleSheet
,
parseDocument
,
getEmbeddedCssNodeIfAny
,
isStyleAttribute
,
getNode
}
from
'
./util
'
;
export
class
DefaultCompletionItemProvider
implements
vscode
.
CompletionItemProvider
{
private
lastCompletionType
:
string
|
undefined
;
public
provideCompletionItems
(
document
:
vscode
.
TextDocument
,
position
:
vscode
.
Position
,
token
:
vscode
.
CancellationToken
,
context
:
vscode
.
CompletionContext
):
Thenable
<
vscode
.
CompletionList
|
undefined
>
|
undefined
{
const
completionResult
=
this
.
provideCompletionItemsInternal
(
document
,
position
,
token
,
context
);
if
(
!
completionResult
)
{
this
.
lastCompletionType
=
undefined
;
return
;
}
return
completionResult
.
then
(
completionList
=>
{
if
(
!
completionList
||
!
completionList
.
items
.
length
)
{
this
.
lastCompletionType
=
undefined
;
return
completionList
;
}
const
item
=
completionList
.
items
[
0
];
const
expandedText
=
item
.
documentation
?
item
.
documentation
.
toString
()
:
''
;
if
(
expandedText
.
startsWith
(
'
<
'
))
{
this
.
lastCompletionType
=
'
html
'
;
}
else
if
(
expandedText
.
indexOf
(
'
:
'
)
>
0
&&
expandedText
.
endsWith
(
'
;
'
))
{
this
.
lastCompletionType
=
'
css
'
;
}
else
{
this
.
lastCompletionType
=
undefined
;
}
return
completionList
;
});
}
private
provideCompletionItemsInternal
(
document
:
vscode
.
TextDocument
,
position
:
vscode
.
Position
,
token
:
vscode
.
CancellationToken
,
context
:
vscode
.
CompletionContext
):
Thenable
<
vscode
.
CompletionList
|
undefined
>
|
undefined
{
const
emmetConfig
=
vscode
.
workspace
.
getConfiguration
(
'
emmet
'
);
const
excludedLanguages
=
emmetConfig
[
'
excludeLanguages
'
]
?
emmetConfig
[
'
excludeLanguages
'
]
:
[];
if
(
excludedLanguages
.
indexOf
(
document
.
languageId
)
>
-
1
)
{
...
...
@@ -28,29 +56,60 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
}
const
helper
=
getEmmetHelper
();
let
validateLocation
=
syntax
===
'
html
'
||
syntax
===
'
jsx
'
||
syntax
===
'
xml
'
;
let
rootNode
:
Node
|
undefined
=
undefined
;
let
currentNode
:
Node
|
null
=
null
;
if
(
document
.
languageId
===
'
html
'
)
{
if
(
context
.
triggerKind
===
vscode
.
CompletionTriggerKind
.
TriggerForIncompleteCompletions
)
{
switch
(
this
.
lastCompletionType
)
{
case
'
html
'
:
validateLocation
=
false
;
break
;
case
'
css
'
:
validateLocation
=
false
;
syntax
=
'
css
'
;
break
;
default
:
break
;
}
}
if
(
validateLocation
)
{
rootNode
=
parseDocument
(
document
,
false
);
currentNode
=
getNode
(
rootNode
,
position
,
true
);
if
(
isStyleAttribute
(
currentNode
,
position
))
{
syntax
=
'
css
'
;
validateLocation
=
false
;
}
else
{
const
embeddedCssNode
=
getEmbeddedCssNodeIfAny
(
document
,
currentNode
,
position
);
if
(
embeddedCssNode
)
{
currentNode
=
getNode
(
embeddedCssNode
,
position
,
true
);
syntax
=
'
css
'
;
}
}
}
}
const
extractAbbreviationResults
=
helper
.
extractAbbreviation
(
document
,
position
,
!
isStyleSheet
(
syntax
));
if
(
!
extractAbbreviationResults
||
!
helper
.
isAbbreviationValid
(
syntax
,
extractAbbreviationResults
.
abbreviation
))
{
return
;
}
let
validateLocation
=
false
;
let
rootNode
:
Node
|
undefined
=
undefined
;
if
(
context
.
triggerKind
!==
vscode
.
CompletionTriggerKind
.
TriggerForIncompleteCompletions
)
{
validateLocation
=
syntax
===
'
html
'
||
syntax
===
'
jsx
'
||
syntax
===
'
xml
'
||
isStyleSheet
(
document
.
languageId
);
// If document can be css parsed, get currentNode
if
(
isStyleSheet
(
document
.
languageId
))
{
let
usePartialParsing
=
vscode
.
workspace
.
getConfiguration
(
'
emmet
'
)[
'
optimizeStylesheetParsing
'
]
===
true
;
rootNode
=
usePartialParsing
&&
document
.
lineCount
>
1000
?
parsePartialStylesheet
(
document
,
position
)
:
<
Stylesheet
>
parseDocument
(
document
,
false
);
if
(
!
rootNode
)
{
return
;
}
}
else
if
(
document
.
languageId
===
'
html
'
)
{
rootNode
=
parseDocument
(
document
,
false
);
if
(
isStyleSheet
(
document
.
languageId
)
&&
context
.
triggerKind
!==
vscode
.
CompletionTriggerKind
.
TriggerForIncompleteCompletions
)
{
validateLocation
=
true
;
let
usePartialParsing
=
vscode
.
workspace
.
getConfiguration
(
'
emmet
'
)[
'
optimizeStylesheetParsing
'
]
===
true
;
rootNode
=
usePartialParsing
&&
document
.
lineCount
>
1000
?
parsePartialStylesheet
(
document
,
position
)
:
<
Stylesheet
>
parseDocument
(
document
,
false
);
if
(
!
rootNode
)
{
return
;
}
currentNode
=
getNode
(
rootNode
,
position
,
true
);
}
if
(
validateLocation
&&
!
isValidLocationForEmmetAbbreviation
(
document
,
rootNode
,
syntax
,
position
,
extractAbbreviationResults
.
abbreviationRange
))
{
if
(
validateLocation
&&
!
isValidLocationForEmmetAbbreviation
(
document
,
rootNode
,
currentNode
,
syntax
,
position
,
extractAbbreviationResults
.
abbreviationRange
))
{
return
;
}
...
...
extensions/emmet/src/test/abbreviationAction.test.ts
浏览文件 @
79a25127
...
...
@@ -25,13 +25,19 @@ const htmlContents = `
</ul>
<style>
.boo {
m10
display: dn;
m10
}
</style>
<span></span>
(ul>li.item$)*2
(ul>li.item$)*2+span
(div>dl>(dt+dd)*2)
<script type="text/html">
span.hello
</script>
<script type="text/javascript">
span.hello
</script>
</body>
`
;
...
...
@@ -216,7 +222,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => {
test
(
'
Expand css when inside style tag (HTML)
'
,
()
=>
{
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
13
,
3
,
13
,
6
);
editor
.
selection
=
new
Selection
(
13
,
16
,
13
,
19
);
let
expandPromise
=
expandEmmetAbbreviation
({
language
:
'
css
'
});
if
(
!
expandPromise
)
{
return
Promise
.
resolve
();
...
...
@@ -228,32 +234,154 @@ suite('Tests for Expand Abbreviations (HTML)', () => {
});
});
// test('Expand css when inside style tag in completion list (HTML)', () => {
// const abbreviation = 'm10';
// const expandedText = 'margin: 10px;';
// return withRandomFileEditor(htmlContents, 'html', (editor, doc) => {
// editor.selection = new Selection(13, 3, 13, 6);
// const cancelSrc = new CancellationTokenSource();
// const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke });
// if (!completionPromise) {
// assert.equal(1, 2, `Problem with expanding m10`);
// return Promise.resolve();
// }
// return completionPromise.then((completionList: CompletionList) => {
// if (!completionList.items || !completionList.items.length) {
// assert.equal(1, 2, `Problem with expanding m10`);
// return Promise.resolve();
// }
// const emmetCompletionItem = completionList.items[0];
// assert.equal(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`);
// assert.equal((<string>emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`);
// assert.equal(emmetCompletionItem.filterText, abbreviation, `FilterText of completion item doesnt match.`);
// return Promise.resolve();
// });
// });
// });
test
(
'
Expand css when inside style tag in completion list (HTML)
'
,
()
=>
{
const
abbreviation
=
'
m10
'
;
const
expandedText
=
'
margin: 10px;
'
;
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
13
,
16
,
13
,
19
);
const
cancelSrc
=
new
CancellationTokenSource
();
const
completionPromise
=
completionProvider
.
provideCompletionItems
(
editor
.
document
,
editor
.
selection
.
active
,
cancelSrc
.
token
,
{
triggerKind
:
CompletionTriggerKind
.
Invoke
});
if
(
!
completionPromise
)
{
assert
.
equal
(
1
,
2
,
`Problem with expanding m10`
);
return
Promise
.
resolve
();
}
return
completionPromise
.
then
((
completionList
:
CompletionList
)
=>
{
if
(
!
completionList
.
items
||
!
completionList
.
items
.
length
)
{
assert
.
equal
(
1
,
2
,
`Problem with expanding m10`
);
return
Promise
.
resolve
();
}
const
emmetCompletionItem
=
completionList
.
items
[
0
];
assert
.
equal
(
emmetCompletionItem
.
label
,
expandedText
,
`Label of completion item doesnt match.`
);
assert
.
equal
((
<
string
>
emmetCompletionItem
.
documentation
||
''
).
replace
(
/
\|
/g
,
''
),
expandedText
,
`Docs of completion item doesnt match.`
);
assert
.
equal
(
emmetCompletionItem
.
filterText
,
abbreviation
,
`FilterText of completion item doesnt match.`
);
return
Promise
.
resolve
();
});
});
});
test
(
'
No expanding text inside style tag if position is not for property name (HTML)
'
,
()
=>
{
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
13
,
14
,
13
,
14
);
return
expandEmmetAbbreviation
(
null
).
then
(()
=>
{
assert
.
equal
(
editor
.
document
.
getText
(),
htmlContents
);
return
Promise
.
resolve
();
});
});
});
test
(
'
No expanding text in completion list inside style tag if position is not for property name (HTML)
'
,
()
=>
{
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
13
,
14
,
13
,
14
);
const
cancelSrc
=
new
CancellationTokenSource
();
const
completionPromise
=
completionProvider
.
provideCompletionItems
(
editor
.
document
,
editor
.
selection
.
active
,
cancelSrc
.
token
,
{
triggerKind
:
CompletionTriggerKind
.
Invoke
});
assert
.
equal
(
!
completionPromise
,
true
,
`Got unexpected comapletion promise instead of undefined`
);
return
Promise
.
resolve
();
});
});
test
(
'
Expand css when inside style attribute (HTML)
'
,
()
=>
{
const
styleAttributeContent
=
'
<div style="m10" class="hello"></div>
'
;
return
withRandomFileEditor
(
styleAttributeContent
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
0
,
15
,
0
,
15
);
let
expandPromise
=
expandEmmetAbbreviation
(
null
);
if
(
!
expandPromise
)
{
return
Promise
.
resolve
();
}
return
expandPromise
.
then
(()
=>
{
assert
.
equal
(
editor
.
document
.
getText
(),
styleAttributeContent
.
replace
(
'
m10
'
,
'
margin: 10px;
'
));
return
Promise
.
resolve
();
});
});
});
test
(
'
Expand css when inside style attribute in completion list (HTML)
'
,
()
=>
{
const
abbreviation
=
'
m10
'
;
const
expandedText
=
'
margin: 10px;
'
;
return
withRandomFileEditor
(
'
<div style="m10" class="hello"></div>
'
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
0
,
15
,
0
,
15
);
const
cancelSrc
=
new
CancellationTokenSource
();
const
completionPromise
=
completionProvider
.
provideCompletionItems
(
editor
.
document
,
editor
.
selection
.
active
,
cancelSrc
.
token
,
{
triggerKind
:
CompletionTriggerKind
.
Invoke
});
if
(
!
completionPromise
)
{
assert
.
equal
(
1
,
2
,
`Problem with expanding m10`
);
return
Promise
.
resolve
();
}
return
completionPromise
.
then
((
completionList
:
CompletionList
)
=>
{
if
(
!
completionList
.
items
||
!
completionList
.
items
.
length
)
{
assert
.
equal
(
1
,
2
,
`Problem with expanding m10`
);
return
Promise
.
resolve
();
}
const
emmetCompletionItem
=
completionList
.
items
[
0
];
assert
.
equal
(
emmetCompletionItem
.
label
,
expandedText
,
`Label of completion item doesnt match.`
);
assert
.
equal
((
<
string
>
emmetCompletionItem
.
documentation
||
''
).
replace
(
/
\|
/g
,
''
),
expandedText
,
`Docs of completion item doesnt match.`
);
assert
.
equal
(
emmetCompletionItem
.
filterText
,
abbreviation
,
`FilterText of completion item doesnt match.`
);
return
Promise
.
resolve
();
});
});
});
test
(
'
Expand html when inside script tag with html type (HTML)
'
,
()
=>
{
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
21
,
12
,
21
,
12
);
let
expandPromise
=
expandEmmetAbbreviation
(
null
);
if
(
!
expandPromise
)
{
return
Promise
.
resolve
();
}
return
expandPromise
.
then
(()
=>
{
assert
.
equal
(
editor
.
document
.
getText
(),
htmlContents
.
replace
(
'
span.hello
'
,
'
<span class="hello"></span>
'
));
return
Promise
.
resolve
();
});
});
});
test
(
'
Expand html when inside script tag with html type (HTML)
'
,
()
=>
{
const
abbreviation
=
'
span.hello
'
;
const
expandedText
=
'
<span class="hello"></span>
'
;
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
21
,
12
,
21
,
12
);
const
cancelSrc
=
new
CancellationTokenSource
();
const
completionPromise
=
completionProvider
.
provideCompletionItems
(
editor
.
document
,
editor
.
selection
.
active
,
cancelSrc
.
token
,
{
triggerKind
:
CompletionTriggerKind
.
Invoke
});
if
(
!
completionPromise
)
{
assert
.
equal
(
1
,
2
,
`Problem with expanding span.hello`
);
return
Promise
.
resolve
();
}
return
completionPromise
.
then
((
completionList
:
CompletionList
)
=>
{
if
(
!
completionList
.
items
||
!
completionList
.
items
.
length
)
{
assert
.
equal
(
1
,
2
,
`Problem with expanding span.hello`
);
return
Promise
.
resolve
();
}
const
emmetCompletionItem
=
completionList
.
items
[
0
];
assert
.
equal
(
emmetCompletionItem
.
label
,
abbreviation
,
`Label of completion item doesnt match.`
);
assert
.
equal
((
<
string
>
emmetCompletionItem
.
documentation
||
''
).
replace
(
/
\|
/g
,
''
),
expandedText
,
`Docs of completion item doesnt match.`
);
return
Promise
.
resolve
();
});
});
});
test
(
'
No expanding text inside script tag with javascript type (HTML)
'
,
()
=>
{
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
24
,
12
,
24
,
12
);
return
expandEmmetAbbreviation
(
null
).
then
(()
=>
{
assert
.
equal
(
editor
.
document
.
getText
(),
htmlContents
);
return
Promise
.
resolve
();
});
});
});
test
(
'
No expanding text in completion list inside script tag with javascript type (HTML)
'
,
()
=>
{
return
withRandomFileEditor
(
htmlContents
,
'
html
'
,
(
editor
,
doc
)
=>
{
editor
.
selection
=
new
Selection
(
24
,
12
,
24
,
12
);
const
cancelSrc
=
new
CancellationTokenSource
();
const
completionPromise
=
completionProvider
.
provideCompletionItems
(
editor
.
document
,
editor
.
selection
.
active
,
cancelSrc
.
token
,
{
triggerKind
:
CompletionTriggerKind
.
Invoke
});
assert
.
equal
(
!
completionPromise
,
true
,
`Got unexpected comapletion promise instead of undefined`
);
return
Promise
.
resolve
();
});
});
// test('No expanding when html is excluded in the settings', () => {
// return workspace.getConfiguration('emmet').update('excludeLanguages', ['html'], ConfigurationTarget.Global).then(() => {
...
...
extensions/emmet/src/test/partialParsingStylesheet.test.ts
浏览文件 @
79a25127
...
...
@@ -7,12 +7,17 @@ import 'mocha';
import
*
as
assert
from
'
assert
'
;
import
{
withRandomFileEditor
}
from
'
./testUtils
'
;
import
*
as
vscode
from
'
vscode
'
;
import
{
parsePartialStylesheet
}
from
'
../util
'
;
import
{
parsePartialStylesheet
,
getNode
}
from
'
../util
'
;
import
{
isValidLocationForEmmetAbbreviation
}
from
'
../abbreviationActions
'
;
suite
(
'
Tests for partial parse of Stylesheets
'
,
()
=>
{
function
isValid
(
doc
:
vscode
.
TextDocument
,
range
:
vscode
.
Range
,
syntax
:
string
):
boolean
{
const
rootNode
=
parsePartialStylesheet
(
doc
,
range
.
end
);
const
currentNode
=
getNode
(
rootNode
,
range
.
end
,
true
);
return
isValidLocationForEmmetAbbreviation
(
doc
,
rootNode
,
currentNode
,
'
css
'
,
range
.
end
,
range
);
}
suite
(
'
Tests for partial parse of Stylesheets
'
,
()
=>
{
test
(
'
Ignore block comment inside rule
'
,
function
():
any
{
const
cssContents
=
`
p {
...
...
@@ -37,10 +42,10 @@ p {
]
rangesForEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
css
'
,
range
.
end
,
range
),
true
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
css
'
),
true
);
});
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
css
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
css
'
),
false
);
});
return
Promise
.
resolve
();
...
...
@@ -67,7 +72,7 @@ dn {
new
vscode
.
Range
(
7
,
2
,
7
,
4
)
// bg after ending of badly constructed block
];
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
false
);
});
return
Promise
.
resolve
();
});
...
...
@@ -102,10 +107,10 @@ comment */
new
vscode
.
Range
(
10
,
2
,
10
,
3
)
// p after ending of block
];
rangesForEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
css
'
,
range
.
end
,
range
),
true
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
css
'
),
true
);
});
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
css
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
css
'
),
false
);
});
return
Promise
.
resolve
();
});
...
...
@@ -137,10 +142,10 @@ comment */
new
vscode
.
Range
(
6
,
3
,
6
,
4
)
// In selector
];
rangesForEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
true
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
true
);
});
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
false
);
});
return
Promise
.
resolve
();
});
...
...
@@ -169,10 +174,10 @@ comment */
new
vscode
.
Range
(
1
,
66
,
1
,
68
)
// Outside any ruleset
];
rangesForEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
true
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
true
);
});
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
false
);
});
return
Promise
.
resolve
();
});
...
...
@@ -204,10 +209,10 @@ p.#{dn} {
new
vscode
.
Range
(
7
,
1
,
7
,
3
)
// dn inside ruleset whose selector uses nested interpolation
];
rangesForEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
true
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
true
);
});
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
false
);
});
return
Promise
.
resolve
();
});
...
...
@@ -242,10 +247,10 @@ ment */{
new
vscode
.
Range
(
6
,
3
,
6
,
4
)
// In c inside block comment
];
rangesForEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
true
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
true
);
});
rangesNotEmmet
.
forEach
(
range
=>
{
assert
.
equal
(
isValid
LocationForEmmetAbbreviation
(
doc
,
parsePartialStylesheet
(
doc
,
range
.
end
),
'
scss
'
,
range
.
end
,
range
),
false
);
assert
.
equal
(
isValid
(
doc
,
range
,
'
scss
'
),
false
);
});
return
Promise
.
resolve
();
});
...
...
extensions/emmet/src/util.ts
浏览文件 @
79a25127
...
...
@@ -529,3 +529,37 @@ export function getCssPropertyFromDocument(editor: vscode.TextEditor, position:
return
(
node
&&
node
.
type
===
'
property
'
)
?
<
Property
>
node
:
null
;
}
}
export
function
getEmbeddedCssNodeIfAny
(
document
:
vscode
.
TextDocument
,
currentNode
:
Node
|
null
,
position
:
vscode
.
Position
):
Node
|
undefined
{
if
(
!
currentNode
)
{
return
;
}
const
currentHtmlNode
=
<
HtmlNode
>
currentNode
;
if
(
currentHtmlNode
&&
currentHtmlNode
.
close
)
{
const
innerRange
=
getInnerRange
(
currentHtmlNode
);
if
(
innerRange
&&
innerRange
.
contains
(
position
))
{
if
(
currentHtmlNode
.
name
===
'
style
'
&&
currentHtmlNode
.
open
.
end
.
isBefore
(
position
)
&&
currentHtmlNode
.
close
.
start
.
isAfter
(
position
)
)
{
let
buffer
=
new
DocumentStreamReader
(
document
,
currentHtmlNode
.
open
.
end
,
new
vscode
.
Range
(
currentHtmlNode
.
open
.
end
,
currentHtmlNode
.
close
.
start
));
return
parseStylesheet
(
buffer
);
}
}
}
}
export
function
isStyleAttribute
(
currentNode
:
Node
|
null
,
position
:
vscode
.
Position
):
boolean
{
if
(
!
currentNode
)
{
return
false
;
}
const
currentHtmlNode
=
<
HtmlNode
>
currentNode
;
const
index
=
(
currentHtmlNode
.
attributes
||
[]).
findIndex
(
x
=>
x
.
name
.
toString
()
===
'
style
'
);
if
(
index
===
-
1
)
{
return
false
;
}
const
styleAttribute
=
currentHtmlNode
.
attributes
[
index
];
return
position
.
isAfterOrEqual
(
styleAttribute
.
value
.
start
)
&&
position
.
isBeforeOrEqual
(
styleAttribute
.
value
.
end
);
}
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录