Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
c44b7d25
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,发现更多精彩内容 >>
未验证
提交
c44b7d25
编写于
12月 28, 2020
作者:
R
Raymond Zhao
提交者:
GitHub
12月 28, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Refactor Emmet merge lines and select item commands (#113516)
上级
c7dbab59
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
179 addition
and
122 deletion
+179
-122
extensions/emmet/src/mergeLines.ts
extensions/emmet/src/mergeLines.ts
+26
-14
extensions/emmet/src/selectItem.ts
extensions/emmet/src/selectItem.ts
+12
-6
extensions/emmet/src/selectItemHTML.ts
extensions/emmet/src/selectItemHTML.ts
+66
-60
extensions/emmet/src/selectItemStylesheet.ts
extensions/emmet/src/selectItemStylesheet.ts
+60
-42
extensions/emmet/src/util.ts
extensions/emmet/src/util.ts
+15
-0
未找到文件。
extensions/emmet/src/mergeLines.ts
浏览文件 @
c44b7d25
...
...
@@ -4,8 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
{
Node
}
from
'
EmmetNode
'
;
import
{
getNode
,
parseDocument
,
validate
}
from
'
./util
'
;
import
{
Node
}
from
'
EmmetFlatNode
'
;
import
{
getFlatNode
,
offsetRangeToVsRange
,
validate
}
from
'
./util
'
;
import
{
getRootNode
}
from
'
./parseDocument
'
;
export
function
mergeLines
()
{
if
(
!
validate
(
false
)
||
!
vscode
.
window
.
activeTextEditor
)
{
...
...
@@ -14,14 +15,14 @@ export function mergeLines() {
const
editor
=
vscode
.
window
.
activeTextEditor
;
let
rootNode
=
parseDocument
(
editor
.
document
);
const
rootNode
=
getRootNode
(
editor
.
document
,
true
);
if
(
!
rootNode
)
{
return
;
}
return
editor
.
edit
(
editBuilder
=>
{
editor
.
selections
.
reverse
().
forEach
(
selection
=>
{
let
textEdit
=
getRangesToReplace
(
editor
.
document
,
selection
,
rootNode
!
);
const
textEdit
=
getRangesToReplace
(
editor
.
document
,
selection
,
rootNode
);
if
(
textEdit
)
{
editBuilder
.
replace
(
textEdit
.
range
,
textEdit
.
newText
);
}
...
...
@@ -30,25 +31,36 @@ export function mergeLines() {
}
function
getRangesToReplace
(
document
:
vscode
.
TextDocument
,
selection
:
vscode
.
Selection
,
rootNode
:
Node
):
vscode
.
TextEdit
|
undefined
{
let
startNodeToUpdate
:
Node
|
null
;
let
endNodeToUpdate
:
Node
|
null
;
let
startNodeToUpdate
:
Node
|
undefined
;
let
endNodeToUpdate
:
Node
|
undefined
;
const
selectionStart
=
document
.
offsetAt
(
selection
.
start
);
const
selectionEnd
=
document
.
offsetAt
(
selection
.
end
);
if
(
selection
.
isEmpty
)
{
startNodeToUpdate
=
endNodeToUpdate
=
get
Node
(
rootNode
,
selection
.
s
tart
,
true
);
startNodeToUpdate
=
endNodeToUpdate
=
get
FlatNode
(
rootNode
,
selectionS
tart
,
true
);
}
else
{
startNodeToUpdate
=
get
Node
(
rootNode
,
selection
.
s
tart
,
true
);
endNodeToUpdate
=
get
Node
(
rootNode
,
selection
.
e
nd
,
true
);
startNodeToUpdate
=
get
FlatNode
(
rootNode
,
selectionS
tart
,
true
);
endNodeToUpdate
=
get
FlatNode
(
rootNode
,
selectionE
nd
,
true
);
}
if
(
!
startNodeToUpdate
||
!
endNodeToUpdate
||
startNodeToUpdate
.
start
.
line
===
endNodeToUpdate
.
end
.
line
)
{
if
(
!
startNodeToUpdate
||
!
endNodeToUpdate
)
{
return
;
}
let
rangeToReplace
=
new
vscode
.
Range
(
startNodeToUpdate
.
start
,
endNodeToUpdate
.
end
);
let
textToReplaceWith
=
document
.
lineAt
(
startNodeToUpdate
.
start
.
line
).
text
.
substr
(
startNodeToUpdate
.
start
.
character
);
for
(
let
i
=
startNodeToUpdate
.
start
.
line
+
1
;
i
<=
endNodeToUpdate
.
end
.
line
;
i
++
)
{
const
startPos
=
document
.
positionAt
(
startNodeToUpdate
.
start
);
const
startLine
=
startPos
.
line
;
const
startChar
=
startPos
.
character
;
const
endPos
=
document
.
positionAt
(
endNodeToUpdate
.
end
);
const
endLine
=
endPos
.
line
;
if
(
startLine
===
endLine
)
{
return
;
}
const
rangeToReplace
=
offsetRangeToVsRange
(
document
,
startNodeToUpdate
.
start
,
endNodeToUpdate
.
end
);
let
textToReplaceWith
=
document
.
lineAt
(
startLine
).
text
.
substr
(
startChar
);
for
(
let
i
=
startLine
+
1
;
i
<=
endLine
;
i
++
)
{
textToReplaceWith
+=
document
.
lineAt
(
i
).
text
.
trim
();
}
return
new
vscode
.
TextEdit
(
rangeToReplace
,
textToReplaceWith
);
}
\ No newline at end of file
}
extensions/emmet/src/selectItem.ts
浏览文件 @
c44b7d25
...
...
@@ -4,17 +4,19 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
{
validate
,
parseDocument
,
isStyleSheet
}
from
'
./util
'
;
import
{
validate
,
isStyleSheet
}
from
'
./util
'
;
import
{
nextItemHTML
,
prevItemHTML
}
from
'
./selectItemHTML
'
;
import
{
nextItemStylesheet
,
prevItemStylesheet
}
from
'
./selectItemStylesheet
'
;
import
{
HtmlNode
,
CssNode
}
from
'
EmmetNode
'
;
import
{
HtmlNode
,
CssNode
}
from
'
EmmetFlatNode
'
;
import
{
getRootNode
}
from
'
./parseDocument
'
;
export
function
fetchSelectItem
(
direction
:
string
):
void
{
if
(
!
validate
()
||
!
vscode
.
window
.
activeTextEditor
)
{
return
;
}
const
editor
=
vscode
.
window
.
activeTextEditor
;
let
rootNode
=
parseDocument
(
editor
.
document
);
const
document
=
editor
.
document
;
const
rootNode
=
getRootNode
(
document
,
true
);
if
(
!
rootNode
)
{
return
;
}
...
...
@@ -26,12 +28,16 @@ export function fetchSelectItem(direction: string): void {
let
updatedSelection
;
if
(
isStyleSheet
(
editor
.
document
.
languageId
))
{
updatedSelection
=
direction
===
'
next
'
?
nextItemStylesheet
(
selectionStart
,
selectionEnd
,
<
CssNode
>
rootNode
!
)
:
prevItemStylesheet
(
selectionStart
,
selectionEnd
,
<
CssNode
>
rootNode
!
);
updatedSelection
=
direction
===
'
next
'
?
nextItemStylesheet
(
document
,
selectionStart
,
selectionEnd
,
<
CssNode
>
rootNode
)
:
prevItemStylesheet
(
document
,
selectionStart
,
selectionEnd
,
<
CssNode
>
rootNode
);
}
else
{
updatedSelection
=
direction
===
'
next
'
?
nextItemHTML
(
selectionStart
,
selectionEnd
,
editor
,
<
HtmlNode
>
rootNode
!
)
:
prevItemHTML
(
selectionStart
,
selectionEnd
,
editor
,
<
HtmlNode
>
rootNode
!
);
updatedSelection
=
direction
===
'
next
'
?
nextItemHTML
(
document
,
selectionStart
,
selectionEnd
,
<
HtmlNode
>
rootNode
)
:
prevItemHTML
(
document
,
selectionStart
,
selectionEnd
,
<
HtmlNode
>
rootNode
);
}
newSelections
.
push
(
updatedSelection
?
updatedSelection
:
selection
);
});
editor
.
selections
=
newSelections
;
editor
.
revealRange
(
editor
.
selections
[
editor
.
selections
.
length
-
1
]);
}
\ No newline at end of file
}
extensions/emmet/src/selectItemHTML.ts
浏览文件 @
c44b7d25
...
...
@@ -4,11 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
{
getDeepest
Node
,
findNextWord
,
findPrevWord
,
getHtmlNode
,
isNumber
}
from
'
./util
'
;
import
{
HtmlNode
}
from
'
EmmetNode
'
;
import
{
getDeepest
FlatNode
,
findNextWord
,
findPrevWord
,
getHtmlFlatNode
,
offsetRangeToSelection
}
from
'
./util
'
;
import
{
HtmlNode
}
from
'
Emmet
Flat
Node
'
;
export
function
nextItemHTML
(
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
editor
:
vscode
.
TextEditor
,
rootNode
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
let
currentNode
=
getHtmlNode
(
editor
.
document
,
rootNode
,
selectionEnd
,
false
);
export
function
nextItemHTML
(
document
:
vscode
.
TextDocument
,
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
rootNode
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
const
selectionEndOffset
=
document
.
offsetAt
(
selectionEnd
);
let
currentNode
=
getHtmlFlatNode
(
document
.
getText
(),
rootNode
,
selectionEndOffset
,
false
);
let
nextNode
:
HtmlNode
|
undefined
=
undefined
;
if
(
!
currentNode
)
{
...
...
@@ -17,13 +18,16 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
if
(
currentNode
.
type
!==
'
comment
'
)
{
// If cursor is in the tag name, select tag
if
(
selectionEnd
.
isBefore
(
currentNode
.
open
.
start
.
translate
(
0
,
currentNode
.
name
.
length
)))
{
return
getSelectionFromNode
(
currentNode
);
if
(
currentNode
.
open
&&
selectionEndOffset
<
currentNode
.
open
.
start
+
currentNode
.
name
.
length
)
{
return
getSelectionFromNode
(
document
,
currentNode
);
}
// If cursor is in the open tag, look for attributes
if
(
selectionEnd
.
isBefore
(
currentNode
.
open
.
end
))
{
let
attrSelection
=
getNextAttribute
(
selectionStart
,
selectionEnd
,
currentNode
);
if
(
currentNode
.
open
&&
selectionEndOffset
<
currentNode
.
open
.
end
)
{
const
selectionStartOffset
=
document
.
offsetAt
(
selectionStart
);
const
attrSelection
=
getNextAttribute
(
document
,
selectionStartOffset
,
selectionEndOffset
,
currentNode
);
if
(
attrSelection
)
{
return
attrSelection
;
}
...
...
@@ -31,12 +35,11 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
// Get the first child of current node which is right after the cursor and is not a comment
nextNode
=
currentNode
.
firstChild
;
while
(
nextNode
&&
(
selectionEnd
.
isAfterOrEqual
(
nextNode
.
end
)
||
nextNode
.
type
===
'
comment
'
))
{
while
(
nextNode
&&
(
selectionEnd
Offset
>=
nextNode
.
end
||
nextNode
.
type
===
'
comment
'
))
{
nextNode
=
nextNode
.
nextSibling
;
}
}
// Get next sibling of current node which is not a comment. If none is found try the same on the parent
while
(
!
nextNode
&&
currentNode
)
{
if
(
currentNode
.
nextSibling
)
{
...
...
@@ -50,33 +53,36 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
}
}
return
nextNode
&&
getSelectionFromNode
(
nextNode
);
return
nextNode
&&
getSelectionFromNode
(
document
,
nextNode
);
}
export
function
prevItemHTML
(
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
editor
:
vscode
.
TextEditor
,
rootNode
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
let
currentNode
=
getHtmlNode
(
editor
.
document
,
rootNode
,
selectionStart
,
false
);
export
function
prevItemHTML
(
document
:
vscode
.
TextDocument
,
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
rootNode
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
const
selectionStartOffset
=
document
.
offsetAt
(
selectionStart
);
let
currentNode
=
getHtmlFlatNode
(
document
.
getText
(),
rootNode
,
selectionStartOffset
,
false
);
let
prevNode
:
HtmlNode
|
undefined
=
undefined
;
if
(
!
currentNode
)
{
return
;
}
if
(
currentNode
.
type
!==
'
comment
'
&&
selectionStart
.
translate
(
0
,
-
1
).
isAfter
(
currentNode
.
open
.
start
))
{
if
(
selectionStart
.
isBefore
(
currentNode
.
open
.
end
)
||
!
currentNode
.
firstChild
||
selectionEnd
.
isBeforeOrEqual
(
currentNode
.
firstChild
.
start
))
{
const
selectionEndOffset
=
document
.
offsetAt
(
selectionEnd
);
if
(
currentNode
.
open
&&
currentNode
.
type
!==
'
comment
'
&&
selectionStartOffset
-
1
>
currentNode
.
open
.
start
)
{
if
(
selectionStartOffset
<
currentNode
.
open
.
end
||
!
currentNode
.
firstChild
||
selectionEndOffset
<=
currentNode
.
firstChild
.
start
)
{
prevNode
=
currentNode
;
}
else
{
// Select the child that appears just before the cursor and is not a comment
prevNode
=
currentNode
.
firstChild
;
let
oldOption
:
HtmlNode
|
undefined
=
undefined
;
while
(
prevNode
.
nextSibling
&&
selectionStart
.
isAfterOrEqual
(
prevNode
.
nextSibling
.
end
)
)
{
while
(
prevNode
.
nextSibling
&&
selectionStart
Offset
>=
prevNode
.
nextSibling
.
end
)
{
if
(
prevNode
&&
prevNode
.
type
!==
'
comment
'
)
{
oldOption
=
prevNode
;
}
prevNode
=
prevNode
.
nextSibling
;
}
prevNode
=
<
HtmlNode
>
getDeepestNode
((
prevNode
&&
prevNode
.
type
!==
'
comment
'
)
?
prevNode
:
oldOption
);
prevNode
=
<
HtmlNode
>
getDeepest
Flat
Node
((
prevNode
&&
prevNode
.
type
!==
'
comment
'
)
?
prevNode
:
oldOption
);
}
}
...
...
@@ -84,7 +90,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
while
(
!
prevNode
&&
currentNode
)
{
if
(
currentNode
.
previousSibling
)
{
if
(
currentNode
.
previousSibling
.
type
!==
'
comment
'
)
{
prevNode
=
<
HtmlNode
>
getDeepestNode
(
currentNode
.
previousSibling
);
prevNode
=
<
HtmlNode
>
getDeepest
Flat
Node
(
currentNode
.
previousSibling
);
}
else
{
currentNode
=
currentNode
.
previousSibling
;
}
...
...
@@ -98,66 +104,66 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
return
undefined
;
}
let
attrSelection
=
getPrevAttribute
(
selectionStart
,
selectionEnd
,
prevNode
);
return
attrSelection
?
attrSelection
:
getSelectionFromNode
(
prevNode
);
const
attrSelection
=
getPrevAttribute
(
document
,
selectionStartOffset
,
selectionEndOffset
,
prevNode
);
return
attrSelection
?
attrSelection
:
getSelectionFromNode
(
document
,
prevNode
);
}
function
getSelectionFromNode
(
node
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
function
getSelectionFromNode
(
document
:
vscode
.
TextDocument
,
node
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
if
(
node
&&
node
.
open
)
{
let
selectionStart
=
(
<
vscode
.
Position
>
node
.
open
.
start
).
translate
(
0
,
1
);
let
selectionEnd
=
selectionStart
.
translate
(
0
,
node
.
name
.
length
);
return
new
vscode
.
Selection
(
selectionStart
,
selectionEnd
);
const
selectionStart
=
node
.
open
.
start
+
1
;
const
selectionEnd
=
selectionStart
+
node
.
name
.
length
;
return
offsetRangeToSelection
(
document
,
selectionStart
,
selectionEnd
);
}
return
undefined
;
}
function
getNextAttribute
(
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
node
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
function
getNextAttribute
(
document
:
vscode
.
TextDocument
,
selectionStart
:
number
,
selectionEnd
:
number
,
node
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
if
(
!
node
.
attributes
||
node
.
attributes
.
length
===
0
||
node
.
type
===
'
comment
'
)
{
return
;
}
for
(
const
attr
of
node
.
attributes
)
{
if
(
selectionEnd
.
isBefore
(
attr
.
start
)
)
{
if
(
selectionEnd
<
attr
.
start
)
{
// select full attr
return
new
vscode
.
Selection
(
attr
.
start
,
attr
.
end
);
return
offsetRangeToSelection
(
document
,
attr
.
start
,
attr
.
end
);
}
if
(
!
attr
.
value
||
(
<
vscode
.
Position
>
attr
.
value
.
start
).
isEqual
(
attr
.
value
.
end
)
)
{
if
(
!
attr
.
value
||
attr
.
value
.
start
===
attr
.
value
.
end
)
{
// No attr value to select
continue
;
}
if
((
selectionStart
.
isEqual
(
attr
.
start
)
&&
selectionEnd
.
isEqual
(
attr
.
end
))
||
selectionEnd
.
isBefore
(
attr
.
value
.
start
))
{
if
((
selectionStart
===
attr
.
start
&&
selectionEnd
===
attr
.
end
)
||
selectionEnd
<
attr
.
value
.
start
)
{
// cursor is in attr name, so select full attr value
return
new
vscode
.
Selection
(
attr
.
value
.
start
,
attr
.
value
.
end
);
return
offsetRangeToSelection
(
document
,
attr
.
value
.
start
,
attr
.
value
.
end
);
}
// Fetch the next word in the attr value
if
(
attr
.
value
.
toString
().
indexOf
(
'
'
)
===
-
1
)
{
// attr value does not have space, so no next word to find
continue
;
}
let
pos
:
number
|
undefined
=
undefined
;
if
(
selectionStart
.
isEqual
(
attr
.
value
.
start
)
&&
selectionEnd
.
isEqual
(
attr
.
value
.
end
)
)
{
if
(
selectionStart
===
attr
.
value
.
start
&&
selectionEnd
===
attr
.
value
.
end
)
{
pos
=
-
1
;
}
if
(
pos
===
undefined
&&
selectionEnd
.
isBefore
(
attr
.
end
))
{
pos
=
selectionEnd
.
character
-
attr
.
value
.
start
.
character
-
1
;
if
(
pos
===
undefined
&&
selectionEnd
<
attr
.
end
)
{
const
selectionEndCharacter
=
document
.
positionAt
(
selectionEnd
).
character
;
const
attrValueStartCharacter
=
document
.
positionAt
(
attr
.
value
.
start
).
character
;
pos
=
selectionEndCharacter
-
attrValueStartCharacter
-
1
;
}
if
(
pos
!==
undefined
)
{
le
t
[
newSelectionStartOffset
,
newSelectionEndOffset
]
=
findNextWord
(
attr
.
value
.
toString
(),
pos
);
if
(
!
isNumber
(
newSelectionStartOffset
)
||
!
isNumber
(
newSelectionEndOffset
)
)
{
cons
t
[
newSelectionStartOffset
,
newSelectionEndOffset
]
=
findNextWord
(
attr
.
value
.
toString
(),
pos
);
if
(
newSelectionStartOffset
===
undefined
||
newSelectionEndOffset
===
undefined
)
{
return
;
}
if
(
newSelectionStartOffset
>=
0
&&
newSelectionEndOffset
>=
0
)
{
const
newSelectionStart
=
(
<
vscode
.
Position
>
attr
.
value
.
start
).
translate
(
0
,
newSelectionStartOffset
)
;
const
newSelectionEnd
=
(
<
vscode
.
Position
>
attr
.
value
.
start
).
translate
(
0
,
newSelectionEndOffset
)
;
return
new
vscode
.
Selection
(
newSelectionStart
,
newSelectionEnd
);
const
newSelectionStart
=
attr
.
value
.
start
+
newSelectionStartOffset
;
const
newSelectionEnd
=
attr
.
value
.
start
+
newSelectionEndOffset
;
return
offsetRangeToSelection
(
document
,
newSelectionStart
,
newSelectionEnd
);
}
}
...
...
@@ -166,44 +172,44 @@ function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.
return
;
}
function
getPrevAttribute
(
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
node
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
function
getPrevAttribute
(
document
:
vscode
.
TextDocument
,
selectionStart
:
number
,
selectionEnd
:
number
,
node
:
HtmlNode
):
vscode
.
Selection
|
undefined
{
if
(
!
node
.
attributes
||
node
.
attributes
.
length
===
0
||
node
.
type
===
'
comment
'
)
{
return
;
}
for
(
let
i
=
node
.
attributes
.
length
-
1
;
i
>=
0
;
i
--
)
{
let
attr
=
node
.
attributes
[
i
];
if
(
selectionStart
.
isBeforeOrEqual
(
attr
.
start
))
{
const
attr
=
node
.
attributes
[
i
];
if
(
selectionStart
<=
attr
.
start
)
{
continue
;
}
if
(
!
attr
.
value
||
(
<
vscode
.
Position
>
attr
.
value
.
start
).
isEqual
(
attr
.
value
.
end
)
||
selectionStart
.
isBefore
(
attr
.
value
.
start
)
)
{
if
(
!
attr
.
value
||
attr
.
value
.
start
===
attr
.
value
.
end
||
selectionStart
<
attr
.
value
.
start
)
{
// select full attr
return
new
vscode
.
Selection
(
attr
.
start
,
attr
.
end
);
return
offsetRangeToSelection
(
document
,
attr
.
start
,
attr
.
end
);
}
if
(
selectionStart
.
isEqual
(
attr
.
value
.
start
)
)
{
if
(
selectionEnd
.
isAfterOrEqual
(
attr
.
value
.
end
)
)
{
if
(
selectionStart
===
attr
.
value
.
start
)
{
if
(
selectionEnd
>=
attr
.
value
.
end
)
{
// select full attr
return
new
vscode
.
Selection
(
attr
.
start
,
attr
.
end
);
return
offsetRangeToSelection
(
document
,
attr
.
start
,
attr
.
end
);
}
// select attr value
return
new
vscode
.
Selection
(
attr
.
value
.
start
,
attr
.
value
.
end
);
return
offsetRangeToSelection
(
document
,
attr
.
value
.
start
,
attr
.
value
.
end
);
}
// Fetch the prev word in the attr value
let
pos
=
selectionStart
.
isAfter
(
attr
.
value
.
end
)
?
attr
.
value
.
toString
().
length
:
selectionStart
.
character
-
attr
.
value
.
start
.
character
;
let
[
newSelectionStartOffset
,
newSelectionEndOffset
]
=
findPrevWord
(
attr
.
value
.
toString
(),
pos
);
if
(
!
isNumber
(
newSelectionStartOffset
)
||
!
isNumber
(
newSelectionEndOffset
))
{
const
selectionStartCharacter
=
document
.
positionAt
(
selectionStart
).
character
;
const
attrValueStartCharacter
=
document
.
positionAt
(
attr
.
value
.
start
).
character
;
const
pos
=
selectionStart
>
attr
.
value
.
end
?
attr
.
value
.
toString
().
length
:
selectionStartCharacter
-
attrValueStartCharacter
;
const
[
newSelectionStartOffset
,
newSelectionEndOffset
]
=
findPrevWord
(
attr
.
value
.
toString
(),
pos
);
if
(
newSelectionStartOffset
===
undefined
||
newSelectionEndOffset
===
undefined
)
{
return
;
}
if
(
newSelectionStartOffset
>=
0
&&
newSelectionEndOffset
>=
0
)
{
const
newSelectionStart
=
(
<
vscode
.
Position
>
attr
.
value
.
start
).
translate
(
0
,
newSelectionStartOffset
)
;
const
newSelectionEnd
=
(
<
vscode
.
Position
>
attr
.
value
.
start
).
translate
(
0
,
newSelectionEndOffset
)
;
return
new
vscode
.
Selection
(
newSelectionStart
,
newSelectionEnd
);
const
newSelectionStart
=
attr
.
value
.
start
+
newSelectionStartOffset
;
const
newSelectionEnd
=
attr
.
value
.
start
+
newSelectionEndOffset
;
return
offsetRangeToSelection
(
document
,
newSelectionStart
,
newSelectionEnd
);
}
}
...
...
extensions/emmet/src/selectItemStylesheet.ts
浏览文件 @
c44b7d25
...
...
@@ -4,11 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
{
getDeepest
Node
,
findNextWord
,
findPrevWord
,
getNode
}
from
'
./util
'
;
import
{
Node
,
CssNode
,
Rule
,
Property
}
from
'
EmmetNode
'
;
import
{
getDeepest
FlatNode
,
findNextWord
,
findPrevWord
,
getFlatNode
,
offsetRangeToSelection
}
from
'
./util
'
;
import
{
Node
,
CssNode
,
Rule
,
Property
}
from
'
Emmet
Flat
Node
'
;
export
function
nextItemStylesheet
(
startOffset
:
vscode
.
Position
,
endOffset
:
vscode
.
Position
,
rootNode
:
Node
):
vscode
.
Selection
|
undefined
{
let
currentNode
=
<
CssNode
>
getNode
(
rootNode
,
endOffset
,
true
);
export
function
nextItemStylesheet
(
document
:
vscode
.
TextDocument
,
startPosition
:
vscode
.
Position
,
endPosition
:
vscode
.
Position
,
rootNode
:
Node
):
vscode
.
Selection
|
undefined
{
const
startOffset
=
document
.
offsetAt
(
startPosition
);
const
endOffset
=
document
.
offsetAt
(
endPosition
);
let
currentNode
:
CssNode
|
undefined
=
<
CssNode
>
getFlatNode
(
rootNode
,
endOffset
,
true
);
if
(
!
currentNode
)
{
currentNode
=
<
CssNode
>
rootNode
;
}
...
...
@@ -16,27 +18,31 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
return
;
}
// Full property is selected, so select full property value next
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
.
isEqual
(
currentNode
.
start
)
&&
endOffset
.
isEqual
(
currentNode
.
end
))
{
return
getSelectionFromProperty
(
currentNode
,
startOffset
,
endOffset
,
true
,
'
next
'
);
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
===
currentNode
.
start
&&
endOffset
===
currentNode
.
end
)
{
return
getSelectionFromProperty
(
document
,
currentNode
,
startOffset
,
endOffset
,
true
,
'
next
'
);
}
// Part or whole of propertyValue is selected, so select the next word in the propertyValue
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
.
isAfterOrEqual
((
<
Property
>
currentNode
).
valueToken
.
start
)
&&
endOffset
.
isBeforeOrEqual
((
<
Property
>
currentNode
).
valueToken
.
end
))
{
let
singlePropertyValue
=
getSelectionFromProperty
(
currentNode
,
startOffset
,
endOffset
,
false
,
'
next
'
);
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
>=
(
<
Property
>
currentNode
).
valueToken
.
start
&&
endOffset
<=
(
<
Property
>
currentNode
).
valueToken
.
end
)
{
let
singlePropertyValue
=
getSelectionFromProperty
(
document
,
currentNode
,
startOffset
,
endOffset
,
false
,
'
next
'
);
if
(
singlePropertyValue
)
{
return
singlePropertyValue
;
}
}
// Cursor is in the selector or in a property
if
((
currentNode
.
type
===
'
rule
'
&&
endOffset
.
isBefore
((
<
Rule
>
currentNode
).
selectorToken
.
end
)
)
||
(
currentNode
.
type
===
'
property
'
&&
endOffset
.
isBefore
((
<
Property
>
currentNode
).
valueToken
.
end
)
))
{
return
getSelectionFromNode
(
currentNode
);
if
((
currentNode
.
type
===
'
rule
'
&&
endOffset
<
(
<
Rule
>
currentNode
).
selectorToken
.
end
)
||
(
currentNode
.
type
===
'
property
'
&&
endOffset
<
(
<
Property
>
currentNode
).
valueToken
.
end
))
{
return
getSelectionFromNode
(
document
,
currentNode
);
}
// Get the first child of current node which is right after the cursor
let
nextNode
=
currentNode
.
firstChild
;
while
(
nextNode
&&
endOffset
.
isAfterOrEqual
(
nextNode
.
end
)
)
{
while
(
nextNode
&&
endOffset
>=
nextNode
.
end
)
{
nextNode
=
nextNode
.
nextSibling
;
}
...
...
@@ -46,12 +52,13 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
currentNode
=
currentNode
.
parent
;
}
return
getSelectionFromNode
(
nextNode
);
return
nextNode
?
getSelectionFromNode
(
document
,
nextNode
)
:
undefined
;
}
export
function
prevItemStylesheet
(
startOffset
:
vscode
.
Position
,
endOffset
:
vscode
.
Position
,
rootNode
:
CssNode
):
vscode
.
Selection
|
undefined
{
let
currentNode
=
<
CssNode
>
getNode
(
rootNode
,
startOffset
,
false
);
export
function
prevItemStylesheet
(
document
:
vscode
.
TextDocument
,
startPosition
:
vscode
.
Position
,
endPosition
:
vscode
.
Position
,
rootNode
:
CssNode
):
vscode
.
Selection
|
undefined
{
const
startOffset
=
document
.
offsetAt
(
startPosition
);
const
endOffset
=
document
.
offsetAt
(
endPosition
);
let
currentNode
=
<
CssNode
>
getFlatNode
(
rootNode
,
startOffset
,
false
);
if
(
!
currentNode
)
{
currentNode
=
rootNode
;
}
...
...
@@ -60,70 +67,80 @@ export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
// Full property value is selected, so select the whole property next
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
.
isEqual
((
<
Property
>
currentNode
).
valueToken
.
start
)
&&
endOffset
.
isEqual
((
<
Property
>
currentNode
).
valueToken
.
end
))
{
return
getSelectionFromNode
(
currentNode
);
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
===
(
<
Property
>
currentNode
).
valueToken
.
start
&&
endOffset
===
(
<
Property
>
currentNode
).
valueToken
.
end
)
{
return
getSelectionFromNode
(
document
,
currentNode
);
}
// Part of propertyValue is selected, so select the prev word in the propertyValue
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
.
isAfterOrEqual
((
<
Property
>
currentNode
).
valueToken
.
start
)
&&
endOffset
.
isBeforeOrEqual
((
<
Property
>
currentNode
).
valueToken
.
end
))
{
let
singlePropertyValue
=
getSelectionFromProperty
(
currentNode
,
startOffset
,
endOffset
,
false
,
'
prev
'
);
if
(
currentNode
.
type
===
'
property
'
&&
startOffset
>=
(
<
Property
>
currentNode
).
valueToken
.
start
&&
endOffset
<=
(
<
Property
>
currentNode
).
valueToken
.
end
)
{
let
singlePropertyValue
=
getSelectionFromProperty
(
document
,
currentNode
,
startOffset
,
endOffset
,
false
,
'
prev
'
);
if
(
singlePropertyValue
)
{
return
singlePropertyValue
;
}
}
if
(
currentNode
.
type
===
'
property
'
||
!
currentNode
.
firstChild
||
(
currentNode
.
type
===
'
rule
'
&&
startOffset
.
isBeforeOrEqual
(
currentNode
.
firstChild
.
start
)))
{
return
getSelectionFromNode
(
currentNode
);
if
(
currentNode
.
type
===
'
property
'
||
!
currentNode
.
firstChild
||
(
currentNode
.
type
===
'
rule
'
&&
startOffset
<=
currentNode
.
firstChild
.
start
))
{
return
getSelectionFromNode
(
document
,
currentNode
);
}
// Select the child that appears just before the cursor
let
prevNode
=
currentNode
.
firstChild
;
while
(
prevNode
.
nextSibling
&&
startOffset
.
isAfterOrEqual
(
prevNode
.
nextSibling
.
end
)
)
{
let
prevNode
:
CssNode
|
undefined
=
currentNode
.
firstChild
;
while
(
prevNode
.
nextSibling
&&
startOffset
>=
prevNode
.
nextSibling
.
end
)
{
prevNode
=
prevNode
.
nextSibling
;
}
prevNode
=
<
CssNode
>
getDeepestNode
(
prevNode
);
return
getSelectionFromProperty
(
prevNode
,
startOffset
,
endOffset
,
false
,
'
prev
'
);
prevNode
=
<
CssNode
|
undefined
>
getDeepestFlatNode
(
prevNode
);
return
getSelectionFromProperty
(
document
,
prevNode
,
startOffset
,
endOffset
,
false
,
'
prev
'
);
}
function
getSelectionFromNode
(
node
:
Node
):
vscode
.
Selection
|
undefined
{
function
getSelectionFromNode
(
document
:
vscode
.
TextDocument
,
node
:
Node
|
undefined
):
vscode
.
Selection
|
undefined
{
if
(
!
node
)
{
return
;
}
le
t
nodeToSelect
=
node
.
type
===
'
rule
'
?
(
<
Rule
>
node
).
selectorToken
:
node
;
return
new
vscode
.
Selection
(
nodeToSelect
.
start
,
nodeToSelect
.
end
);
cons
t
nodeToSelect
=
node
.
type
===
'
rule
'
?
(
<
Rule
>
node
).
selectorToken
:
node
;
return
offsetRangeToSelection
(
document
,
nodeToSelect
.
start
,
nodeToSelect
.
end
);
}
function
getSelectionFromProperty
(
node
:
Node
,
selectionStart
:
vscode
.
Position
,
selectionEnd
:
vscode
.
Position
,
selectFullValue
:
boolean
,
direction
:
string
):
vscode
.
Selection
|
undefined
{
function
getSelectionFromProperty
(
document
:
vscode
.
TextDocument
,
node
:
Node
|
undefined
,
selectionStart
:
number
,
selectionEnd
:
number
,
selectFullValue
:
boolean
,
direction
:
string
):
vscode
.
Selection
|
undefined
{
if
(
!
node
||
node
.
type
!==
'
property
'
)
{
return
;
}
const
propertyNode
=
<
Property
>
node
;
let
propertyValue
=
propertyNode
.
valueToken
.
stream
.
substring
(
propertyNode
.
valueToken
.
start
,
propertyNode
.
valueToken
.
end
);
selectFullValue
=
selectFullValue
||
(
direction
===
'
prev
'
&&
selectionStart
.
isEqual
(
propertyNode
.
valueToken
.
start
)
&&
selectionEnd
.
isBefore
(
propertyNode
.
valueToken
.
end
));
selectFullValue
=
selectFullValue
||
(
direction
===
'
prev
'
&&
selectionStart
===
propertyNode
.
valueToken
.
start
&&
selectionEnd
<
propertyNode
.
valueToken
.
end
);
if
(
selectFullValue
)
{
return
new
vscode
.
Selection
(
propertyNode
.
valueToken
.
start
,
propertyNode
.
valueToken
.
end
);
return
offsetRangeToSelection
(
document
,
propertyNode
.
valueToken
.
start
,
propertyNode
.
valueToken
.
end
);
}
let
pos
:
number
=
-
1
;
if
(
direction
===
'
prev
'
)
{
if
(
selectionStart
.
isEqual
(
propertyNode
.
valueToken
.
start
)
)
{
if
(
selectionStart
===
propertyNode
.
valueToken
.
start
)
{
return
;
}
pos
=
selectionStart
.
isAfter
(
propertyNode
.
valueToken
.
end
)
?
propertyValue
.
length
:
selectionStart
.
character
-
propertyNode
.
valueToken
.
start
.
character
;
}
if
(
direction
===
'
next
'
)
{
if
(
selectionEnd
.
isEqual
(
propertyNode
.
valueToken
.
end
)
&&
(
selectionStart
.
isAfter
(
propertyNode
.
valueToken
.
start
)
||
propertyValue
.
indexOf
(
'
'
)
===
-
1
))
{
const
selectionStartChar
=
document
.
positionAt
(
selectionStart
).
character
;
const
tokenStartChar
=
document
.
positionAt
(
propertyNode
.
valueToken
.
start
).
character
;
pos
=
selectionStart
>
propertyNode
.
valueToken
.
end
?
propertyValue
.
length
:
selectionStartChar
-
tokenStartChar
;
}
else
if
(
direction
===
'
next
'
)
{
if
(
selectionEnd
===
propertyNode
.
valueToken
.
end
&&
(
selectionStart
>
propertyNode
.
valueToken
.
start
||
!
propertyValue
.
includes
(
'
'
)))
{
return
;
}
pos
=
selectionEnd
.
isEqual
(
propertyNode
.
valueToken
.
end
)
?
-
1
:
selectionEnd
.
character
-
propertyNode
.
valueToken
.
start
.
character
-
1
;
const
selectionEndChar
=
document
.
positionAt
(
selectionEnd
).
character
;
const
tokenStartChar
=
document
.
positionAt
(
propertyNode
.
valueToken
.
start
).
character
;
pos
=
selectionEnd
===
propertyNode
.
valueToken
.
end
?
-
1
:
selectionEndChar
-
tokenStartChar
-
1
;
}
...
...
@@ -132,8 +149,9 @@ function getSelectionFromProperty(node: Node, selectionStart: vscode.Position, s
return
;
}
const
newSelectionStart
=
(
<
vscode
.
Position
>
propertyNode
.
valueToken
.
start
).
translate
(
0
,
newSelectionStartOffset
);
const
newSelectionEnd
=
(
<
vscode
.
Position
>
propertyNode
.
valueToken
.
start
).
translate
(
0
,
newSelectionEndOffset
);
const
tokenStart
=
document
.
positionAt
(
propertyNode
.
valueToken
.
start
);
const
newSelectionStart
=
tokenStart
.
translate
(
0
,
newSelectionStartOffset
);
const
newSelectionEnd
=
tokenStart
.
translate
(
0
,
newSelectionEndOffset
);
return
new
vscode
.
Selection
(
newSelectionStart
,
newSelectionEnd
);
}
...
...
extensions/emmet/src/util.ts
浏览文件 @
c44b7d25
...
...
@@ -473,6 +473,21 @@ export function getDeepestNode(node: Node | undefined): Node | undefined {
return
undefined
;
}
/**
* Returns the deepest non comment node under given node
*/
export
function
getDeepestFlatNode
(
node
:
FlatNode
|
undefined
):
FlatNode
|
undefined
{
if
(
!
node
||
!
node
.
children
||
node
.
children
.
length
===
0
||
!
node
.
children
.
find
(
x
=>
x
.
type
!==
'
comment
'
))
{
return
node
;
}
for
(
let
i
=
node
.
children
.
length
-
1
;
i
>=
0
;
i
--
)
{
if
(
node
.
children
[
i
].
type
!==
'
comment
'
)
{
return
getDeepestFlatNode
(
node
.
children
[
i
]);
}
}
return
undefined
;
}
export
function
findNextWord
(
propertyValue
:
string
,
pos
:
number
):
[
number
|
undefined
,
number
|
undefined
]
{
let
foundSpace
=
pos
===
-
1
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录