Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
e6570733
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,发现更多精彩内容 >>
提交
e6570733
编写于
11月 08, 2016
作者:
J
Johannes Rieken
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
snippet parser work
上级
a710e6b3
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
380 addition
and
0 deletion
+380
-0
src/vs/editor/contrib/snippet/common/snippetParser.ts
src/vs/editor/contrib/snippet/common/snippetParser.ts
+278
-0
src/vs/editor/contrib/snippet/test/common/snippetParser.test.ts
.../editor/contrib/snippet/test/common/snippetParser.test.ts
+102
-0
未找到文件。
src/vs/editor/contrib/snippet/common/snippetParser.ts
0 → 100644
浏览文件 @
e6570733
/*---------------------------------------------------------------------------------------------
* 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
{
ICodeSnippet
}
from
'
./snippet
'
;
import
{
CharCode
}
from
'
vs/base/common/charCode
'
;
export
enum
TokenType
{
Dollar
,
Colon
,
CurlyOpen
,
CurlyClose
,
DoubleCurlyOpen
,
DoubleCurlyClose
,
Backslash
,
Int
,
VariableName
,
Format
,
EOF
}
export
interface
Token
{
type
:
TokenType
;
pos
:
number
;
len
:
number
;
}
export
class
Scanner
{
private
static
_table
:
{
[
ch
:
number
]:
TokenType
}
=
{
[
CharCode
.
DollarSign
]:
TokenType
.
Dollar
,
[
CharCode
.
Colon
]:
TokenType
.
Colon
,
[
CharCode
.
OpenCurlyBrace
]:
TokenType
.
CurlyOpen
,
[
CharCode
.
CloseCurlyBrace
]:
TokenType
.
CurlyClose
,
[
CharCode
.
Backslash
]:
TokenType
.
Backslash
,
};
static
isDigitCharacter
(
ch
:
number
):
boolean
{
return
ch
>=
CharCode
.
Digit0
&&
ch
<=
CharCode
.
Digit9
;
}
static
isVariableCharacter
(
ch
:
number
):
boolean
{
return
ch
===
CharCode
.
Underline
||
(
ch
>=
CharCode
.
a
&&
ch
<=
CharCode
.
z
)
||
(
ch
>=
CharCode
.
A
&&
ch
<=
CharCode
.
Z
);
}
value
:
string
;
pos
:
number
;
constructor
()
{
this
.
text
(
''
);
}
text
(
value
:
string
)
{
this
.
value
=
value
;
this
.
pos
=
0
;
}
tokenText
(
token
:
Token
):
string
{
return
this
.
value
.
substr
(
token
.
pos
,
token
.
len
);
}
next
():
Token
{
if
(
this
.
pos
>=
this
.
value
.
length
)
{
return
{
type
:
TokenType
.
EOF
,
pos
:
this
.
pos
,
len
:
0
};
}
let
pos
=
this
.
pos
;
let
len
=
0
;
let
ch
=
this
.
value
.
charCodeAt
(
pos
);
let
type
:
TokenType
;
// static types
type
=
Scanner
.
_table
[
ch
];
if
(
typeof
type
===
'
number
'
)
{
if
(
type
===
TokenType
.
CurlyOpen
&&
this
.
value
.
charCodeAt
(
pos
+
1
)
===
CharCode
.
OpenCurlyBrace
)
{
this
.
pos
+=
2
;
return
{
type
:
TokenType
.
DoubleCurlyOpen
,
pos
,
len
:
2
};
}
else
if
(
type
===
TokenType
.
CurlyClose
&&
this
.
value
.
charCodeAt
(
pos
+
1
)
===
CharCode
.
CloseCurlyBrace
)
{
this
.
pos
+=
2
;
return
{
type
:
TokenType
.
DoubleCurlyClose
,
pos
,
len
:
2
};
}
else
{
this
.
pos
+=
1
;
return
{
type
,
pos
,
len
:
1
};
}
}
// number
if
(
Scanner
.
isDigitCharacter
(
ch
))
{
type
=
TokenType
.
Int
;
do
{
len
+=
1
;
ch
=
this
.
value
.
charCodeAt
(
pos
+
len
);
}
while
(
Scanner
.
isDigitCharacter
(
ch
));
this
.
pos
+=
len
;
return
{
type
,
pos
,
len
};
}
// variable name
if
(
Scanner
.
isVariableCharacter
(
ch
))
{
type
=
TokenType
.
VariableName
;
do
{
ch
=
this
.
value
.
charCodeAt
(
pos
+
(
++
len
));
}
while
(
Scanner
.
isVariableCharacter
(
ch
)
||
Scanner
.
isDigitCharacter
(
ch
));
this
.
pos
+=
len
;
return
{
type
,
pos
,
len
};
}
// format
type
=
TokenType
.
Format
;
do
{
len
+=
1
;
ch
=
this
.
value
.
charCodeAt
(
pos
+
len
);
}
while
(
!
isNaN
(
ch
)
&&
typeof
Scanner
.
_table
[
ch
]
===
'
undefined
'
// not static token
&&
!
Scanner
.
isDigitCharacter
(
ch
)
// not number
&&
!
Scanner
.
isVariableCharacter
(
ch
)
// not variable
);
this
.
pos
+=
len
;
return
{
type
,
pos
,
len
};
}
}
abstract
class
Marker
{
// pos: number;
toString
()
{
return
''
;
}
}
class
Text
extends
Marker
{
constructor
(
public
string
:
string
)
{
super
();
}
toString
()
{
return
this
.
string
;
}
}
class
TabStop
extends
Marker
{
constructor
(
public
order
:
string
)
{
super
();
}
}
class
Placeholder
extends
Marker
{
constructor
(
public
name
:
string
,
public
value
:
Marker
[])
{
super
();
}
toString
()
{
let
result
=
''
;
for
(
const
m
of
this
.
value
)
{
result
+=
m
.
toString
();
}
return
result
;
}
}
class
CodeSnippet
implements
ICodeSnippet
{
finishPlaceHolderIndex
=
-
1
;
placeHolders
=
[];
lines
=
[];
constructor
(
marker
:
Marker
[])
{
let
output
=
''
;
for
(
const
m
of
marker
)
{
output
+=
m
.
toString
();
}
this
.
lines
=
output
.
split
(
'
\n
'
);
}
}
export
class
SnippetParser
{
private
_scanner
=
new
Scanner
();
private
_token
:
Token
;
private
_prevToken
:
Token
;
parse
(
value
:
string
):
ICodeSnippet
{
const
marker
:
Marker
[]
=
[];
this
.
_scanner
.
text
(
value
);
this
.
_token
=
this
.
_scanner
.
next
();
while
(
this
.
_parse
(
marker
)
||
this
.
_parseAny
(
marker
))
{
// nothing
}
return
new
CodeSnippet
(
marker
);
}
private
_accept
(
type
:
TokenType
):
boolean
{
if
(
type
===
undefined
||
this
.
_token
.
type
===
type
)
{
this
.
_prevToken
=
this
.
_token
;
this
.
_token
=
this
.
_scanner
.
next
();
return
true
;
}
}
private
_return
(
token
:
Token
):
void
{
this
.
_prevToken
=
undefined
;
this
.
_token
=
token
;
this
.
_scanner
.
pos
=
token
.
pos
+
token
.
len
;
}
private
_parse
(
marker
:
Marker
[]):
boolean
{
if
(
this
.
_parseEscaped
(
marker
))
{
return
true
;
}
else
if
(
this
.
_parseBlock
(
marker
))
{
return
true
;
}
}
private
_parseAny
(
marker
:
Marker
[]):
boolean
{
if
(
this
.
_token
.
type
!==
TokenType
.
EOF
)
{
this
.
_accept
(
undefined
);
marker
.
push
(
this
.
_scanner
.
tokenText
(
this
.
_prevToken
));
return
true
;
}
}
private
_parseBlock
(
marker
:
Marker
[]):
boolean
{
let
{
pos
,
value
}
=
this
.
_scanner
;
if
(
this
.
_accept
(
TokenType
.
DoubleCurlyOpen
))
{
let
name
:
string
;
if
(
this
.
_accept
(
TokenType
.
VariableName
))
{
name
=
this
.
_scanner
.
tokenText
(
this
.
_prevToken
);
if
(
!
this
.
_accept
(
TokenType
.
Colon
))
{
this
.
_return
(
this
.
_prevToken
);
name
=
undefined
;
}
}
let
children
:
Marker
[]
=
[];
while
(
true
)
{
if
(
this
.
_accept
(
TokenType
.
DoubleCurlyClose
))
{
marker
.
push
(
new
Placeholder
(
name
,
children
));
return
true
;
}
if
(
this
.
_parse
(
children
)
||
this
.
_parseAny
(
children
))
{
continue
;
}
marker
.
push
(
new
Text
(
'
{{
'
));
marker
.
push
(...
children
);
return
;
}
}
}
private
_parseEscaped
(
marker
:
Marker
[]):
boolean
{
if
(
this
.
_accept
(
TokenType
.
Backslash
))
{
if
(
this
.
_accept
(
TokenType
.
CurlyOpen
)
||
this
.
_accept
(
TokenType
.
CurlyClose
)
||
this
.
_accept
(
TokenType
.
Backslash
))
{
// just consume them
}
marker
.
push
(
new
Text
(
this
.
_scanner
.
tokenText
(
this
.
_prevToken
)));
return
true
;
}
}
}
src/vs/editor/contrib/snippet/test/common/snippetParser.test.ts
0 → 100644
浏览文件 @
e6570733
/*---------------------------------------------------------------------------------------------
* 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
{
Scanner
,
TokenType
,
SnippetParser
}
from
'
vs/editor/contrib/snippet/common/snippetParser
'
;
suite
(
'
SnippetParser
'
,
()
=>
{
test
(
'
Scanner
'
,
()
=>
{
const
scanner
=
new
Scanner
();
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
abc
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
{{abc}}
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
DoubleCurlyOpen
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
DoubleCurlyClose
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
abc()
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Format
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
abc 123
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Format
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Int
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
$foo
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Dollar
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
$foo_bar
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Dollar
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
$foo-bar
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Dollar
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Format
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
${foo}
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Dollar
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
CurlyOpen
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
CurlyClose
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
${1223:foo}
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Dollar
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
CurlyOpen
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Int
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Colon
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
VariableName
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
CurlyClose
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
EOF
);
scanner
.
text
(
'
\\
${}
'
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Backslash
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
Dollar
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
CurlyOpen
);
assert
.
equal
(
scanner
.
next
().
type
,
TokenType
.
CurlyClose
);
});
function
assertOutput
(
value
:
string
,
expected
:
string
)
{
const
p
=
new
SnippetParser
();
const
{
lines
}
=
p
.
parse
(
value
);
assert
.
equal
(
lines
.
join
(
'
\n
'
),
expected
);
}
test
(
'
Snippet, Output
'
,
()
=>
{
assertOutput
(
'
$
'
,
'
$
'
);
assertOutput
(
'
{
'
,
'
{
'
);
assertOutput
(
'
{{
'
,
'
{{
'
);
assertOutput
(
'
{{dd
'
,
'
{{dd
'
);
assertOutput
(
'
}}
'
,
'
}}
'
);
assertOutput
(
'
ff}}
'
,
'
ff}}
'
);
assertOutput
(
'
farboo
'
,
'
farboo
'
);
assertOutput
(
'
far{{}}boo
'
,
'
farboo
'
);
assertOutput
(
'
far{{123}}boo
'
,
'
far123boo
'
);
assertOutput
(
'
far{{id:bern}}boo
'
,
'
farbernboo
'
);
assertOutput
(
'
far{{id:bern {{basel}}}}boo
'
,
'
farbern baselboo
'
);
assertOutput
(
'
far{{id:bern {{id:basel}}}}boo
'
,
'
farbern baselboo
'
);
assertOutput
(
'
far{{id:bern {{id2:basel}}}}boo
'
,
'
farbern baselboo
'
);
});
});
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录