Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
803ca903
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,发现更多精彩内容 >>
未验证
提交
803ca903
编写于
8月 08, 2018
作者:
M
Martin Aeschlimann
提交者:
GitHub
8月 08, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #55971 from Microsoft/octref/css-import-completion
@import completion for css/scss/less. Fix #51331
上级
e9b33047
a40bfc94
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
152 addition
and
19 deletion
+152
-19
extensions/css-language-features/.vscode/launch.json
extensions/css-language-features/.vscode/launch.json
+20
-0
extensions/css-language-features/package.json
extensions/css-language-features/package.json
+1
-0
extensions/css-language-features/server/src/pathCompletion.ts
...nsions/css-language-features/server/src/pathCompletion.ts
+56
-15
extensions/css-language-features/server/src/test/completion.test.ts
.../css-language-features/server/src/test/completion.test.ts
+50
-4
extensions/css-language-features/server/src/utils/strings.ts
extensions/css-language-features/server/src/utils/strings.ts
+14
-0
extensions/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss
...eatures/server/test/pathCompletionFixtures/scss/_foo.scss
+4
-0
extensions/css-language-features/server/test/pathCompletionFixtures/scss/main.scss
...eatures/server/test/pathCompletionFixtures/scss/main.scss
+4
-0
extensions/css-language-features/test/mocha.opts
extensions/css-language-features/test/mocha.opts
+3
-0
未找到文件。
extensions/css-language-features/.vscode/launch.json
浏览文件 @
803ca903
...
...
@@ -54,6 +54,26 @@
],
"smartStep"
:
true
,
"restart"
:
true
},
{
"name"
:
"Server Unit Tests"
,
"type"
:
"node"
,
"request"
:
"launch"
,
"program"
:
"${workspaceRoot}/node_modules/mocha/bin/_mocha"
,
"stopOnEntry"
:
false
,
"args"
:
[
"--timeout"
,
"999999"
,
"--colors"
],
"cwd"
:
"${workspaceRoot}"
,
"runtimeExecutable"
:
null
,
"runtimeArgs"
:
[],
"env"
:
{},
"sourceMaps"
:
true
,
"outFiles"
:
[
"${workspaceRoot}/server/out/**"
]
}
]
}
\ No newline at end of file
extensions/css-language-features/package.json
浏览文件 @
803ca903
...
...
@@ -19,6 +19,7 @@
"scripts"
:
{
"compile"
:
"gulp compile-extension:css-language-features-client compile-extension:css-language-features-server"
,
"watch"
:
"gulp watch-extension:css-language-features-client watch-extension:css-language-features-server"
,
"test"
:
"mocha"
,
"postinstall"
:
"cd server && yarn install"
,
"install-client-next"
:
"yarn add vscode-languageclient@next"
},
...
...
extensions/css-language-features/server/src/pathCompletion.ts
浏览文件 @
803ca903
...
...
@@ -12,7 +12,7 @@ import { TextDocument, CompletionList, CompletionItemKind, CompletionItem, TextE
import
{
WorkspaceFolder
}
from
'
vscode-languageserver
'
;
import
{
ICompletionParticipant
}
from
'
vscode-css-languageservice
'
;
import
{
startsWith
}
from
'
./utils/strings
'
;
import
{
startsWith
,
endsWith
}
from
'
./utils/strings
'
;
export
function
getPathCompletionParticipant
(
document
:
TextDocument
,
...
...
@@ -21,32 +21,73 @@ export function getPathCompletionParticipant(
):
ICompletionParticipant
{
return
{
onCssURILiteralValue
:
({
position
,
range
,
uriValue
})
=>
{
const
isValueQuoted
=
startsWith
(
uriValue
,
`'`
)
||
startsWith
(
uriValue
,
`"`
);
const
fullValue
=
stripQuotes
(
uriValue
);
const
valueBeforeCursor
=
isValueQuoted
?
fullValue
.
slice
(
0
,
position
.
character
-
(
range
.
start
.
character
+
1
))
:
fullValue
.
slice
(
0
,
position
.
character
-
range
.
start
.
character
);
if
(
fullValue
===
'
.
'
||
fullValue
===
'
..
'
)
{
result
.
isIncomplete
=
true
;
if
(
!
shouldDoPathCompletion
(
uriValue
,
workspaceFolders
))
{
if
(
fullValue
===
'
.
'
||
fullValue
===
'
..
'
)
{
result
.
isIncomplete
=
true
;
}
return
;
}
if
(
!
workspaceFolders
||
workspaceFolders
.
length
===
0
)
{
let
suggestions
=
providePathSuggestions
(
uriValue
,
position
,
range
,
document
,
workspaceFolders
);
result
.
items
=
[...
suggestions
,
...
result
.
items
];
},
onCssImportPath
:
({
position
,
range
,
pathValue
})
=>
{
const
fullValue
=
stripQuotes
(
pathValue
);
if
(
!
shouldDoPathCompletion
(
pathValue
,
workspaceFolders
))
{
if
(
fullValue
===
'
.
'
||
fullValue
===
'
..
'
)
{
result
.
isIncomplete
=
true
;
}
return
;
}
const
workspaceRoot
=
resolveWorkspaceRoot
(
document
,
workspaceFolders
);
const
paths
=
providePaths
(
valueBeforeCursor
,
URI
.
parse
(
document
.
uri
).
fsPath
,
workspaceRoot
);
const
fullValueRange
=
isValueQuoted
?
shiftRange
(
range
,
1
,
-
1
)
:
range
;
const
replaceRange
=
pathToReplaceRange
(
valueBeforeCursor
,
fullValue
,
fullValueRange
);
const
suggestions
=
paths
.
map
(
p
=>
pathToSuggestion
(
p
,
replaceRange
));
let
suggestions
=
providePathSuggestions
(
pathValue
,
position
,
range
,
document
,
workspaceFolders
);
if
(
document
.
languageId
===
'
scss
'
)
{
suggestions
.
forEach
(
s
=>
{
if
(
startsWith
(
s
.
label
,
'
_
'
)
&&
endsWith
(
s
.
label
,
'
.scss
'
))
{
if
(
s
.
textEdit
)
{
s
.
textEdit
.
newText
=
s
.
label
.
slice
(
1
,
-
5
);
}
else
{
s
.
label
=
s
.
label
.
slice
(
1
,
-
5
);
}
}
});
}
result
.
items
=
[...
suggestions
,
...
result
.
items
];
}
};
}
function
providePathSuggestions
(
pathValue
:
string
,
position
:
Position
,
range
:
Range
,
document
:
TextDocument
,
workspaceFolders
:
WorkspaceFolder
[])
{
const
fullValue
=
stripQuotes
(
pathValue
);
const
isValueQuoted
=
startsWith
(
pathValue
,
`'`
)
||
startsWith
(
pathValue
,
`"`
);
const
valueBeforeCursor
=
isValueQuoted
?
fullValue
.
slice
(
0
,
position
.
character
-
(
range
.
start
.
character
+
1
))
:
fullValue
.
slice
(
0
,
position
.
character
-
range
.
start
.
character
);
const
workspaceRoot
=
resolveWorkspaceRoot
(
document
,
workspaceFolders
);
const
paths
=
providePaths
(
valueBeforeCursor
,
URI
.
parse
(
document
.
uri
).
fsPath
,
workspaceRoot
);
const
fullValueRange
=
isValueQuoted
?
shiftRange
(
range
,
1
,
-
1
)
:
range
;
const
replaceRange
=
pathToReplaceRange
(
valueBeforeCursor
,
fullValue
,
fullValueRange
);
const
suggestions
=
paths
.
map
(
p
=>
pathToSuggestion
(
p
,
replaceRange
));
return
suggestions
;
}
function
shouldDoPathCompletion
(
pathValue
:
string
,
workspaceFolders
:
WorkspaceFolder
[]):
boolean
{
const
fullValue
=
stripQuotes
(
pathValue
);
if
(
fullValue
===
'
.
'
||
fullValue
===
'
..
'
)
{
return
false
;
}
if
(
!
workspaceFolders
||
workspaceFolders
.
length
===
0
)
{
return
false
;
}
return
true
;
}
function
stripQuotes
(
fullValue
:
string
)
{
if
(
startsWith
(
fullValue
,
`'`
)
||
startsWith
(
fullValue
,
`"`
))
{
return
fullValue
.
slice
(
1
,
-
1
);
...
...
extensions/css-language-features/server/src/test/completion.test.ts
浏览文件 @
803ca903
...
...
@@ -33,11 +33,11 @@ suite('Completions', () => {
}
};
function
assertCompletions
(
value
:
string
,
expected
:
{
count
?:
number
,
items
?:
ItemDescription
[]
},
testUri
:
string
,
workspaceFolders
?:
WorkspaceFolder
[]):
void
{
function
assertCompletions
(
value
:
string
,
expected
:
{
count
?:
number
,
items
?:
ItemDescription
[]
},
testUri
:
string
,
workspaceFolders
?:
WorkspaceFolder
[]
,
lang
:
string
=
'
css
'
):
void
{
const
offset
=
value
.
indexOf
(
'
|
'
);
value
=
value
.
substr
(
0
,
offset
)
+
value
.
substr
(
offset
+
1
);
const
document
=
TextDocument
.
create
(
testUri
,
'
css
'
,
0
,
value
);
const
document
=
TextDocument
.
create
(
testUri
,
lang
,
0
,
value
);
const
position
=
document
.
positionAt
(
offset
);
if
(
!
workspaceFolders
)
{
...
...
@@ -61,7 +61,7 @@ suite('Completions', () => {
}
}
test
(
'
CSS Path completion
'
,
function
()
{
test
(
'
CSS
url()
Path completion
'
,
function
()
{
let
testUri
=
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test/pathCompletionFixtures/about/about.css
'
)).
toString
();
let
folders
=
[{
name
:
'
x
'
,
uri
:
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test
'
)).
toString
()
}];
...
...
@@ -121,7 +121,7 @@ suite('Completions', () => {
},
testUri
,
folders
);
});
test
(
'
CSS Path Completion - Unquoted url
'
,
function
()
{
test
(
'
CSS
url()
Path Completion - Unquoted url
'
,
function
()
{
let
testUri
=
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test/pathCompletionFixtures/about/about.css
'
)).
toString
();
let
folders
=
[{
name
:
'
x
'
,
uri
:
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test
'
)).
toString
()
}];
...
...
@@ -149,4 +149,50 @@ suite('Completions', () => {
]
},
testUri
,
folders
);
});
test
(
'
CSS @import Path completion
'
,
function
()
{
let
testUri
=
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test/pathCompletionFixtures/about/about.css
'
)).
toString
();
let
folders
=
[{
name
:
'
x
'
,
uri
:
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test
'
)).
toString
()
}];
assertCompletions
(
`@import './|'`
,
{
items
:
[
{
label
:
'
about.css
'
,
resultText
:
`@import './about.css'`
},
{
label
:
'
about.html
'
,
resultText
:
`@import './about.html'`
},
]
},
testUri
,
folders
);
assertCompletions
(
`@import '../|'`
,
{
items
:
[
{
label
:
'
about/
'
,
resultText
:
`@import '../about/'`
},
{
label
:
'
scss/
'
,
resultText
:
`@import '../scss/'`
},
{
label
:
'
index.html
'
,
resultText
:
`@import '../index.html'`
},
{
label
:
'
src/
'
,
resultText
:
`@import '../src/'`
}
]
},
testUri
,
folders
);
});
/**
* For SCSS, `@import 'foo';` can be used for importing partial file `_foo.scss`
*/
test
(
'
SCSS @import Path completion
'
,
function
()
{
let
testCSSUri
=
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test/pathCompletionFixtures/about/about.css
'
)).
toString
();
let
folders
=
[{
name
:
'
x
'
,
uri
:
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test
'
)).
toString
()
}];
/**
* We are in a CSS file, so no special treatment for SCSS partial files
*/
assertCompletions
(
`@import '../scss/|'`
,
{
items
:
[
{
label
:
'
main.scss
'
,
resultText
:
`@import '../scss/main.scss'`
},
{
label
:
'
_foo.scss
'
,
resultText
:
`@import '../scss/_foo.scss'`
}
]
},
testCSSUri
,
folders
);
let
testSCSSUri
=
Uri
.
file
(
path
.
resolve
(
__dirname
,
'
../../test/pathCompletionFixtures/scss/main.scss
'
)).
toString
();
assertCompletions
(
`@import './|'`
,
{
items
:
[
{
label
:
'
_foo.scss
'
,
resultText
:
`@import './foo'`
}
]
},
testSCSSUri
,
folders
,
'
scss
'
);
});
});
\ No newline at end of file
extensions/css-language-features/server/src/utils/strings.ts
浏览文件 @
803ca903
...
...
@@ -17,3 +17,17 @@ export function startsWith(haystack: string, needle: string): boolean {
return
true
;
}
/**
* Determines if haystack ends with needle.
*/
export
function
endsWith
(
haystack
:
string
,
needle
:
string
):
boolean
{
let
diff
=
haystack
.
length
-
needle
.
length
;
if
(
diff
>
0
)
{
return
haystack
.
lastIndexOf
(
needle
)
===
diff
;
}
else
if
(
diff
===
0
)
{
return
haystack
===
needle
;
}
else
{
return
false
;
}
}
extensions/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss
0 → 100644
浏览文件 @
803ca903
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
\ No newline at end of file
extensions/css-language-features/server/test/pathCompletionFixtures/scss/main.scss
0 → 100644
浏览文件 @
803ca903
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
\ No newline at end of file
extensions/css-language-features/test/mocha.opts
0 → 100644
浏览文件 @
803ca903
--ui tdd
--useColors true
server/out/test/**.test.js
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录