Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
bbe82060
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,发现更多精彩内容 >>
提交
bbe82060
编写于
5月 24, 2017
作者:
J
Johannes Rieken
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
debt - remove unused snippet code
上级
9532abde
变更
6
展开全部
隐藏空白更改
内联
并排
Showing
6 changed file
with
62 addition
and
2140 deletion
+62
-2140
src/vs/editor/contrib/snippet/common/snippet.ts
src/vs/editor/contrib/snippet/common/snippet.ts
+0
-405
src/vs/editor/contrib/snippet/common/snippetController.ts
src/vs/editor/contrib/snippet/common/snippetController.ts
+0
-762
src/vs/editor/contrib/snippet/common/snippetVariables.ts
src/vs/editor/contrib/snippet/common/snippetVariables.ts
+2
-67
src/vs/editor/contrib/snippet/test/common/snippet.test.ts
src/vs/editor/contrib/snippet/test/common/snippet.test.ts
+0
-351
src/vs/editor/contrib/snippet/test/common/snippetController.test.ts
...tor/contrib/snippet/test/common/snippetController.test.ts
+0
-553
src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts
.../workbench/parts/emmet/electron-browser/editorAccessor.ts
+60
-2
未找到文件。
src/vs/editor/contrib/snippet/common/snippet.ts
已删除
100644 → 0
浏览文件 @
9532abde
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
strings
from
'
vs/base/common/strings
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
Marker
,
Variable
,
Placeholder
,
Text
,
SnippetParser
,
walk
}
from
'
vs/editor/contrib/snippet/common/snippetParser
'
;
export
interface
IIndentationNormalizer
{
normalizeIndentation
(
str
:
string
):
string
;
}
export
interface
IPlaceHolder
{
id
:
string
;
value
:
string
;
occurences
:
Range
[];
}
export
interface
ICodeSnippet
{
lines
:
string
[];
placeHolders
:
IPlaceHolder
[];
finishPlaceHolderIndex
:
number
;
}
export
interface
ISnippetVariableResolver
{
resolve
(
name
:
string
):
string
;
}
export
class
CodeSnippet
implements
ICodeSnippet
{
static
fromTextmate
(
template
:
string
,
variableResolver
?:
ISnippetVariableResolver
):
CodeSnippet
{
const
marker
=
new
SnippetParser
(
true
,
false
).
parse
(
template
);
const
snippet
=
new
CodeSnippet
();
_resolveSnippetVariables
(
marker
,
variableResolver
);
_fillCodeSnippetFromMarker
(
snippet
,
marker
);
return
snippet
;
}
static
fromInternal
(
template
:
string
):
CodeSnippet
{
const
marker
=
new
SnippetParser
(
false
,
true
).
parse
(
template
);
const
snippet
=
new
CodeSnippet
();
_fillCodeSnippetFromMarker
(
snippet
,
marker
);
return
snippet
;
}
static
none
(
template
:
string
):
CodeSnippet
{
const
snippet
=
new
CodeSnippet
();
snippet
.
lines
=
template
.
split
(
/
\r\n
|
\n
|
\r
/
);
return
snippet
;
}
static
fixEmmetFinalTabstop
(
template
:
string
):
string
{
let
matchFinalStops
=
template
.
match
(
/
\$\{
0
\}
|
\$
0/g
);
if
(
!
matchFinalStops
||
matchFinalStops
.
length
===
1
)
{
return
template
;
}
// string to string conversion that tries to fix the
// snippet in-place
let
marker
=
new
SnippetParser
(
true
,
false
).
parse
(
template
);
let
maxIndex
=
-
Number
.
MIN_VALUE
;
// find highest placeholder index
walk
(
marker
,
candidate
=>
{
if
(
candidate
instanceof
Placeholder
)
{
let
index
=
Number
(
candidate
.
index
);
if
(
index
>
maxIndex
)
{
maxIndex
=
index
;
}
}
return
true
;
});
// rewrite final tabstops
walk
(
marker
,
candidate
=>
{
if
(
candidate
instanceof
Placeholder
)
{
if
(
candidate
.
isFinalTabstop
)
{
candidate
.
index
=
String
(
++
maxIndex
);
}
}
return
true
;
});
// write back as string
function
toSnippetString
(
marker
:
Marker
):
string
{
if
(
marker
instanceof
Text
)
{
return
marker
.
string
;
}
else
if
(
marker
instanceof
Placeholder
)
{
if
(
marker
.
defaultValue
.
length
>
0
)
{
return
`
\$
{
${
marker
.
index
}
:
${
marker
.
defaultValue
.
map
(
toSnippetString
).
join
(
''
)}
}`
;
}
else
{
return
`
\$
${
marker
.
index
}
`
;
}
}
else
if
(
marker
instanceof
Variable
)
{
if
(
marker
.
defaultValue
.
length
>
0
)
{
return
`
\$
{
${
marker
.
name
}
:
${
marker
.
defaultValue
.
map
(
toSnippetString
).
join
(
''
)}
}`
;
}
else
{
return
`
\$
${
marker
.
name
}
`
;
}
}
else
{
throw
new
Error
(
'
unexpected marker:
'
+
marker
);
}
}
return
marker
.
map
(
toSnippetString
).
join
(
''
);
}
static
fromEmmet
(
template
:
string
):
CodeSnippet
{
CodeSnippet
.
fixEmmetFinalTabstop
(
template
);
let
matchFinalStops
=
template
.
match
(
/
\$\{
0
\}
|
\$
0/g
);
if
(
!
matchFinalStops
||
matchFinalStops
.
length
===
1
)
{
return
CodeSnippet
.
fromTextmate
(
template
);
}
// Emmet sometimes returns snippets with multiple ${0}
// In such cases, replace ${0} with incremental tab stops
const
snippetMarkers
:
Marker
[]
=
new
SnippetParser
(
true
,
false
).
parse
(
template
)
||
[];
let
getMaxTabStop
=
(
markers
:
Marker
[]):
number
=>
{
let
currentMaxTabStop
=
-
1
;
markers
.
forEach
(
marker
=>
{
if
(
marker
instanceof
Placeholder
&&
/^
\d
+$/
.
test
(
marker
[
'
index
'
]))
{
let
currentTabStop
=
Number
(
marker
[
'
index
'
]);
let
nestedMaxTabStop
=
getMaxTabStop
(
marker
[
'
defaultValue
'
]
||
[]);
currentMaxTabStop
=
Math
.
max
(
currentMaxTabStop
,
currentTabStop
,
nestedMaxTabStop
);
}
});
return
currentMaxTabStop
;
};
let
maxTabStop
=
getMaxTabStop
(
snippetMarkers
);
let
setNextTabStop
=
(
markers
:
Marker
[])
=>
{
markers
.
forEach
(
marker
=>
{
if
(
marker
instanceof
Placeholder
)
{
if
(
marker
[
'
index
'
]
===
'
0
'
)
{
marker
[
'
index
'
]
=
++
maxTabStop
+
''
;
}
setNextTabStop
(
marker
[
'
defaultValue
'
]
||
[]);
}
});
};
setNextTabStop
(
snippetMarkers
);
const
snippet
=
new
CodeSnippet
();
_fillCodeSnippetFromMarker
(
snippet
,
snippetMarkers
);
return
snippet
;
}
public
lines
:
string
[]
=
[];
public
placeHolders
:
IPlaceHolder
[]
=
[];
public
finishPlaceHolderIndex
:
number
=
-
1
;
get
isInsertOnly
():
boolean
{
return
this
.
placeHolders
.
length
===
0
;
}
get
isSingleTabstopOnly
():
boolean
{
if
(
this
.
placeHolders
.
length
!==
1
)
{
return
false
;
}
const
[
placeHolder
]
=
this
.
placeHolders
;
if
(
placeHolder
.
value
!==
''
||
placeHolder
.
occurences
.
length
!==
1
)
{
return
false
;
}
const
[
placeHolderRange
]
=
placeHolder
.
occurences
;
if
(
!
Range
.
isEmpty
(
placeHolderRange
))
{
return
false
;
}
return
true
;
}
private
extractLineIndentation
(
str
:
string
,
maxColumn
:
number
=
Number
.
MAX_VALUE
):
string
{
var
fullIndentation
=
strings
.
getLeadingWhitespace
(
str
);
if
(
fullIndentation
.
length
>
maxColumn
-
1
)
{
return
fullIndentation
.
substring
(
0
,
maxColumn
-
1
);
}
return
fullIndentation
;
}
public
bind
(
referenceLine
:
string
,
deltaLine
:
number
,
firstLineDeltaColumn
:
number
,
config
:
IIndentationNormalizer
):
ICodeSnippet
{
const
resultLines
:
string
[]
=
[];
const
resultPlaceHolders
:
IPlaceHolder
[]
=
[];
const
referenceIndentation
=
this
.
extractLineIndentation
(
referenceLine
,
firstLineDeltaColumn
+
1
);
// Compute resultLines & keep deltaColumns as a reference for adjusting placeholders
const
deltaColumns
:
number
[]
=
[];
for
(
let
i
=
0
,
len
=
this
.
lines
.
length
;
i
<
len
;
i
++
)
{
let
originalLine
=
this
.
lines
[
i
];
if
(
i
===
0
)
{
deltaColumns
[
i
+
1
]
=
firstLineDeltaColumn
;
resultLines
[
i
]
=
originalLine
;
}
else
{
let
originalLineIndentation
=
this
.
extractLineIndentation
(
originalLine
);
let
remainingLine
=
originalLine
.
substr
(
originalLineIndentation
.
length
);
let
indentation
=
config
.
normalizeIndentation
(
referenceIndentation
+
originalLineIndentation
);
deltaColumns
[
i
+
1
]
=
indentation
.
length
-
originalLineIndentation
.
length
;
resultLines
[
i
]
=
indentation
+
remainingLine
;
}
}
// Compute resultPlaceHolders
for
(
const
originalPlaceHolder
of
this
.
placeHolders
)
{
let
resultOccurences
:
Range
[]
=
[];
for
(
let
{
startLineNumber
,
startColumn
,
endLineNumber
,
endColumn
}
of
originalPlaceHolder
.
occurences
)
{
if
(
startColumn
>
1
||
startLineNumber
===
1
)
{
// placeholders that aren't at the beginning of new snippet lines
// will be moved by how many characters the indentation has been
// adjusted
startColumn
=
startColumn
+
deltaColumns
[
startLineNumber
];
endColumn
=
endColumn
+
deltaColumns
[
endLineNumber
];
}
else
{
// placeholders at the beginning of new snippet lines
// will be indented by the reference indentation
startColumn
+=
referenceIndentation
.
length
;
endColumn
+=
referenceIndentation
.
length
;
}
resultOccurences
.
push
(
new
Range
(
startLineNumber
+
deltaLine
,
startColumn
,
endLineNumber
+
deltaLine
,
endColumn
,
));
}
resultPlaceHolders
.
push
({
id
:
originalPlaceHolder
.
id
,
value
:
originalPlaceHolder
.
value
,
occurences
:
resultOccurences
});
}
return
{
lines
:
resultLines
,
placeHolders
:
resultPlaceHolders
,
finishPlaceHolderIndex
:
this
.
finishPlaceHolderIndex
};
}
}
// --- parsing
interface
ISnippetParser
{
parse
(
input
:
string
):
CodeSnippet
;
}
interface
IParsedLinePlaceHolderInfo
{
id
:
string
;
value
:
string
;
startColumn
:
number
;
endColumn
:
number
;
}
interface
IParsedLine
{
line
:
string
;
placeHolders
:
IParsedLinePlaceHolderInfo
[];
}
function
_resolveSnippetVariables
(
marker
:
Marker
[],
resolver
:
ISnippetVariableResolver
)
{
if
(
resolver
)
{
const
stack
=
[...
marker
];
while
(
stack
.
length
>
0
)
{
const
marker
=
stack
.
shift
();
if
(
marker
instanceof
Variable
)
{
try
{
marker
.
resolvedValue
=
resolver
.
resolve
(
marker
.
name
);
}
catch
(
e
)
{
//
}
if
(
marker
.
isDefined
)
{
continue
;
}
}
if
(
marker
instanceof
Variable
||
marker
instanceof
Placeholder
)
{
// 'recurse'
stack
.
unshift
(...
marker
.
defaultValue
);
}
}
}
}
function
_isFinishPlaceHolder
(
v
:
IPlaceHolder
)
{
return
(
v
.
id
===
''
&&
v
.
value
===
''
)
||
v
.
id
===
'
0
'
;
}
function
_fillCodeSnippetFromMarker
(
snippet
:
CodeSnippet
,
marker
:
Marker
[])
{
let
placeHolders
:
{
[
id
:
string
]:
IPlaceHolder
}
=
Object
.
create
(
null
);
let
hasFinishPlaceHolder
=
false
;
const
stack
=
[...
marker
];
snippet
.
lines
=
[
''
];
while
(
stack
.
length
>
0
)
{
const
marker
=
stack
.
shift
();
if
(
marker
instanceof
Text
)
{
// simple text
let
lines
=
marker
.
string
.
split
(
/
\r\n
|
\n
|
\r
/
);
snippet
.
lines
[
snippet
.
lines
.
length
-
1
]
+=
lines
.
shift
();
snippet
.
lines
.
push
(...
lines
);
}
else
if
(
marker
instanceof
Placeholder
)
{
let
placeHolder
=
placeHolders
[
marker
.
index
];
if
(
!
placeHolder
)
{
placeHolders
[
marker
.
index
]
=
placeHolder
=
{
id
:
marker
.
index
,
value
:
Marker
.
toString
(
marker
.
defaultValue
),
occurences
:
[]
};
snippet
.
placeHolders
.
push
(
placeHolder
);
}
hasFinishPlaceHolder
=
hasFinishPlaceHolder
||
_isFinishPlaceHolder
(
placeHolder
);
const
line
=
snippet
.
lines
.
length
;
const
column
=
snippet
.
lines
[
line
-
1
].
length
+
1
;
placeHolder
.
occurences
.
push
(
new
Range
(
line
,
column
,
line
,
column
+
Marker
.
toString
(
marker
.
defaultValue
).
length
// TODO multiline placeholders!
));
stack
.
unshift
(...
marker
.
defaultValue
);
}
else
if
(
marker
instanceof
Variable
)
{
if
(
!
marker
.
isDefined
)
{
// contine as placeholder
// THIS is because of us having falsy
// advertised ${foo} as placeholder syntax
stack
.
unshift
(
new
Placeholder
(
marker
.
name
,
marker
.
defaultValue
.
length
===
0
?
[
new
Text
(
marker
.
name
)]
:
marker
.
defaultValue
));
}
else
if
(
marker
.
resolvedValue
)
{
// contine with the value
stack
.
unshift
(
new
Text
(
marker
.
resolvedValue
));
}
else
{
// continue with default values
stack
.
unshift
(...
marker
.
defaultValue
);
}
}
if
(
stack
.
length
===
0
&&
!
hasFinishPlaceHolder
)
{
stack
.
push
(
new
Placeholder
(
'
0
'
,
[]));
}
}
// Named variables (e.g. {greeting} and {greeting:Hello}) are sorted first, followed by
// tab-stops and numeric variables (e.g. $1, $2, ${3:foo}) which are sorted in ascending order
snippet
.
placeHolders
.
sort
((
a
,
b
)
=>
{
let
nonIntegerId
=
(
v
:
IPlaceHolder
)
=>
!
(
/^
\d
+$/
).
test
(
v
.
id
);
// Sort finish placeholder last
if
(
_isFinishPlaceHolder
(
a
))
{
return
1
;
}
else
if
(
_isFinishPlaceHolder
(
b
))
{
return
-
1
;
}
// Sort named placeholders first
if
(
nonIntegerId
(
a
)
&&
nonIntegerId
(
b
))
{
return
0
;
}
else
if
(
nonIntegerId
(
a
))
{
return
-
1
;
}
else
if
(
nonIntegerId
(
b
))
{
return
1
;
}
if
(
a
.
id
===
b
.
id
)
{
return
0
;
}
return
Number
(
a
.
id
)
<
Number
(
b
.
id
)
?
-
1
:
1
;
});
if
(
snippet
.
placeHolders
.
length
>
0
)
{
snippet
.
finishPlaceHolderIndex
=
snippet
.
placeHolders
.
length
-
1
;
snippet
.
placeHolders
[
snippet
.
finishPlaceHolderIndex
].
id
=
''
;
}
}
src/vs/editor/contrib/snippet/common/snippetController.ts
已删除
100644 → 0
浏览文件 @
9532abde
此差异已折叠。
点击以展开。
src/vs/editor/contrib/snippet/common/snippetVariables.ts
浏览文件 @
bbe82060
...
...
@@ -5,11 +5,9 @@
'
use strict
'
;
import
{
basename
,
dirname
,
normalize
}
from
'
vs/base/common/paths
'
;
import
{
I
CommonCodeEditor
,
I
Model
}
from
'
vs/editor/common/editorCommon
'
;
import
{
basename
,
dirname
}
from
'
vs/base/common/paths
'
;
import
{
IModel
}
from
'
vs/editor/common/editorCommon
'
;
import
{
Selection
}
from
'
vs/editor/common/core/selection
'
;
import
{
ISnippetVariableResolver
}
from
'
./snippet
'
;
export
class
EditorSnippetVariableResolver
{
...
...
@@ -67,66 +65,3 @@ export class EditorSnippetVariableResolver {
}
}
}
export
class
SnippetVariablesResolver
implements
ISnippetVariableResolver
{
private
readonly
_editor
:
ICommonCodeEditor
;
constructor
(
editor
:
ICommonCodeEditor
)
{
this
.
_editor
=
editor
;
}
resolve
(
name
:
string
):
string
{
const
model
=
this
.
_editor
.
getModel
();
if
(
!
model
)
{
throw
new
Error
();
}
switch
(
name
)
{
case
'
SELECTION
'
:
case
'
TM_SELECTED_TEXT
'
:
return
this
.
_tmSelectedText
();
case
'
TM_CURRENT_LINE
'
:
return
this
.
_tmCurrentLine
();
case
'
TM_CURRENT_WORD
'
:
return
this
.
_tmCurrentWord
();
case
'
TM_LINE_INDEX
'
:
return
this
.
_tmLineIndex
();
case
'
TM_LINE_NUMBER
'
:
return
this
.
_tmLineNumber
();
case
'
TM_FILENAME
'
:
return
this
.
_tmFilename
();
case
'
TM_DIRECTORY
'
:
return
this
.
_tmDirectory
();
case
'
TM_FILEPATH
'
:
return
this
.
_tmFilepath
();
}
return
undefined
;
}
private
_tmCurrentLine
():
string
{
const
{
positionLineNumber
}
=
this
.
_editor
.
getSelection
();
return
this
.
_editor
.
getModel
().
getValueInRange
({
startLineNumber
:
positionLineNumber
,
startColumn
:
1
,
endLineNumber
:
positionLineNumber
,
endColumn
:
Number
.
MAX_VALUE
});
}
private
_tmCurrentWord
():
string
{
const
word
=
this
.
_editor
.
getModel
().
getWordAtPosition
(
this
.
_editor
.
getPosition
());
return
word
?
word
.
word
:
''
;
}
private
_tmFilename
():
string
{
return
basename
(
this
.
_editor
.
getModel
().
uri
.
fsPath
);
}
private
_tmDirectory
():
string
{
const
dir
=
dirname
(
normalize
(
this
.
_editor
.
getModel
().
uri
.
fsPath
));
return
dir
!==
'
.
'
?
dir
:
''
;
}
private
_tmFilepath
():
string
{
return
this
.
_editor
.
getModel
().
uri
.
fsPath
;
}
private
_tmLineIndex
():
string
{
return
String
(
this
.
_editor
.
getSelection
().
positionLineNumber
-
1
);
}
private
_tmLineNumber
():
string
{
return
String
(
this
.
_editor
.
getSelection
().
positionLineNumber
);
}
private
_tmSelectedText
():
string
{
return
this
.
_editor
.
getModel
().
getValueInRange
(
this
.
_editor
.
getSelection
());
}
}
src/vs/editor/contrib/snippet/test/common/snippet.test.ts
已删除
100644 → 0
浏览文件 @
9532abde
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
CodeSnippet
,
ICodeSnippet
,
ISnippetVariableResolver
}
from
'
vs/editor/contrib/snippet/common/snippet
'
;
suite
(
'
Editor Contrib - Snippets
'
,
()
=>
{
function
assertInternalAndTextmate
(
internal
:
string
,
textmate
:
string
,
callback
:
(
snippet
:
ICodeSnippet
)
=>
any
)
{
callback
(
CodeSnippet
.
fromInternal
(
internal
));
callback
(
CodeSnippet
.
fromTextmate
(
textmate
));
}
test
(
'
Support tab stop order
'
,
()
=>
{
assertInternalAndTextmate
(
'
finished:{{}}, second:{{2:name}}, first:{{1:}}, third:{{3:}}
'
,
'
finished:$0, second:${2:name}, first:$1, third:$3
'
,
snippet
=>
{
assert
.
deepEqual
(
snippet
.
lines
,
[
'
finished:, second:name, first:, third:
'
]);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
4
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
id
,
'
1
'
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
value
,
''
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
id
,
'
2
'
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
value
,
'
name
'
);
assert
.
equal
(
snippet
.
placeHolders
[
2
].
id
,
'
3
'
);
assert
.
equal
(
snippet
.
placeHolders
[
2
].
value
,
''
);
assert
.
equal
(
snippet
.
placeHolders
[
3
].
id
,
''
);
assert
.
equal
(
snippet
.
placeHolders
[
3
].
value
,
''
);
assert
.
equal
(
snippet
.
finishPlaceHolderIndex
,
3
);
});
});
test
(
'
Support tab stop order with implicit finish
'
,
()
=>
{
assertInternalAndTextmate
(
'
t2:{{2:}}, t1:{{1:}}
'
,
'
t2:$2, t1:$1
'
,
snippet
=>
{
assert
.
deepEqual
(
snippet
.
lines
,
[
'
t2:, t1:
'
]);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
3
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
id
,
'
1
'
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
value
,
''
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
id
,
'
2
'
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
value
,
''
);
assert
.
equal
(
snippet
.
finishPlaceHolderIndex
,
2
);
});
});
test
(
'
Support tab stop order with no finish
'
,
()
=>
{
assertInternalAndTextmate
(
'
t2:{{2:second}}, t3:{{3:last}}, t1:{{1:first}}
'
,
'
t2:${2:second}, t3:${3:last}, t1:${1:first}
'
,
snippet
=>
{
assert
.
deepEqual
(
snippet
.
lines
,
[
'
t2:second, t3:last, t1:first
'
]);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
4
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
id
,
'
1
'
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
value
,
'
first
'
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
id
,
'
2
'
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
value
,
'
second
'
);
assert
.
equal
(
snippet
.
placeHolders
[
2
].
id
,
'
3
'
);
assert
.
equal
(
snippet
.
placeHolders
[
2
].
value
,
'
last
'
);
assert
.
equal
(
snippet
.
finishPlaceHolderIndex
,
3
);
});
});
test
(
'
Support tab stop order which does not affect named variable id
\'
s
'
,
()
=>
{
assertInternalAndTextmate
(
'
{{first}}-{{2:}}-{{second}}-{{1:}}
'
,
'
${first}-${2}-${second}-${1}
'
,
snippet
=>
{
assert
.
deepEqual
(
snippet
.
lines
,
[
'
first--second-
'
]);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
5
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
id
,
'
first
'
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
id
,
'
second
'
);
assert
.
equal
(
snippet
.
placeHolders
[
2
].
id
,
'
1
'
);
assert
.
equal
(
snippet
.
placeHolders
[
3
].
id
,
'
2
'
);
}
);
});
test
(
'
nested placeholder
'
,
()
=>
{
let
snippet
=
CodeSnippet
.
fromTextmate
([
'
<div${1: id="${2:some_id}"}>
'
,
'
\t
$0
'
,
'
</div>
'
].
join
(
'
\n
'
));
assert
.
equal
(
snippet
.
placeHolders
.
length
,
3
);
assert
.
equal
(
snippet
.
finishPlaceHolderIndex
,
2
);
let
[
first
,
second
,
third
]
=
snippet
.
placeHolders
;
assert
.
equal
(
third
.
id
,
0
);
assert
.
equal
(
third
.
occurences
.
length
,
1
);
assert
.
deepEqual
(
third
.
occurences
[
0
],
new
Range
(
2
,
2
,
2
,
2
));
assert
.
equal
(
second
.
id
,
2
);
assert
.
equal
(
second
.
occurences
.
length
,
1
);
assert
.
deepEqual
(
second
.
occurences
[
0
],
new
Range
(
1
,
10
,
1
,
17
));
assert
.
equal
(
first
.
id
,
'
1
'
);
assert
.
equal
(
first
.
occurences
.
length
,
1
);
assert
.
deepEqual
(
first
.
occurences
[
0
],
new
Range
(
1
,
5
,
1
,
18
));
});
test
(
'
bug #17541:[snippets] Support default text in mirrors
'
,
()
=>
{
var
external
=
[
'
begin{${1:enumerate}}
'
,
'
\t
$0
'
,
'
end{$1}
'
].
join
(
'
\n
'
);
var
internal
=
[
'
begin
\\
{{{1:enumerate}}
\\
}
'
,
'
\t
{{}}
'
,
'
end
\\
{{{1:}}
\\
}
'
].
join
(
'
\n
'
);
assertInternalAndTextmate
(
internal
,
external
,
snippet
=>
{
assert
.
deepEqual
(
snippet
.
lines
,
[
'
begin{enumerate}
'
,
'
\t
'
,
'
end{enumerate}
'
]);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
2
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
id
,
'
1
'
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
.
length
,
2
);
assert
.
deepEqual
(
snippet
.
placeHolders
[
0
].
occurences
[
0
],
new
Range
(
1
,
7
,
1
,
16
));
assert
.
deepEqual
(
snippet
.
placeHolders
[
0
].
occurences
[
1
],
new
Range
(
3
,
5
,
3
,
14
));
assert
.
equal
(
snippet
.
placeHolders
[
1
].
id
,
''
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
occurences
.
length
,
1
);
assert
.
deepEqual
(
snippet
.
placeHolders
[
1
].
occurences
[
0
],
new
Range
(
2
,
2
,
2
,
2
));
});
});
test
(
'
bug #7093: Snippet default value is only populated for first variable reference
'
,
()
=>
{
var
internal
=
'
logger.error({ logContext: lc, errorContext: `{{1:err}}`, error: {{1:}} });
'
;
var
external
=
'
logger.error({ logContext: lc, errorContext: `${1:err}`, error: $1 });
'
;
assertInternalAndTextmate
(
internal
,
external
,
snippet
=>
{
assert
.
equal
(
snippet
.
lines
.
length
,
1
);
assert
.
equal
(
snippet
.
lines
[
0
],
'
logger.error({ logContext: lc, errorContext: `err`, error: err });
'
);
});
});
test
(
'
bug #17487:[snippets] four backslashes are required to get one backslash in the inserted text
'
,
()
=>
{
var
external
=
[
'
\\
begin{${1:enumerate}}
'
,
'
\t
$0
'
,
'
\\
end{$1}
'
].
join
(
'
\n
'
);
var
internal
=
[
'
\\
begin
\\
{{{1:enumerate}}
\\
}
'
,
'
\t
{{}}
'
,
'
\\
end
\\
{{{1:}}
\\
}
'
].
join
(
'
\n
'
);
assertInternalAndTextmate
(
internal
,
external
,
snippet
=>
{
assert
.
deepEqual
(
snippet
.
lines
,
[
'
\\
begin{enumerate}
'
,
'
\t
'
,
'
\\
end{enumerate}
'
]);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
2
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
id
,
'
1
'
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
.
length
,
2
);
assert
.
deepEqual
(
snippet
.
placeHolders
[
0
].
occurences
[
0
],
new
Range
(
1
,
8
,
1
,
17
));
assert
.
deepEqual
(
snippet
.
placeHolders
[
0
].
occurences
[
1
],
new
Range
(
3
,
6
,
3
,
15
));
assert
.
equal
(
snippet
.
placeHolders
[
1
].
id
,
''
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
occurences
.
length
,
1
);
assert
.
deepEqual
(
snippet
.
placeHolders
[
1
].
occurences
[
0
],
new
Range
(
2
,
2
,
2
,
2
));
});
});
test
(
'
issue #3552: Snippet Converted Not Working for literal Dollar Sign
'
,
()
=>
{
let
external
=
'
\n\\
$scope.
\\
$broadcast(
\'
scroll.infiniteScrollComplete
\'
);
\n
'
;
let
snippet
=
CodeSnippet
.
fromTextmate
(
external
);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
1
);
assert
.
equal
(
snippet
.
finishPlaceHolderIndex
,
0
);
assert
.
deepEqual
(
snippet
.
lines
,
[
''
,
'
$scope.$broadcast(
\'
scroll.infiniteScrollComplete
\'
);
'
,
''
]);
});
test
(
'
bind, adjust indentation
'
,
()
=>
{
// don't move placeholder at the beginning of the line
let
snippet
=
CodeSnippet
.
fromTextmate
([
'
afterEach((done) => {
'
,
'
\t
${1}test${2}
'
,
'
})
'
].
join
(
'
\n
'
));
// replace tab-stop with two spaces
let
boundSnippet
=
snippet
.
bind
(
''
,
0
,
0
,
{
normalizeIndentation
(
str
:
string
):
string
{
return
str
.
replace
(
/
\t
/g
,
'
'
);
}
});
let
[
first
,
second
]
=
boundSnippet
.
placeHolders
;
assert
.
equal
(
first
.
occurences
.
length
,
1
);
assert
.
equal
(
first
.
occurences
[
0
].
startColumn
,
3
);
assert
.
equal
(
second
.
occurences
.
length
,
1
);
assert
.
equal
(
second
.
occurences
[
0
].
startColumn
,
7
);
// keep tab-stop, identity
boundSnippet
=
snippet
.
bind
(
''
,
0
,
0
,
{
normalizeIndentation
(
str
:
string
):
string
{
return
str
;
}
});
[
first
,
second
]
=
boundSnippet
.
placeHolders
;
assert
.
equal
(
first
.
occurences
.
length
,
1
);
assert
.
equal
(
first
.
occurences
[
0
].
startColumn
,
2
);
assert
.
equal
(
second
.
occurences
.
length
,
1
);
assert
.
equal
(
second
.
occurences
[
0
].
startColumn
,
6
);
});
test
(
'
issue #11890: Bad cursor position 1/2
'
,
()
=>
{
let
snippet
=
CodeSnippet
.
fromTextmate
([
'
afterEach((done) => {
'
,
'
${1}
\t
test${2}
'
,
'
})
'
].
join
(
'
\n
'
));
let
boundSnippet
=
snippet
.
bind
(
''
,
0
,
0
,
{
normalizeIndentation
(
str
:
string
):
string
{
return
str
.
replace
(
/
\t
/g
,
'
'
);
}
});
assert
.
equal
(
boundSnippet
.
lines
[
1
],
'
test
'
);
assert
.
equal
(
boundSnippet
.
placeHolders
.
length
,
3
);
assert
.
equal
(
boundSnippet
.
finishPlaceHolderIndex
,
2
);
let
[
first
,
second
]
=
boundSnippet
.
placeHolders
;
assert
.
equal
(
first
.
occurences
.
length
,
1
);
assert
.
equal
(
first
.
occurences
[
0
].
startColumn
,
1
);
assert
.
equal
(
second
.
occurences
.
length
,
1
);
assert
.
equal
(
second
.
occurences
[
0
].
startColumn
,
7
);
});
test
(
'
issue #11890: Bad cursor position 2/2
'
,
()
=>
{
let
snippet
=
CodeSnippet
.
fromTextmate
(
'
${1}
\t
test
'
);
let
boundSnippet
=
snippet
.
bind
(
'
abc abc abc prefix3
'
,
0
,
12
,
{
normalizeIndentation
(
str
:
string
):
string
{
return
str
.
replace
(
/
\t
/g
,
'
'
);
}
});
assert
.
equal
(
boundSnippet
.
lines
[
0
],
'
\t
test
'
);
assert
.
equal
(
boundSnippet
.
placeHolders
.
length
,
2
);
assert
.
equal
(
boundSnippet
.
finishPlaceHolderIndex
,
1
);
let
[
first
,
second
]
=
boundSnippet
.
placeHolders
;
assert
.
equal
(
first
.
occurences
.
length
,
1
);
assert
.
equal
(
first
.
occurences
[
0
].
startColumn
,
13
);
assert
.
equal
(
second
.
occurences
.
length
,
1
);
assert
.
equal
(
second
.
occurences
[
0
].
startColumn
,
18
);
});
test
(
'
issue #17989: Bad selection
'
,
()
=>
{
let
snippet
=
CodeSnippet
.
fromTextmate
(
'
${1:HoldMeTight}
'
);
let
boundSnippet
=
snippet
.
bind
(
'
abc abc abc prefix3
'
,
0
,
12
,
{
normalizeIndentation
(
str
:
string
):
string
{
return
str
.
replace
(
/
\t
/g
,
'
'
);
}
});
assert
.
equal
(
boundSnippet
.
lines
[
0
],
'
HoldMeTight
'
);
assert
.
equal
(
boundSnippet
.
placeHolders
.
length
,
2
);
assert
.
equal
(
boundSnippet
.
finishPlaceHolderIndex
,
1
);
let
[
first
,
second
]
=
boundSnippet
.
placeHolders
;
assert
.
equal
(
first
.
occurences
.
length
,
1
);
assert
.
equal
(
first
.
occurences
[
0
].
startColumn
,
13
);
assert
.
equal
(
second
.
occurences
.
length
,
1
);
assert
.
equal
(
second
.
occurences
[
0
].
startColumn
,
24
);
});
test
(
'
variables, simple
'
,
()
=>
{
const
resolver
:
ISnippetVariableResolver
=
{
resolve
(
name
)
{
return
name
.
split
(
''
).
reverse
().
join
(
''
);
}
};
// simple
let
snippet
=
CodeSnippet
.
fromTextmate
(
'
$FOO
'
,
resolver
);
assert
.
equal
(
snippet
.
lines
[
0
],
'
OOF
'
);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
1
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
[
0
].
endColumn
,
4
);
snippet
=
CodeSnippet
.
fromTextmate
(
'
${FOO:BAR}
'
,
resolver
);
assert
.
equal
(
snippet
.
lines
[
0
],
'
OOF
'
);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
1
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
[
0
].
endColumn
,
4
);
// placeholder
snippet
=
CodeSnippet
.
fromTextmate
(
'
${1:$FOO}bar$1
'
,
resolver
);
assert
.
equal
(
snippet
.
lines
[
0
],
'
OOFbarOOF
'
);
assert
.
equal
(
snippet
.
placeHolders
.
length
,
2
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
.
length
,
2
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
[
0
].
startColumn
,
1
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
[
0
].
endColumn
,
4
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
[
1
].
startColumn
,
7
);
assert
.
equal
(
snippet
.
placeHolders
[
0
].
occurences
[
1
].
endColumn
,
10
);
assert
.
equal
(
snippet
.
placeHolders
[
1
].
occurences
.
length
,
1
);
snippet
=
CodeSnippet
.
fromTextmate
(
'
${1:${FOO:abc}}bar$1
'
,
resolver
);
assert
.
equal
(
snippet
.
lines
[
0
],
'
OOFbarOOF
'
);
});
test
(
'
variables, evil resolver
'
,
()
=>
{
let
snippet
=
CodeSnippet
.
fromTextmate
(
'
$FOO
'
,
{
resolve
():
string
{
throw
new
Error
();
}
});
assert
.
equal
(
snippet
.
lines
[
0
],
'
FOO
'
);
});
test
(
'
variables, default
'
,
()
=>
{
let
snippet
=
CodeSnippet
.
fromTextmate
(
'
$FOO
'
,
{
resolve
():
string
{
return
undefined
;
}
});
assert
.
equal
(
snippet
.
lines
[
0
],
'
FOO
'
);
snippet
=
CodeSnippet
.
fromTextmate
(
'
$FOO
'
,
{
resolve
():
string
{
return
''
;
}
});
assert
.
equal
(
snippet
.
lines
[
0
],
''
);
snippet
=
CodeSnippet
.
fromTextmate
(
'
${FOO:BAR}
'
,
{
resolve
():
string
{
return
undefined
;
}
});
assert
.
equal
(
snippet
.
lines
[
0
],
'
BAR
'
);
snippet
=
CodeSnippet
.
fromTextmate
(
'
${FOO:BAR}
'
,
{
resolve
():
string
{
return
''
;
}
});
assert
.
equal
(
snippet
.
lines
[
0
],
'
BAR
'
);
});
});
src/vs/editor/contrib/snippet/test/common/snippetController.test.ts
已删除
100644 → 0
浏览文件 @
9532abde
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
assert
from
'
assert
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
Selection
}
from
'
vs/editor/common/core/selection
'
;
import
{
CodeSnippet
}
from
'
vs/editor/contrib/snippet/common/snippet
'
;
import
{
SnippetController
}
from
'
vs/editor/contrib/snippet/common/snippetController
'
;
import
{
MockCodeEditor
,
withMockCodeEditor
}
from
'
vs/editor/test/common/mocks/mockCodeEditor
'
;
import
{
Cursor
}
from
'
vs/editor/common/controller/cursor
'
;
class
TestSnippetController
extends
SnippetController
{
isInSnippetMode
():
boolean
{
return
!!
this
.
_currentController
;
}
}
suite
(
'
SnippetController
'
,
()
=>
{
function
snippetTest
(
cb
:
(
editor
:
MockCodeEditor
,
cursor
:
Cursor
,
codeSnippet
:
CodeSnippet
,
snippetController
:
TestSnippetController
)
=>
void
,
lines
?:
string
[]):
void
{
if
(
!
lines
)
{
lines
=
[
'
function test() {
'
,
'
\t
var x = 3;
'
,
'
\t
var arr = [];
'
,
'
\t
'
,
'
}
'
];
};
withMockCodeEditor
(
lines
,
{},
(
editor
,
cursor
)
=>
{
editor
.
getModel
().
updateOptions
({
insertSpaces
:
false
});
let
snippetController
=
editor
.
registerAndInstantiateContribution
<
TestSnippetController
>
(
TestSnippetController
);
let
codeSnippet
=
CodeSnippet
.
fromInternal
([
'
for (var {{index}}; {{index}} < {{array}}.length; {{index}}++) {
'
,
'
\t
var element = {{array}}[{{index}}];
'
,
'
\t
{{}}
'
,
'
}
'
].
join
(
'
\n
'
));
cb
(
editor
,
cursor
,
codeSnippet
,
snippetController
);
snippetController
.
dispose
();
});
}
test
(
'
Simple accepted
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
4
),
'
\t
for (var index; index < array.length; index++) {
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
5
),
'
\t\t
var element = array[index];
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
6
),
'
\t\t
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
7
),
'
\t
}
'
);
editor
.
trigger
(
'
test
'
,
'
type
'
,
{
text
:
'
i
'
});
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
4
),
'
\t
for (var i; i < array.length; i++) {
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
5
),
'
\t\t
var element = array[i];
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
6
),
'
\t\t
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
7
),
'
\t
}
'
);
snippetController
.
jumpToNextPlaceholder
();
editor
.
trigger
(
'
test
'
,
'
type
'
,
{
text
:
'
arr
'
});
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
4
),
'
\t
for (var i; i < arr.length; i++) {
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
5
),
'
\t\t
var element = arr[i];
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
6
),
'
\t\t
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
7
),
'
\t
}
'
);
snippetController
.
jumpToPrevPlaceholder
();
editor
.
trigger
(
'
test
'
,
'
type
'
,
{
text
:
'
j
'
});
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
4
),
'
\t
for (var j; j < arr.length; j++) {
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
5
),
'
\t\t
var element = arr[j];
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
6
),
'
\t\t
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
7
),
'
\t
}
'
);
snippetController
.
acceptSnippet
();
assert
.
deepEqual
(
editor
.
getPosition
(),
new
Position
(
6
,
3
));
});
});
test
(
'
Simple canceled
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
4
),
'
\t
for (var index; index < array.length; index++) {
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
5
),
'
\t\t
var element = array[index];
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
6
),
'
\t\t
'
);
assert
.
equal
(
editor
.
getModel
().
getLineContent
(
7
),
'
\t
}
'
);
snippetController
.
leaveSnippet
();
assert
.
deepEqual
(
editor
.
getPosition
(),
new
Position
(
4
,
16
));
});
});
test
(
'
Stops when deleting lines above
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
getModel
().
applyEdits
([{
forceMoveMarkers
:
false
,
identifier
:
null
,
isAutoWhitespaceEdit
:
false
,
range
:
new
Range
(
1
,
1
,
3
,
1
),
text
:
null
}]);
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when deleting lines below
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
getModel
().
applyEdits
([{
forceMoveMarkers
:
false
,
identifier
:
null
,
isAutoWhitespaceEdit
:
false
,
range
:
new
Range
(
8
,
1
,
8
,
100
),
text
:
null
}]);
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when inserting lines above
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
getModel
().
applyEdits
([{
forceMoveMarkers
:
false
,
identifier
:
null
,
isAutoWhitespaceEdit
:
false
,
range
:
new
Range
(
1
,
100
,
1
,
100
),
text
:
'
\n
Hello
'
}]);
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when inserting lines below
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
getModel
().
applyEdits
([{
forceMoveMarkers
:
false
,
identifier
:
null
,
isAutoWhitespaceEdit
:
false
,
range
:
new
Range
(
8
,
100
,
8
,
100
),
text
:
'
\n
Hello
'
}]);
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when calling model.setValue()
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
getModel
().
setValue
(
'
goodbye
'
);
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when undoing
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
getModel
().
undo
();
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when moving cursor outside
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
setPosition
({
lineNumber
:
1
,
column
:
1
});
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when disconnecting editor model
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
editor
.
setModel
(
null
);
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Stops when disposing editor
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setPosition
({
lineNumber
:
4
,
column
:
2
});
snippetController
.
run
(
codeSnippet
,
0
,
0
);
snippetController
.
dispose
();
assert
.
equal
(
snippetController
.
isInSnippetMode
(),
false
);
});
});
test
(
'
Final tabstop with multiple selections
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
),
new
Selection
(
2
,
1
,
2
,
1
),
]);
codeSnippet
=
CodeSnippet
.
fromInternal
(
'
foo{{}}
'
);
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
2
);
const
[
first
,
second
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
1
,
startColumn
:
4
,
endLineNumber
:
1
,
endColumn
:
4
}),
first
.
toString
());
assert
.
ok
(
second
.
equalsRange
({
startLineNumber
:
2
,
startColumn
:
4
,
endLineNumber
:
2
,
endColumn
:
4
}),
second
.
toString
());
});
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
),
new
Selection
(
2
,
1
,
2
,
1
),
]);
codeSnippet
=
CodeSnippet
.
fromInternal
(
'
foo{{}}bar
'
);
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
2
);
const
[
first
,
second
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
1
,
startColumn
:
4
,
endLineNumber
:
1
,
endColumn
:
4
}),
first
.
toString
());
assert
.
ok
(
second
.
equalsRange
({
startLineNumber
:
2
,
startColumn
:
4
,
endLineNumber
:
2
,
endColumn
:
4
}),
second
.
toString
());
});
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
),
new
Selection
(
1
,
5
,
1
,
5
),
]);
codeSnippet
=
CodeSnippet
.
fromInternal
(
'
foo{{}}bar
'
);
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
2
);
const
[
first
,
second
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
1
,
startColumn
:
4
,
endLineNumber
:
1
,
endColumn
:
4
}),
first
.
toString
());
assert
.
ok
(
second
.
equalsRange
({
startLineNumber
:
1
,
startColumn
:
14
,
endLineNumber
:
1
,
endColumn
:
14
}),
second
.
toString
());
});
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
),
new
Selection
(
1
,
5
,
1
,
5
),
]);
codeSnippet
=
CodeSnippet
.
fromInternal
(
'
foo
\n
{{}}
\n
bar
'
);
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
2
);
const
[
first
,
second
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
2
,
startColumn
:
1
,
endLineNumber
:
2
,
endColumn
:
1
}),
first
.
toString
());
assert
.
ok
(
second
.
equalsRange
({
startLineNumber
:
4
,
startColumn
:
1
,
endLineNumber
:
4
,
endColumn
:
1
}),
second
.
toString
());
});
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
),
new
Selection
(
1
,
5
,
1
,
5
),
]);
codeSnippet
=
CodeSnippet
.
fromInternal
(
'
foo
\n
{{}}
\n
bar
'
);
snippetController
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
2
);
const
[
first
,
second
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
2
,
startColumn
:
1
,
endLineNumber
:
2
,
endColumn
:
1
}),
first
.
toString
());
assert
.
ok
(
second
.
equalsRange
({
startLineNumber
:
4
,
startColumn
:
1
,
endLineNumber
:
4
,
endColumn
:
1
}),
second
.
toString
());
});
snippetTest
((
editor
,
cursor
,
codeSnippet
,
snippetController
)
=>
{
editor
.
setSelections
([
new
Selection
(
2
,
7
,
2
,
7
),
]);
codeSnippet
=
CodeSnippet
.
fromInternal
(
'
xo{{}}r
'
);
snippetController
.
run
(
codeSnippet
,
1
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
1
);
assert
.
ok
(
editor
.
getSelection
().
equalsRange
({
startLineNumber
:
2
,
startColumn
:
8
,
endColumn
:
8
,
endLineNumber
:
2
}));
});
});
test
(
'
Final tabstop, #11742 simple
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelection
(
new
Selection
(
1
,
19
,
1
,
19
));
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
{{% url_**$1** %}}
'
);
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
1
);
assert
.
ok
(
editor
.
getSelection
().
equalsRange
({
startLineNumber
:
1
,
startColumn
:
27
,
endLineNumber
:
1
,
endColumn
:
27
}));
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
example example {{% url_**** %}}
'
);
},
[
'
example example sc
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelection
(
new
Selection
(
1
,
3
,
1
,
3
));
codeSnippet
=
CodeSnippet
.
fromTextmate
([
'
afterEach((done) => {
'
,
'
\t
${1}test
'
,
'
});
'
].
join
(
'
\n
'
));
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
1
);
assert
.
ok
(
editor
.
getSelection
().
equalsRange
({
startLineNumber
:
2
,
startColumn
:
2
,
endLineNumber
:
2
,
endColumn
:
2
}),
editor
.
getSelection
().
toString
());
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
afterEach((done) => {
\n\t
test
\n
});
'
);
},
[
'
af
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelection
(
new
Selection
(
1
,
3
,
1
,
3
));
codeSnippet
=
CodeSnippet
.
fromTextmate
([
'
afterEach((done) => {
'
,
'
${1}
\t
test
'
,
'
});
'
].
join
(
'
\n
'
));
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
1
);
assert
.
ok
(
editor
.
getSelection
().
equalsRange
({
startLineNumber
:
2
,
startColumn
:
1
,
endLineNumber
:
2
,
endColumn
:
1
}),
editor
.
getSelection
().
toString
());
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
afterEach((done) => {
\n\t
test
\n
});
'
);
},
[
'
af
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelection
(
new
Selection
(
1
,
9
,
1
,
9
));
codeSnippet
=
CodeSnippet
.
fromTextmate
([
'
aft${1}er
'
].
join
(
'
\n
'
));
controller
.
run
(
codeSnippet
,
8
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
after
'
);
assert
.
equal
(
editor
.
getSelections
().
length
,
1
);
assert
.
ok
(
editor
.
getSelection
().
equalsRange
({
startLineNumber
:
1
,
startColumn
:
4
,
endLineNumber
:
1
,
endColumn
:
4
}),
editor
.
getSelection
().
toString
());
},
[
'
afterone
'
]);
});
test
(
'
Final tabstop, #11742 different indents
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
2
,
4
,
2
,
4
),
new
Selection
(
1
,
3
,
1
,
3
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
([
'
afterEach((done) => {
'
,
'
\t
${0}test
'
,
'
});
'
].
join
(
'
\n
'
));
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
2
);
const
[
first
,
second
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
5
,
startColumn
:
3
,
endLineNumber
:
5
,
endColumn
:
3
}),
first
.
toString
());
assert
.
ok
(
second
.
equalsRange
({
startLineNumber
:
2
,
startColumn
:
2
,
endLineNumber
:
2
,
endColumn
:
2
}),
second
.
toString
());
},
[
'
af
'
,
'
\t
af
'
]);
});
test
(
'
Final tabstop, #11890 stay at the beginning
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
5
,
1
,
5
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
([
'
afterEach((done) => {
'
,
'
${1}
\t
test
'
,
'
});
'
].
join
(
'
\n
'
));
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
equal
(
editor
.
getSelections
().
length
,
1
);
const
[
first
]
=
editor
.
getSelections
();
assert
.
ok
(
first
.
equalsRange
({
startLineNumber
:
2
,
startColumn
:
3
,
endLineNumber
:
2
,
endColumn
:
3
}),
first
.
toString
());
},
[
'
af
'
]);
});
test
(
'
Final tabstop, no tabstop
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
3
,
1
,
3
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
afterEach
'
);
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
ok
(
editor
.
getSelection
().
equalsRange
({
startLineNumber
:
1
,
startColumn
:
10
,
endLineNumber
:
1
,
endColumn
:
10
}));
},
[
'
af
'
,
'
\t
af
'
]);
});
test
(
'
Multiple cursor and overwriteBefore/After, issue #11060
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
7
,
1
,
7
),
new
Selection
(
2
,
4
,
2
,
4
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
_foo
'
);
controller
.
run
(
codeSnippet
,
1
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
this._foo
\n
abc_foo
'
);
},
[
'
this._
'
,
'
abc
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
7
,
1
,
7
),
new
Selection
(
2
,
4
,
2
,
4
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
XX
'
);
controller
.
run
(
codeSnippet
,
1
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
this.XX
\n
abcXX
'
);
},
[
'
this._
'
,
'
abc
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
7
,
1
,
7
),
new
Selection
(
2
,
4
,
2
,
4
),
new
Selection
(
3
,
5
,
3
,
5
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
_foo
'
);
controller
.
run
(
codeSnippet
,
1
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
this._foo
\n
abc_foo
\n
def_foo
'
);
},
[
'
this._
'
,
'
abc
'
,
'
def_
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
7
,
1
,
7
),
new
Selection
(
2
,
4
,
2
,
4
),
new
Selection
(
3
,
6
,
3
,
6
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
._foo
'
);
controller
.
run
(
codeSnippet
,
2
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
this._foo
\n
abc._foo
\n
def._foo
'
);
},
[
'
this._
'
,
'
abc
'
,
'
def._
'
]);
});
test
(
'
Multiple cursor and overwriteBefore/After, #16277
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
5
,
1
,
5
),
new
Selection
(
2
,
5
,
2
,
5
),
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
document
'
);
controller
.
run
(
codeSnippet
,
3
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
{document}
\n
{document && true}
'
);
},
[
'
{foo}
'
,
'
{foo && true}
'
]);
});
test
(
'
Insert snippet twice, #19449
'
,
()
=>
{
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
for (var ${1:i}=0; ${1:i}<len; ${1:i}++) { $0 }
'
);
controller
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
for (var i=0; i<len; i++) { }for (var i=0; i<len; i++) { }
'
);
},
[
'
for (var i=0; i<len; i++) { }
'
]);
snippetTest
((
editor
,
cursor
,
codeSnippet
,
controller
)
=>
{
editor
.
setSelections
([
new
Selection
(
1
,
1
,
1
,
1
)
]);
codeSnippet
=
CodeSnippet
.
fromTextmate
(
'
for (let ${1:i}=0; ${1:i}<len; ${1:i}++) { $0 }
'
);
controller
.
run
(
codeSnippet
,
0
,
0
);
assert
.
equal
(
editor
.
getModel
().
getValue
(),
'
for (let i=0; i<len; i++) { }for (var i=0; i<len; i++) { }
'
);
},
[
'
for (var i=0; i<len; i++) { }
'
]);
});
});
src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts
浏览文件 @
bbe82060
...
...
@@ -7,12 +7,12 @@
import
{
ICommonCodeEditor
}
from
'
vs/editor/common/editorCommon
'
;
import
strings
=
require
(
'
vs/base/common/strings
'
);
import
snippets
=
require
(
'
vs/editor/contrib/snippet/common/snippet
'
);
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
SnippetController2
}
from
'
vs/editor/contrib/snippet/browser/snippetController2
'
;
import
{
LanguageId
,
LanguageIdentifier
}
from
'
vs/editor/common/modes
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
CoreEditingCommands
}
from
"
vs/editor/common/controller/coreCommands
"
;
import
{
SnippetParser
,
walk
,
Placeholder
,
Variable
,
Text
,
Marker
}
from
'
vs/editor/contrib/snippet/common/snippetParser
'
;
import
emmet
=
require
(
'
emmet
'
);
...
...
@@ -94,7 +94,7 @@ export class EditorAccessor implements emmet.Editor {
return
;
}
const
tweakedValue
=
snippets
.
CodeSnippet
.
fixEmmetFinalTabstop
(
value
);
const
tweakedValue
=
EditorAccessor
.
fixEmmetFinalTabstop
(
value
);
// let selection define the typing range
this
.
_editor
.
setSelection
(
range
);
...
...
@@ -104,6 +104,64 @@ export class EditorAccessor implements emmet.Editor {
// SnippetController.get(this._editor).runWithReplaceRange(codeSnippet, range);
}
private
static
fixEmmetFinalTabstop
(
template
:
string
):
string
{
let
matchFinalStops
=
template
.
match
(
/
\$\{
0
\}
|
\$
0/g
);
if
(
!
matchFinalStops
||
matchFinalStops
.
length
===
1
)
{
return
template
;
}
// string to string conversion that tries to fix the
// snippet in-place
let
marker
=
new
SnippetParser
(
true
,
false
).
parse
(
template
);
let
maxIndex
=
-
Number
.
MIN_VALUE
;
// find highest placeholder index
walk
(
marker
,
candidate
=>
{
if
(
candidate
instanceof
Placeholder
)
{
let
index
=
Number
(
candidate
.
index
);
if
(
index
>
maxIndex
)
{
maxIndex
=
index
;
}
}
return
true
;
});
// rewrite final tabstops
walk
(
marker
,
candidate
=>
{
if
(
candidate
instanceof
Placeholder
)
{
if
(
candidate
.
isFinalTabstop
)
{
candidate
.
index
=
String
(
++
maxIndex
);
}
}
return
true
;
});
// write back as string
function
toSnippetString
(
marker
:
Marker
):
string
{
if
(
marker
instanceof
Text
)
{
return
SnippetParser
.
escape
(
marker
.
string
);
}
else
if
(
marker
instanceof
Placeholder
)
{
if
(
marker
.
defaultValue
.
length
>
0
)
{
return
`
\$
{
${
marker
.
index
}
:
${
marker
.
defaultValue
.
map
(
toSnippetString
).
join
(
''
)}
}`
;
}
else
{
return
`
\$
${
marker
.
index
}
`
;
}
}
else
if
(
marker
instanceof
Variable
)
{
if
(
marker
.
defaultValue
.
length
>
0
)
{
return
`
\$
{
${
marker
.
name
}
:
${
marker
.
defaultValue
.
map
(
toSnippetString
).
join
(
''
)}
}`
;
}
else
{
return
`
\$
${
marker
.
name
}
`
;
}
}
else
{
throw
new
Error
(
'
unexpected marker:
'
+
marker
);
}
}
return
marker
.
map
(
toSnippetString
).
join
(
''
);
}
public
getRangeToReplace
(
value
:
string
,
start
:
number
,
end
:
number
):
Range
{
//console.log('value', value);
let
startPosition
=
this
.
getPositionFromOffset
(
start
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录