Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
2bceb255
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,发现更多精彩内容 >>
提交
2bceb255
编写于
8月 15, 2019
作者:
A
Alex Dima
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fixes #78975: Look for autoclosing pairs in edits coming in from suggestions
上级
8e55695f
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
140 addition
and
39 deletion
+140
-39
src/vs/editor/browser/editorBrowser.ts
src/vs/editor/browser/editorBrowser.ts
+2
-2
src/vs/editor/browser/widget/codeEditorWidget.ts
src/vs/editor/browser/widget/codeEditorWidget.ts
+10
-8
src/vs/editor/common/controller/cursor.ts
src/vs/editor/common/controller/cursor.ts
+100
-19
src/vs/editor/contrib/snippet/snippetSession.ts
src/vs/editor/contrib/snippet/snippetSession.ts
+5
-9
src/vs/editor/test/browser/controller/cursor.test.ts
src/vs/editor/test/browser/controller/cursor.test.ts
+22
-0
src/vs/monaco.d.ts
src/vs/monaco.d.ts
+1
-1
未找到文件。
src/vs/editor/browser/editorBrowser.ts
浏览文件 @
2bceb255
...
...
@@ -13,7 +13,7 @@ import { IPosition, Position } from 'vs/editor/common/core/position';
import
{
IRange
,
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
Selection
}
from
'
vs/editor/common/core/selection
'
;
import
*
as
editorCommon
from
'
vs/editor/common/editorCommon
'
;
import
{
IIdentifiedSingleEditOperation
,
IModelDecoration
,
IModelDeltaDecoration
,
ITextModel
}
from
'
vs/editor/common/model
'
;
import
{
IIdentifiedSingleEditOperation
,
IModelDecoration
,
IModelDeltaDecoration
,
ITextModel
,
ICursorStateComputer
}
from
'
vs/editor/common/model
'
;
import
{
IModelContentChangedEvent
,
IModelDecorationsChangedEvent
,
IModelLanguageChangedEvent
,
IModelLanguageConfigurationChangedEvent
,
IModelOptionsChangedEvent
}
from
'
vs/editor/common/model/textModelEvents
'
;
import
{
OverviewRulerZone
}
from
'
vs/editor/common/view/overviewZoneManager
'
;
import
{
IEditorWhitespace
}
from
'
vs/editor/common/viewLayout/whitespaceComputer
'
;
...
...
@@ -612,7 +612,7 @@ export interface ICodeEditor extends editorCommon.IEditor {
* @param edits The edits to execute.
* @param endCursorState Cursor state after the edits were applied.
*/
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
endCursorState
?:
Selection
[]):
boolean
;
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
endCursorState
?:
ICursorStateComputer
|
Selection
[]):
boolean
;
/**
* Execute multiple (concomitant) commands on the editor.
...
...
src/vs/editor/browser/widget/codeEditorWidget.ts
浏览文件 @
2bceb255
...
...
@@ -33,7 +33,7 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection';
import
{
InternalEditorAction
}
from
'
vs/editor/common/editorAction
'
;
import
*
as
editorCommon
from
'
vs/editor/common/editorCommon
'
;
import
{
EditorContextKeys
}
from
'
vs/editor/common/editorContextKeys
'
;
import
{
EndOfLinePreference
,
IIdentifiedSingleEditOperation
,
IModelDecoration
,
IModelDecorationOptions
,
IModelDecorationsChangeAccessor
,
IModelDeltaDecoration
,
ITextModel
}
from
'
vs/editor/common/model
'
;
import
{
EndOfLinePreference
,
IIdentifiedSingleEditOperation
,
IModelDecoration
,
IModelDecorationOptions
,
IModelDecorationsChangeAccessor
,
IModelDeltaDecoration
,
ITextModel
,
ICursorStateComputer
}
from
'
vs/editor/common/model
'
;
import
{
ClassName
}
from
'
vs/editor/common/model/intervalTree
'
;
import
{
ModelDecorationOptions
}
from
'
vs/editor/common/model/textModel
'
;
import
{
IModelContentChangedEvent
,
IModelDecorationsChangedEvent
,
IModelLanguageChangedEvent
,
IModelLanguageConfigurationChangedEvent
,
IModelOptionsChangedEvent
}
from
'
vs/editor/common/model/textModelEvents
'
;
...
...
@@ -980,7 +980,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
return
true
;
}
public
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
endCursorState
?:
Selection
[]):
boolean
{
public
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
endCursorState
?:
ICursorStateComputer
|
Selection
[]):
boolean
{
if
(
!
this
.
_modelData
)
{
return
false
;
}
...
...
@@ -989,14 +989,16 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
return
false
;
}
this
.
_modelData
.
model
.
pushEditOperations
(
this
.
_modelData
.
cursor
.
getSelections
(),
edits
,
()
=>
{
return
endCursorState
?
endCursorState
:
null
;
});
if
(
endCursorState
)
{
this
.
_modelData
.
cursor
.
setSelections
(
source
,
endCursorState
);
let
cursorStateComputer
:
ICursorStateComputer
;
if
(
!
endCursorState
)
{
cursorStateComputer
=
()
=>
null
;
}
else
if
(
Array
.
isArray
(
endCursorState
))
{
cursorStateComputer
=
()
=>
endCursorState
;
}
else
{
cursorStateComputer
=
endCursorState
;
}
this
.
_modelData
.
cursor
.
executeEdits
(
source
,
edits
,
cursorStateComputer
);
return
true
;
}
...
...
src/vs/editor/common/controller/cursor.ts
浏览文件 @
2bceb255
...
...
@@ -15,7 +15,7 @@ import { Position } from 'vs/editor/common/core/position';
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
ISelection
,
Selection
,
SelectionDirection
}
from
'
vs/editor/common/core/selection
'
;
import
*
as
editorCommon
from
'
vs/editor/common/editorCommon
'
;
import
{
IIdentifiedSingleEditOperation
,
ITextModel
,
TrackedRangeStickiness
,
IModelDeltaDecoration
}
from
'
vs/editor/common/model
'
;
import
{
IIdentifiedSingleEditOperation
,
ITextModel
,
TrackedRangeStickiness
,
IModelDeltaDecoration
,
ICursorStateComputer
}
from
'
vs/editor/common/model
'
;
import
{
RawContentChangedType
}
from
'
vs/editor/common/model/textModelEvents
'
;
import
*
as
viewEvents
from
'
vs/editor/common/view/viewEvents
'
;
import
{
IViewModel
}
from
'
vs/editor/common/viewModel/viewModel
'
;
...
...
@@ -429,6 +429,31 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
// ------ auxiliary handling logic
private
_pushAutoClosedAction
(
autoClosedCharactersRanges
:
Range
[],
autoClosedEnclosingRanges
:
Range
[]):
void
{
let
autoClosedCharactersDeltaDecorations
:
IModelDeltaDecoration
[]
=
[];
let
autoClosedEnclosingDeltaDecorations
:
IModelDeltaDecoration
[]
=
[];
for
(
let
i
=
0
,
len
=
autoClosedCharactersRanges
.
length
;
i
<
len
;
i
++
)
{
autoClosedCharactersDeltaDecorations
.
push
({
range
:
autoClosedCharactersRanges
[
i
],
options
:
{
inlineClassName
:
'
auto-closed-character
'
,
stickiness
:
TrackedRangeStickiness
.
NeverGrowsWhenTypingAtEdges
}
});
autoClosedEnclosingDeltaDecorations
.
push
({
range
:
autoClosedEnclosingRanges
[
i
],
options
:
{
stickiness
:
TrackedRangeStickiness
.
NeverGrowsWhenTypingAtEdges
}
});
}
const
autoClosedCharactersDecorations
=
this
.
_model
.
deltaDecorations
([],
autoClosedCharactersDeltaDecorations
);
const
autoClosedEnclosingDecorations
=
this
.
_model
.
deltaDecorations
([],
autoClosedEnclosingDeltaDecorations
);
this
.
_autoClosedActions
.
push
(
new
AutoClosedAction
(
this
.
_model
,
autoClosedCharactersDecorations
,
autoClosedEnclosingDecorations
));
}
private
_executeEditOperation
(
opResult
:
EditOperationResult
|
null
):
void
{
if
(
!
opResult
)
{
...
...
@@ -446,32 +471,19 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
this
.
_interpretCommandResult
(
result
);
// Check for auto-closing closed characters
let
autoClosedCharactersRanges
:
IModelDeltaDecoration
[]
=
[];
let
autoClosedEnclosingRanges
:
IModelDeltaDecoration
[]
=
[];
let
autoClosedCharactersRanges
:
Range
[]
=
[];
let
autoClosedEnclosingRanges
:
Range
[]
=
[];
for
(
let
i
=
0
;
i
<
opResult
.
commands
.
length
;
i
++
)
{
const
command
=
opResult
.
commands
[
i
];
if
(
command
instanceof
TypeWithAutoClosingCommand
&&
command
.
enclosingRange
&&
command
.
closeCharacterRange
)
{
autoClosedCharactersRanges
.
push
({
range
:
command
.
closeCharacterRange
,
options
:
{
inlineClassName
:
'
auto-closed-character
'
,
stickiness
:
TrackedRangeStickiness
.
NeverGrowsWhenTypingAtEdges
}
});
autoClosedEnclosingRanges
.
push
({
range
:
command
.
enclosingRange
,
options
:
{
stickiness
:
TrackedRangeStickiness
.
NeverGrowsWhenTypingAtEdges
}
});
autoClosedCharactersRanges
.
push
(
command
.
closeCharacterRange
);
autoClosedEnclosingRanges
.
push
(
command
.
enclosingRange
);
}
}
if
(
autoClosedCharactersRanges
.
length
>
0
)
{
const
autoClosedCharactersDecorations
=
this
.
_model
.
deltaDecorations
([],
autoClosedCharactersRanges
);
const
autoClosedEnclosingDecorations
=
this
.
_model
.
deltaDecorations
([],
autoClosedEnclosingRanges
);
this
.
_autoClosedActions
.
push
(
new
AutoClosedAction
(
this
.
_model
,
autoClosedCharactersDecorations
,
autoClosedEnclosingDecorations
));
this
.
_pushAutoClosedAction
(
autoClosedCharactersRanges
,
autoClosedEnclosingRanges
);
}
this
.
_prevEditOperationType
=
opResult
.
type
;
...
...
@@ -563,6 +575,75 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
// -----------------------------------------------------------------------------------------------------------
// ----- handlers beyond this point
private
_findAutoClosingPairs
(
edits
:
IIdentifiedSingleEditOperation
[]):
[
number
,
number
][]
|
null
{
if
(
!
edits
.
length
)
{
return
null
;
}
let
indices
:
[
number
,
number
][]
=
[];
for
(
let
i
=
0
,
len
=
edits
.
length
;
i
<
len
;
i
++
)
{
const
edit
=
edits
[
i
];
if
(
!
edit
.
text
||
edit
.
text
.
indexOf
(
'
\n
'
)
>=
0
)
{
return
null
;
}
const
m
=
edit
.
text
.
match
(
/
([
)
\]
}>'"`
])([^
)
\]
}>'"`
]
*
)
$/
);
if
(
!
m
)
{
return
null
;
}
const
closeChar
=
m
[
1
];
const
openChar
=
this
.
context
.
config
.
autoClosingPairsClose
[
closeChar
];
if
(
!
openChar
)
{
return
null
;
}
const
closeCharIndex
=
edit
.
text
.
length
-
m
[
2
].
length
-
1
;
const
openCharIndex
=
edit
.
text
.
lastIndexOf
(
openChar
,
closeCharIndex
-
1
);
if
(
openCharIndex
===
-
1
)
{
return
null
;
}
indices
.
push
([
openCharIndex
,
closeCharIndex
]);
}
return
indices
;
}
public
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
cursorStateComputer
:
ICursorStateComputer
):
void
{
let
autoClosingIndices
:
[
number
,
number
][]
|
null
=
null
;
if
(
source
===
'
snippet
'
)
{
autoClosingIndices
=
this
.
_findAutoClosingPairs
(
edits
);
}
if
(
autoClosingIndices
)
{
edits
[
0
].
_isTracked
=
true
;
}
let
autoClosedCharactersRanges
:
Range
[]
=
[];
let
autoClosedEnclosingRanges
:
Range
[]
=
[];
const
selections
=
this
.
_model
.
pushEditOperations
(
this
.
getSelections
(),
edits
,
(
undoEdits
)
=>
{
if
(
autoClosingIndices
)
{
for
(
let
i
=
0
,
len
=
autoClosingIndices
.
length
;
i
<
len
;
i
++
)
{
const
[
openCharInnerIndex
,
closeCharInnerIndex
]
=
autoClosingIndices
[
i
];
const
undoEdit
=
undoEdits
[
i
];
const
lineNumber
=
undoEdit
.
range
.
startLineNumber
;
const
openCharIndex
=
undoEdit
.
range
.
startColumn
-
1
+
openCharInnerIndex
;
const
closeCharIndex
=
undoEdit
.
range
.
startColumn
-
1
+
closeCharInnerIndex
;
autoClosedCharactersRanges
.
push
(
new
Range
(
lineNumber
,
closeCharIndex
+
1
,
lineNumber
,
closeCharIndex
+
2
));
autoClosedEnclosingRanges
.
push
(
new
Range
(
lineNumber
,
openCharIndex
+
1
,
lineNumber
,
closeCharIndex
+
2
));
}
}
return
cursorStateComputer
(
undoEdits
);
});
if
(
selections
)
{
this
.
setSelections
(
source
,
selections
);
}
if
(
autoClosedCharactersRanges
.
length
>
0
)
{
this
.
_pushAutoClosedAction
(
autoClosedCharactersRanges
,
autoClosedEnclosingRanges
);
}
}
public
trigger
(
source
:
string
,
handlerId
:
string
,
payload
:
any
):
void
{
const
H
=
editorCommon
.
Handler
;
...
...
src/vs/editor/contrib/snippet/snippetSession.ts
浏览文件 @
2bceb255
...
...
@@ -489,21 +489,18 @@ export class SnippetSession {
return
;
}
const
model
=
this
.
_editor
.
getModel
();
// make insert edit and start with first selections
const
{
edits
,
snippets
}
=
SnippetSession
.
createEditsAndSnippets
(
this
.
_editor
,
this
.
_template
,
this
.
_options
.
overwriteBefore
,
this
.
_options
.
overwriteAfter
,
false
,
this
.
_options
.
adjustWhitespace
,
this
.
_options
.
clipboardText
);
this
.
_snippets
=
snippets
;
const
selections
=
model
.
pushEditOperations
(
this
.
_editor
.
getSelections
()
,
edits
,
undoEdits
=>
{
this
.
_editor
.
executeEdits
(
'
snippet
'
,
edits
,
undoEdits
=>
{
if
(
this
.
_snippets
[
0
].
hasPlaceholder
)
{
return
this
.
_move
(
true
);
}
else
{
return
undoEdits
.
map
(
edit
=>
Selection
.
fromPositions
(
edit
.
range
.
getEndPosition
()));
}
})
!
;
this
.
_editor
.
setSelections
(
selections
);
this
.
_editor
.
revealRange
(
selections
[
0
]);
});
this
.
_editor
.
revealRange
(
this
.
_editor
.
getSelections
()[
0
]);
}
merge
(
template
:
string
,
options
:
ISnippetSessionInsertOptions
=
_defaultOptions
):
void
{
...
...
@@ -513,8 +510,7 @@ export class SnippetSession {
this
.
_templateMerges
.
push
([
this
.
_snippets
[
0
].
_nestingLevel
,
this
.
_snippets
[
0
].
_placeholderGroupsIdx
,
template
]);
const
{
edits
,
snippets
}
=
SnippetSession
.
createEditsAndSnippets
(
this
.
_editor
,
template
,
options
.
overwriteBefore
,
options
.
overwriteAfter
,
true
,
options
.
adjustWhitespace
,
options
.
clipboardText
);
this
.
_editor
.
setSelections
(
this
.
_editor
.
getModel
().
pushEditOperations
(
this
.
_editor
.
getSelections
(),
edits
,
undoEdits
=>
{
this
.
_editor
.
executeEdits
(
'
snippet
'
,
edits
,
undoEdits
=>
{
for
(
const
snippet
of
this
.
_snippets
)
{
snippet
.
merge
(
snippets
);
}
...
...
@@ -525,7 +521,7 @@ export class SnippetSession {
}
else
{
return
undoEdits
.
map
(
edit
=>
Selection
.
fromPositions
(
edit
.
range
.
getEndPosition
()));
}
})
!
)
;
});
}
next
():
void
{
...
...
src/vs/editor/test/browser/controller/cursor.test.ts
浏览文件 @
2bceb255
...
...
@@ -4692,6 +4692,28 @@ suite('autoClosingPairs', () => {
mode
.
dispose
();
});
test
(
'
issue #78975 - Parentheses swallowing does not work when parentheses are inserted by autocomplete
'
,
()
=>
{
let
mode
=
new
AutoClosingMode
();
usingCursor
({
text
:
[
'
<div id
'
],
languageIdentifier
:
mode
.
getLanguageIdentifier
()
},
(
model
,
cursor
)
=>
{
cursor
.
setSelections
(
'
test
'
,
[
new
Selection
(
1
,
8
,
1
,
8
)]);
cursor
.
executeEdits
(
'
snippet
'
,
[{
range
:
new
Range
(
1
,
6
,
1
,
8
),
text
:
'
id=""
'
}],
()
=>
[
new
Selection
(
1
,
10
,
1
,
10
)]);
assert
.
strictEqual
(
model
.
getLineContent
(
1
),
'
<div id=""
'
);
cursorCommand
(
cursor
,
H
.
Type
,
{
text
:
'
a
'
},
'
keyboard
'
);
assert
.
strictEqual
(
model
.
getLineContent
(
1
),
'
<div id="a"
'
);
cursorCommand
(
cursor
,
H
.
Type
,
{
text
:
'
"
'
},
'
keyboard
'
);
assert
.
strictEqual
(
model
.
getLineContent
(
1
),
'
<div id="a"
'
);
});
mode
.
dispose
();
});
test
(
'
issue #15825: accents on mac US intl keyboard
'
,
()
=>
{
let
mode
=
new
AutoClosingMode
();
usingCursor
({
...
...
src/vs/monaco.d.ts
浏览文件 @
2bceb255
...
...
@@ -4054,7 +4054,7 @@ declare namespace monaco.editor {
* @param edits The edits to execute.
* @param endCursorState Cursor state after the edits were applied.
*/
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
endCursorState
?:
Selection
[]):
boolean
;
executeEdits
(
source
:
string
,
edits
:
IIdentifiedSingleEditOperation
[],
endCursorState
?:
ICursorStateComputer
|
Selection
[]):
boolean
;
/**
* Execute multiple (concomitant) commands on the editor.
* @param source The source of the call.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录