Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
f76ca9f6
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,发现更多精彩内容 >>
未验证
提交
f76ca9f6
编写于
3月 18, 2020
作者:
P
Pine
提交者:
GitHub
3月 18, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #92597 from microsoft/octref/live-rename
On Type Rename for #88424
上级
1c2c8baf
196562bf
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
1064 addition
and
83 deletion
+1064
-83
src/vs/editor/common/config/editorOptions.ts
src/vs/editor/common/config/editorOptions.ts
+10
-0
src/vs/editor/common/modes.ts
src/vs/editor/common/modes.ts
+19
-0
src/vs/editor/common/standalone/standaloneEnums.ts
src/vs/editor/common/standalone/standaloneEnums.ts
+42
-41
src/vs/editor/contrib/rename/media/onTypeRename.css
src/vs/editor/contrib/rename/media/onTypeRename.css
+11
-0
src/vs/editor/contrib/rename/onTypeRename.ts
src/vs/editor/contrib/rename/onTypeRename.ts
+367
-0
src/vs/editor/contrib/rename/test/onTypeRename.test.ts
src/vs/editor/contrib/rename/test/onTypeRename.test.ts
+451
-0
src/vs/editor/editor.all.ts
src/vs/editor/editor.all.ts
+1
-0
src/vs/editor/standalone/browser/standaloneLanguages.ts
src/vs/editor/standalone/browser/standaloneLanguages.ts
+8
-0
src/vs/monaco.d.ts
src/vs/monaco.d.ts
+65
-41
src/vs/vscode.proposed.d.ts
src/vs/vscode.proposed.d.ts
+37
-0
src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
+12
-0
src/vs/workbench/api/common/extHost.api.impl.ts
src/vs/workbench/api/common/extHost.api.impl.ts
+4
-0
src/vs/workbench/api/common/extHost.protocol.ts
src/vs/workbench/api/common/extHost.protocol.ts
+2
-0
src/vs/workbench/api/common/extHostLanguageFeatures.ts
src/vs/workbench/api/common/extHostLanguageFeatures.ts
+35
-1
未找到文件。
src/vs/editor/common/config/editorOptions.ts
浏览文件 @
f76ca9f6
...
...
@@ -135,6 +135,11 @@ export interface IEditorOptions {
* Defaults to false.
*/
readOnly
?:
boolean
;
/**
* Rename matching regions on type.
* Defaults to false.
*/
renameOnType
?:
boolean
;
/**
* Should the editor render validation decorations.
* Defaults to editable.
...
...
@@ -3374,6 +3379,7 @@ export const enum EditorOption {
quickSuggestions
,
quickSuggestionsDelay
,
readOnly
,
renameOnType
,
renderControlCharacters
,
renderIndentGuides
,
renderFinalNewline
,
...
...
@@ -3790,6 +3796,10 @@ export const EditorOptions = {
readOnly
:
register
(
new
EditorBooleanOption
(
EditorOption
.
readOnly
,
'
readOnly
'
,
false
,
)),
renameOnType
:
register
(
new
EditorBooleanOption
(
EditorOption
.
renameOnType
,
'
renameOnType
'
,
false
,
{
description
:
nls
.
localize
(
'
renameOnType
'
,
"
Controls whether the editor auto renames on type.
"
)
}
)),
renderControlCharacters
:
register
(
new
EditorBooleanOption
(
EditorOption
.
renderControlCharacters
,
'
renderControlCharacters
'
,
false
,
{
description
:
nls
.
localize
(
'
renderControlCharacters
'
,
"
Controls whether the editor should render control characters.
"
)
}
...
...
src/vs/editor/common/modes.ts
浏览文件 @
f76ca9f6
...
...
@@ -789,6 +789,20 @@ export interface DocumentHighlightProvider {
provideDocumentHighlights
(
model
:
model
.
ITextModel
,
position
:
Position
,
token
:
CancellationToken
):
ProviderResult
<
DocumentHighlight
[]
>
;
}
/**
* The rename provider interface defines the contract between extensions and
* the live-rename feature.
*/
export
interface
OnTypeRenameProvider
{
stopPattern
?:
RegExp
;
/**
* Provide a list of ranges that can be live-renamed together.
*/
provideOnTypeRenameRanges
(
model
:
model
.
ITextModel
,
position
:
Position
,
token
:
CancellationToken
):
ProviderResult
<
IRange
[]
>
;
}
/**
* Value-object that contains additional information when
* requesting references.
...
...
@@ -1642,6 +1656,11 @@ export const DocumentSymbolProviderRegistry = new LanguageFeatureRegistry<Docume
*/
export
const
DocumentHighlightProviderRegistry
=
new
LanguageFeatureRegistry
<
DocumentHighlightProvider
>
();
/**
* @internal
*/
export
const
OnTypeRenameProviderRegistry
=
new
LanguageFeatureRegistry
<
OnTypeRenameProvider
>
();
/**
* @internal
*/
...
...
src/vs/editor/common/standalone/standaloneEnums.ts
浏览文件 @
f76ca9f6
...
...
@@ -238,47 +238,48 @@ export enum EditorOption {
quickSuggestions
=
70
,
quickSuggestionsDelay
=
71
,
readOnly
=
72
,
renderControlCharacters
=
73
,
renderIndentGuides
=
74
,
renderFinalNewline
=
75
,
renderLineHighlight
=
76
,
renderValidationDecorations
=
77
,
renderWhitespace
=
78
,
revealHorizontalRightPadding
=
79
,
roundedSelection
=
80
,
rulers
=
81
,
scrollbar
=
82
,
scrollBeyondLastColumn
=
83
,
scrollBeyondLastLine
=
84
,
scrollPredominantAxis
=
85
,
selectionClipboard
=
86
,
selectionHighlight
=
87
,
selectOnLineNumbers
=
88
,
showFoldingControls
=
89
,
showUnused
=
90
,
snippetSuggestions
=
91
,
smoothScrolling
=
92
,
stopRenderingLineAfter
=
93
,
suggest
=
94
,
suggestFontSize
=
95
,
suggestLineHeight
=
96
,
suggestOnTriggerCharacters
=
97
,
suggestSelection
=
98
,
tabCompletion
=
99
,
useTabStops
=
100
,
wordSeparators
=
101
,
wordWrap
=
102
,
wordWrapBreakAfterCharacters
=
103
,
wordWrapBreakBeforeCharacters
=
104
,
wordWrapColumn
=
105
,
wordWrapMinified
=
106
,
wrappingIndent
=
107
,
wrappingStrategy
=
108
,
editorClassName
=
109
,
pixelRatio
=
110
,
tabFocusMode
=
111
,
layoutInfo
=
112
,
wrappingInfo
=
113
renameOnType
=
73
,
renderControlCharacters
=
74
,
renderIndentGuides
=
75
,
renderFinalNewline
=
76
,
renderLineHighlight
=
77
,
renderValidationDecorations
=
78
,
renderWhitespace
=
79
,
revealHorizontalRightPadding
=
80
,
roundedSelection
=
81
,
rulers
=
82
,
scrollbar
=
83
,
scrollBeyondLastColumn
=
84
,
scrollBeyondLastLine
=
85
,
scrollPredominantAxis
=
86
,
selectionClipboard
=
87
,
selectionHighlight
=
88
,
selectOnLineNumbers
=
89
,
showFoldingControls
=
90
,
showUnused
=
91
,
snippetSuggestions
=
92
,
smoothScrolling
=
93
,
stopRenderingLineAfter
=
94
,
suggest
=
95
,
suggestFontSize
=
96
,
suggestLineHeight
=
97
,
suggestOnTriggerCharacters
=
98
,
suggestSelection
=
99
,
tabCompletion
=
100
,
useTabStops
=
101
,
wordSeparators
=
102
,
wordWrap
=
103
,
wordWrapBreakAfterCharacters
=
104
,
wordWrapBreakBeforeCharacters
=
105
,
wordWrapColumn
=
106
,
wordWrapMinified
=
107
,
wrappingIndent
=
108
,
wrappingStrategy
=
109
,
editorClassName
=
110
,
pixelRatio
=
111
,
tabFocusMode
=
112
,
layoutInfo
=
113
,
wrappingInfo
=
114
}
/**
...
...
src/vs/editor/contrib/rename/media/onTypeRename.css
0 → 100644
浏览文件 @
f76ca9f6
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor
.on-type-rename-decoration
{
background
:
rgba
(
255
,
0
,
0
,
0.3
);
border-left
:
1px
solid
rgba
(
255
,
0
,
0
,
0.3
);
/* So border can be transparent */
background-clip
:
padding-box
;
}
src/vs/editor/contrib/rename/onTypeRename.ts
0 → 100644
浏览文件 @
f76ca9f6
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
'
vs/css!./media/onTypeRename
'
;
import
*
as
nls
from
'
vs/nls
'
;
import
{
registerEditorContribution
,
registerModelAndPositionCommand
,
EditorAction
,
EditorCommand
,
ServicesAccessor
,
registerEditorAction
,
registerEditorCommand
}
from
'
vs/editor/browser/editorExtensions
'
;
import
*
as
arrays
from
'
vs/base/common/arrays
'
;
import
{
IEditorContribution
}
from
'
vs/editor/common/editorCommon
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
ICodeEditor
}
from
'
vs/editor/browser/editorBrowser
'
;
import
{
EditorOption
}
from
'
vs/editor/common/config/editorOptions
'
;
import
{
Position
,
IPosition
}
from
'
vs/editor/common/core/position
'
;
import
{
ITextModel
,
IModelDeltaDecoration
,
TrackedRangeStickiness
,
IIdentifiedSingleEditOperation
}
from
'
vs/editor/common/model
'
;
import
{
CancellationToken
}
from
'
vs/base/common/cancellation
'
;
import
{
IRange
,
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
OnTypeRenameProviderRegistry
}
from
'
vs/editor/common/modes
'
;
import
{
first
,
createCancelablePromise
,
CancelablePromise
,
RunOnceScheduler
}
from
'
vs/base/common/async
'
;
import
{
ModelDecorationOptions
}
from
'
vs/editor/common/model/textModel
'
;
import
{
ContextKeyExpr
,
RawContextKey
,
IContextKeyService
,
IContextKey
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
EditorContextKeys
}
from
'
vs/editor/common/editorContextKeys
'
;
import
{
KeyCode
,
KeyMod
}
from
'
vs/base/common/keyCodes
'
;
import
{
KeybindingWeight
}
from
'
vs/platform/keybinding/common/keybindingsRegistry
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
ICodeEditorService
}
from
'
vs/editor/browser/services/codeEditorService
'
;
import
{
onUnexpectedError
,
onUnexpectedExternalError
}
from
'
vs/base/common/errors
'
;
import
*
as
strings
from
'
vs/base/common/strings
'
;
export
const
CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE
=
new
RawContextKey
<
boolean
>
(
'
onTypeRenameInputVisible
'
,
false
);
export
class
OnTypeRenameContribution
extends
Disposable
implements
IEditorContribution
{
public
static
readonly
ID
=
'
editor.contrib.onTypeRename
'
;
private
static
readonly
DECORATION
=
ModelDecorationOptions
.
register
({
stickiness
:
TrackedRangeStickiness
.
AlwaysGrowsWhenTypingAtEdges
,
className
:
'
on-type-rename-decoration
'
});
static
get
(
editor
:
ICodeEditor
):
OnTypeRenameContribution
{
return
editor
.
getContribution
<
OnTypeRenameContribution
>
(
OnTypeRenameContribution
.
ID
);
}
private
readonly
_editor
:
ICodeEditor
;
private
_enabled
:
boolean
;
private
readonly
_visibleContextKey
:
IContextKey
<
boolean
>
;
private
_currentRequest
:
CancelablePromise
<
{
ranges
:
IRange
[],
stopPattern
?:
RegExp
}
|
null
|
undefined
>
|
null
;
private
_currentDecorations
:
string
[];
// The one at index 0 is the reference one
private
_stopPattern
:
RegExp
;
private
_ignoreChangeEvent
:
boolean
;
private
_updateMirrors
:
RunOnceScheduler
;
constructor
(
editor
:
ICodeEditor
,
@
IContextKeyService
contextKeyService
:
IContextKeyService
)
{
super
();
this
.
_editor
=
editor
;
this
.
_enabled
=
this
.
_editor
.
getOption
(
EditorOption
.
renameOnType
);
this
.
_visibleContextKey
=
CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE
.
bindTo
(
contextKeyService
);
this
.
_currentRequest
=
null
;
this
.
_currentDecorations
=
[];
this
.
_stopPattern
=
/^
\s
/
;
this
.
_ignoreChangeEvent
=
false
;
this
.
_updateMirrors
=
this
.
_register
(
new
RunOnceScheduler
(()
=>
this
.
_doUpdateMirrors
(),
0
));
this
.
_register
(
this
.
_editor
.
onDidChangeModel
((
e
)
=>
{
this
.
stopAll
();
this
.
run
();
}));
this
.
_register
(
this
.
_editor
.
onDidChangeConfiguration
((
e
)
=>
{
if
(
e
.
hasChanged
(
EditorOption
.
renameOnType
))
{
this
.
_enabled
=
this
.
_editor
.
getOption
(
EditorOption
.
renameOnType
);
this
.
stopAll
();
this
.
run
();
}
}));
this
.
_register
(
this
.
_editor
.
onDidChangeCursorPosition
((
e
)
=>
{
// no regions, run
if
(
this
.
_currentDecorations
.
length
===
0
)
{
this
.
run
(
e
.
position
);
}
// has cached regions, don't run
if
(
!
this
.
_editor
.
hasModel
())
{
return
;
}
if
(
this
.
_currentDecorations
.
length
===
0
)
{
return
;
}
const
model
=
this
.
_editor
.
getModel
();
const
currentRanges
=
this
.
_currentDecorations
.
map
(
decId
=>
model
.
getDecorationRange
(
decId
)
!
);
// just moving cursor around, don't run again
if
(
Range
.
containsPosition
(
currentRanges
[
0
],
e
.
position
))
{
return
;
}
// moving cursor out of primary region, run
this
.
run
(
e
.
position
);
}));
this
.
_register
(
OnTypeRenameProviderRegistry
.
onDidChange
(()
=>
{
this
.
run
();
}));
this
.
_register
(
this
.
_editor
.
onDidChangeModelContent
((
e
)
=>
{
if
(
this
.
_ignoreChangeEvent
)
{
return
;
}
if
(
!
this
.
_editor
.
hasModel
())
{
return
;
}
if
(
this
.
_currentDecorations
.
length
===
0
)
{
// nothing to do
return
;
}
if
(
e
.
isUndoing
||
e
.
isRedoing
)
{
return
;
}
if
(
e
.
changes
[
0
]
&&
this
.
_stopPattern
.
test
(
e
.
changes
[
0
].
text
))
{
this
.
stopAll
();
return
;
}
this
.
_updateMirrors
.
schedule
();
}));
}
private
_doUpdateMirrors
():
void
{
if
(
!
this
.
_editor
.
hasModel
())
{
return
;
}
if
(
this
.
_currentDecorations
.
length
===
0
)
{
// nothing to do
return
;
}
const
model
=
this
.
_editor
.
getModel
();
const
currentRanges
=
this
.
_currentDecorations
.
map
(
decId
=>
model
.
getDecorationRange
(
decId
)
!
);
const
referenceRange
=
currentRanges
[
0
];
if
(
referenceRange
.
startLineNumber
!==
referenceRange
.
endLineNumber
)
{
return
this
.
stopAll
();
}
const
referenceValue
=
model
.
getValueInRange
(
referenceRange
);
if
(
this
.
_stopPattern
.
test
(
referenceValue
))
{
return
this
.
stopAll
();
}
let
edits
:
IIdentifiedSingleEditOperation
[]
=
[];
for
(
let
i
=
1
,
len
=
currentRanges
.
length
;
i
<
len
;
i
++
)
{
const
mirrorRange
=
currentRanges
[
i
];
if
(
mirrorRange
.
startLineNumber
!==
mirrorRange
.
endLineNumber
)
{
edits
.
push
({
range
:
mirrorRange
,
text
:
referenceValue
});
}
else
{
let
oldValue
=
model
.
getValueInRange
(
mirrorRange
);
let
newValue
=
referenceValue
;
let
rangeStartColumn
=
mirrorRange
.
startColumn
;
let
rangeEndColumn
=
mirrorRange
.
endColumn
;
const
commonPrefixLength
=
strings
.
commonPrefixLength
(
oldValue
,
newValue
);
rangeStartColumn
+=
commonPrefixLength
;
oldValue
=
oldValue
.
substr
(
commonPrefixLength
);
newValue
=
newValue
.
substr
(
commonPrefixLength
);
const
commonSuffixLength
=
strings
.
commonSuffixLength
(
oldValue
,
newValue
);
rangeEndColumn
-=
commonSuffixLength
;
oldValue
=
oldValue
.
substr
(
0
,
oldValue
.
length
-
commonSuffixLength
);
newValue
=
newValue
.
substr
(
0
,
newValue
.
length
-
commonSuffixLength
);
if
(
rangeStartColumn
!==
rangeEndColumn
||
newValue
.
length
!==
0
)
{
edits
.
push
({
range
:
new
Range
(
mirrorRange
.
startLineNumber
,
rangeStartColumn
,
mirrorRange
.
endLineNumber
,
rangeEndColumn
),
text
:
newValue
});
}
}
}
if
(
edits
.
length
===
0
)
{
return
;
}
try
{
this
.
_ignoreChangeEvent
=
true
;
const
prevEditOperationType
=
this
.
_editor
.
_getCursors
().
getPrevEditOperationType
();
this
.
_editor
.
executeEdits
(
'
onTypeRename
'
,
edits
);
this
.
_editor
.
_getCursors
().
setPrevEditOperationType
(
prevEditOperationType
);
}
finally
{
this
.
_ignoreChangeEvent
=
false
;
}
}
public
dispose
():
void
{
super
.
dispose
();
this
.
stopAll
();
}
stopAll
():
void
{
this
.
_visibleContextKey
.
set
(
false
);
this
.
_currentDecorations
=
this
.
_editor
.
deltaDecorations
(
this
.
_currentDecorations
,
[]);
}
async
run
(
position
:
Position
|
null
=
this
.
_editor
.
getPosition
(),
force
=
false
):
Promise
<
void
>
{
if
(
!
position
)
{
return
;
}
if
(
!
this
.
_enabled
&&
!
force
)
{
return
;
}
if
(
!
this
.
_editor
.
hasModel
())
{
return
;
}
if
(
this
.
_currentRequest
)
{
this
.
_currentRequest
.
cancel
();
this
.
_currentRequest
=
null
;
}
const
model
=
this
.
_editor
.
getModel
();
this
.
_currentRequest
=
createCancelablePromise
(
token
=>
getOnTypeRenameRanges
(
model
,
position
,
token
));
try
{
const
response
=
await
this
.
_currentRequest
;
let
ranges
:
IRange
[]
=
[];
if
(
response
?.
ranges
)
{
ranges
=
response
.
ranges
;
}
if
(
response
?.
stopPattern
)
{
this
.
_stopPattern
=
response
.
stopPattern
;
}
let
foundReferenceRange
=
false
;
for
(
let
i
=
0
,
len
=
ranges
.
length
;
i
<
len
;
i
++
)
{
if
(
Range
.
containsPosition
(
ranges
[
i
],
position
))
{
foundReferenceRange
=
true
;
if
(
i
!==
0
)
{
const
referenceRange
=
ranges
[
i
];
ranges
.
splice
(
i
,
1
);
ranges
.
unshift
(
referenceRange
);
}
break
;
}
}
if
(
!
foundReferenceRange
)
{
// Cannot do on type rename if the ranges are not where the cursor is...
this
.
stopAll
();
return
;
}
const
decorations
:
IModelDeltaDecoration
[]
=
ranges
.
map
(
range
=>
({
range
:
range
,
options
:
OnTypeRenameContribution
.
DECORATION
}));
this
.
_visibleContextKey
.
set
(
true
);
this
.
_currentDecorations
=
this
.
_editor
.
deltaDecorations
(
this
.
_currentDecorations
,
decorations
);
}
catch
(
err
)
{
onUnexpectedError
(
err
);
this
.
stopAll
();
}
}
}
export
class
OnTypeRenameAction
extends
EditorAction
{
constructor
()
{
super
({
id
:
'
editor.action.onTypeRename
'
,
label
:
nls
.
localize
(
'
onTypeRename.label
'
,
"
On Type Rename Symbol
"
),
alias
:
'
On Type Rename Symbol
'
,
precondition
:
ContextKeyExpr
.
and
(
EditorContextKeys
.
writable
,
EditorContextKeys
.
hasRenameProvider
),
kbOpts
:
{
kbExpr
:
EditorContextKeys
.
editorTextFocus
,
primary
:
KeyMod
.
CtrlCmd
|
KeyMod
.
Shift
|
KeyCode
.
F2
,
weight
:
KeybindingWeight
.
EditorContrib
}
});
}
runCommand
(
accessor
:
ServicesAccessor
,
args
:
[
URI
,
IPosition
]):
void
|
Promise
<
void
>
{
const
editorService
=
accessor
.
get
(
ICodeEditorService
);
const
[
uri
,
pos
]
=
Array
.
isArray
(
args
)
&&
args
||
[
undefined
,
undefined
];
if
(
URI
.
isUri
(
uri
)
&&
Position
.
isIPosition
(
pos
))
{
return
editorService
.
openCodeEditor
({
resource
:
uri
},
editorService
.
getActiveCodeEditor
()).
then
(
editor
=>
{
if
(
!
editor
)
{
return
;
}
editor
.
setPosition
(
pos
);
editor
.
invokeWithinContext
(
accessor
=>
{
this
.
reportTelemetry
(
accessor
,
editor
);
return
this
.
run
(
accessor
,
editor
);
});
},
onUnexpectedError
);
}
return
super
.
runCommand
(
accessor
,
args
);
}
run
(
accessor
:
ServicesAccessor
,
editor
:
ICodeEditor
):
Promise
<
void
>
{
const
controller
=
OnTypeRenameContribution
.
get
(
editor
);
if
(
controller
)
{
return
Promise
.
resolve
(
controller
.
run
(
editor
.
getPosition
(),
true
));
}
return
Promise
.
resolve
();
}
}
const
OnTypeRenameCommand
=
EditorCommand
.
bindToContribution
<
OnTypeRenameContribution
>
(
OnTypeRenameContribution
.
get
);
registerEditorCommand
(
new
OnTypeRenameCommand
({
id
:
'
cancelOnTypeRenameInput
'
,
precondition
:
CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE
,
handler
:
x
=>
x
.
stopAll
(),
kbOpts
:
{
kbExpr
:
EditorContextKeys
.
editorTextFocus
,
weight
:
KeybindingWeight
.
EditorContrib
+
99
,
primary
:
KeyCode
.
Escape
,
secondary
:
[
KeyMod
.
Shift
|
KeyCode
.
Escape
]
}
}));
export
function
getOnTypeRenameRanges
(
model
:
ITextModel
,
position
:
Position
,
token
:
CancellationToken
):
Promise
<
{
ranges
:
IRange
[],
stopPattern
?:
RegExp
}
|
undefined
|
null
>
{
const
orderedByScore
=
OnTypeRenameProviderRegistry
.
ordered
(
model
);
// in order of score ask the occurrences provider
// until someone response with a good result
// (good = none empty array)
return
first
<
{
ranges
:
IRange
[],
stopPattern
?:
RegExp
}
|
undefined
>
(
orderedByScore
.
map
(
provider
=>
()
=>
{
return
Promise
.
resolve
(
provider
.
provideOnTypeRenameRanges
(
model
,
position
,
token
)).
then
((
ranges
)
=>
{
if
(
!
ranges
)
{
return
undefined
;
}
return
{
ranges
,
stopPattern
:
provider
.
stopPattern
};
},
(
err
)
=>
{
onUnexpectedExternalError
(
err
);
return
undefined
;
});
}),
result
=>
!!
result
&&
arrays
.
isNonEmptyArray
(
result
?.
ranges
));
}
registerModelAndPositionCommand
(
'
_executeRenameOnTypeProvider
'
,
(
model
,
position
)
=>
getOnTypeRenameRanges
(
model
,
position
,
CancellationToken
.
None
));
registerEditorContribution
(
OnTypeRenameContribution
.
ID
,
OnTypeRenameContribution
);
registerEditorAction
(
OnTypeRenameAction
);
src/vs/editor/contrib/rename/test/onTypeRename.test.ts
0 → 100644
浏览文件 @
f76ca9f6
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
assert
from
'
assert
'
;
import
{
DisposableStore
}
from
'
vs/base/common/lifecycle
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
Handler
}
from
'
vs/editor/common/editorCommon
'
;
import
*
as
modes
from
'
vs/editor/common/modes
'
;
import
{
OnTypeRenameContribution
}
from
'
vs/editor/contrib/rename/onTypeRename
'
;
import
{
createTestCodeEditor
,
TestCodeEditor
}
from
'
vs/editor/test/browser/testCodeEditor
'
;
import
{
createTextModel
}
from
'
vs/editor/test/common/editorTestUtils
'
;
import
{
CoreEditingCommands
}
from
'
vs/editor/browser/controller/coreCommands
'
;
const
mockFile
=
URI
.
parse
(
'
test:somefile.ttt
'
);
const
mockFileSelector
=
{
scheme
:
'
test
'
};
const
timeout
=
30
;
suite
(
'
On type rename
'
,
()
=>
{
const
disposables
=
new
DisposableStore
();
setup
(()
=>
{
disposables
.
clear
();
});
teardown
(()
=>
{
disposables
.
clear
();
});
function
createMockEditor
(
text
:
string
|
string
[])
{
const
model
=
typeof
text
===
'
string
'
?
createTextModel
(
text
,
undefined
,
undefined
,
mockFile
)
:
createTextModel
(
text
.
join
(
'
\n
'
),
undefined
,
undefined
,
mockFile
);
const
editor
=
createTestCodeEditor
({
model
});
disposables
.
add
(
model
);
disposables
.
add
(
editor
);
return
editor
;
}
function
testCase
(
name
:
string
,
initialState
:
{
text
:
string
|
string
[],
ranges
:
Range
[],
stopPattern
?:
RegExp
},
operations
:
(
editor
:
TestCodeEditor
,
contrib
:
OnTypeRenameContribution
)
=>
Promise
<
void
>
,
expectedEndText
:
string
|
string
[]
)
{
test
(
name
,
async
()
=>
{
disposables
.
add
(
modes
.
OnTypeRenameProviderRegistry
.
register
(
mockFileSelector
,
{
stopPattern
:
initialState
.
stopPattern
||
/^
\s
/
,
provideOnTypeRenameRanges
()
{
return
initialState
.
ranges
;
}
}));
const
editor
=
createMockEditor
(
initialState
.
text
);
const
ontypeRenameContribution
=
editor
.
registerAndInstantiateContribution
(
OnTypeRenameContribution
.
ID
,
OnTypeRenameContribution
);
await
operations
(
editor
,
ontypeRenameContribution
);
return
new
Promise
((
resolve
)
=>
{
setTimeout
(()
=>
{
if
(
typeof
expectedEndText
===
'
string
'
)
{
assert
.
equal
(
editor
.
getModel
()
!
.
getValue
(),
expectedEndText
);
}
else
{
assert
.
equal
(
editor
.
getModel
()
!
.
getValue
(),
expectedEndText
.
join
(
'
\n
'
));
}
resolve
();
},
timeout
);
});
});
}
const
state
=
{
text
:
'
<ooo></ooo>
'
,
ranges
:
[
new
Range
(
1
,
2
,
1
,
5
),
new
Range
(
1
,
8
,
1
,
11
),
]
};
/**
* Simple insertion
*/
testCase
(
'
Simple insert - initial
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<iooo></iooo>
'
);
testCase
(
'
Simple insert - middle
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
3
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<oioo></oioo>
'
);
testCase
(
'
Simple insert - end
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<oooi></oooi>
'
);
/**
* Simple insertion - end
*/
testCase
(
'
Simple insert end - initial
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
8
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<iooo></iooo>
'
);
testCase
(
'
Simple insert end - middle
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
9
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<oioo></oioo>
'
);
testCase
(
'
Simple insert end - end
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
11
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<oooi></oooi>
'
);
/**
* Boundary insertion
*/
testCase
(
'
Simple insert - out of boundary
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
1
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
i<ooo></ooo>
'
);
testCase
(
'
Simple insert - out of boundary 2
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
6
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<ooo>i</ooo>
'
);
testCase
(
'
Simple insert - out of boundary 3
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
7
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<ooo><i/ooo>
'
);
testCase
(
'
Simple insert - out of boundary 4
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
12
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<ooo></ooo>i
'
);
/**
* Insert + Move
*/
testCase
(
'
Continuous insert
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<iiooo></iiooo>
'
);
testCase
(
'
Insert - move - insert
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
editor
.
setPosition
(
new
Position
(
1
,
4
));
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<ioioo></ioioo>
'
);
testCase
(
'
Insert - move - insert outside region
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
editor
.
setPosition
(
new
Position
(
1
,
7
));
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<iooo>i</iooo>
'
);
/**
* Selection insert
*/
testCase
(
'
Selection insert - simple
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
setSelection
(
new
Range
(
1
,
2
,
1
,
3
));
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<ioo></ioo>
'
);
testCase
(
'
Selection insert - whole
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
setSelection
(
new
Range
(
1
,
2
,
1
,
5
));
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<i></i>
'
);
testCase
(
'
Selection insert - across boundary
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
setSelection
(
new
Range
(
1
,
1
,
1
,
3
));
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
ioo></oo>
'
);
/**
* @todo
* Undefined behavior
*/
// testCase('Selection insert - across two boundary', state, async (editor, ontypeRenameContribution) => {
// const pos = new Position(1, 2);
// editor.setPosition(pos);
// await ontypeRenameContribution.run(pos, true);
// editor.setSelection(new Range(1, 4, 1, 9));
// editor.trigger('keyboard', Handler.Type, { text: 'i' });
// }, '<ooioo>');
/**
* Break out behavior
*/
testCase
(
'
Breakout - type space
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
'
});
},
'
<ooo ></ooo>
'
);
testCase
(
'
Breakout - type space then undo
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
'
});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<ooo></ooo>
'
);
testCase
(
'
Breakout - type space in middle
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
4
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
'
});
},
'
<oo o></ooo>
'
);
testCase
(
'
Breakout - paste content starting with space
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Paste
,
{
text
:
'
i="i"
'
});
},
'
<ooo i="i"></ooo>
'
);
testCase
(
'
Breakout - paste content starting with space then undo
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Paste
,
{
text
:
'
i="i"
'
});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<ooo></ooo>
'
);
testCase
(
'
Breakout - paste content starting with space in middle
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
4
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Paste
,
{
text
:
'
i
'
});
},
'
<oo io></ooo>
'
);
/**
* Break out with custom stopPattern
*/
const
state3
=
{
...
state
,
stopPattern
:
/^s/
};
testCase
(
'
Breakout with stop pattern - insert
'
,
state3
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
'
<iooo></iooo>
'
);
testCase
(
'
Breakout with stop pattern - insert stop char
'
,
state3
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
s
'
});
},
'
<sooo></ooo>
'
);
testCase
(
'
Breakout with stop pattern - paste char
'
,
state3
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Paste
,
{
text
:
'
s
'
});
},
'
<sooo></ooo>
'
);
testCase
(
'
Breakout with stop pattern - paste string
'
,
state3
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Paste
,
{
text
:
'
so
'
});
},
'
<soooo></ooo>
'
);
testCase
(
'
Breakout with stop pattern - insert at end
'
,
state3
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
s
'
});
},
'
<ooos></ooo>
'
);
/**
* Delete
*/
testCase
(
'
Delete - left char
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
'
deleteLeft
'
,
{});
},
'
<oo></oo>
'
);
testCase
(
'
Delete - left char then undo
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
'
deleteLeft
'
,
{});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<ooo></ooo>
'
);
testCase
(
'
Delete - left word
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
'
deleteWordLeft
'
,
{});
},
'
<></>
'
);
testCase
(
'
Delete - left word then undo
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
'
deleteWordLeft
'
,
{});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<ooo></ooo>
'
);
/**
* Todo: Fix test
*/
// testCase('Delete - left all', state, async (editor, ontypeRenameContribution) => {
// const pos = new Position(1, 3);
// editor.setPosition(pos);
// await ontypeRenameContribution.run(pos, true);
// editor.trigger('keyboard', 'deleteAllLeft', {});
// }, '></>');
/**
* Todo: Fix test
*/
// testCase('Delete - left all then undo', state, async (editor, ontypeRenameContribution) => {
// const pos = new Position(1, 5);
// editor.setPosition(pos);
// await ontypeRenameContribution.run(pos, true);
// editor.trigger('keyboard', 'deleteAllLeft', {});
// CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
// }, '></ooo>');
testCase
(
'
Delete - left all then undo twice
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
'
deleteAllLeft
'
,
{});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<ooo></ooo>
'
);
testCase
(
'
Delete - selection
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
5
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
setSelection
(
new
Range
(
1
,
2
,
1
,
3
));
editor
.
trigger
(
'
keyboard
'
,
'
deleteLeft
'
,
{});
},
'
<oo></oo>
'
);
testCase
(
'
Delete - selection across boundary
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
3
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
setSelection
(
new
Range
(
1
,
1
,
1
,
3
));
editor
.
trigger
(
'
keyboard
'
,
'
deleteLeft
'
,
{});
},
'
oo></oo>
'
);
/**
* Undo / redo
*/
testCase
(
'
Undo/redo - simple undo
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<ooo></ooo>
'
);
testCase
(
'
Undo/redo - simple undo/redo
'
,
state
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
CoreEditingCommands
.
Undo
.
runEditorCommand
(
null
,
editor
,
null
);
CoreEditingCommands
.
Redo
.
runEditorCommand
(
null
,
editor
,
null
);
},
'
<iooo></iooo>
'
);
/**
* Multi line
*/
const
state2
=
{
text
:
[
'
<ooo>
'
,
'
</ooo>
'
],
ranges
:
[
new
Range
(
1
,
2
,
1
,
5
),
new
Range
(
2
,
3
,
2
,
6
),
]
};
testCase
(
'
Multiline insert
'
,
state2
,
async
(
editor
,
ontypeRenameContribution
)
=>
{
const
pos
=
new
Position
(
1
,
2
);
editor
.
setPosition
(
pos
);
await
ontypeRenameContribution
.
run
(
pos
,
true
);
editor
.
trigger
(
'
keyboard
'
,
Handler
.
Type
,
{
text
:
'
i
'
});
},
[
'
<iooo>
'
,
'
</iooo>
'
]);
});
src/vs/editor/editor.all.ts
浏览文件 @
f76ca9f6
...
...
@@ -32,6 +32,7 @@ import 'vs/editor/contrib/linesOperations/linesOperations';
import
'
vs/editor/contrib/links/links
'
;
import
'
vs/editor/contrib/multicursor/multicursor
'
;
import
'
vs/editor/contrib/parameterHints/parameterHints
'
;
import
'
vs/editor/contrib/rename/onTypeRename
'
;
import
'
vs/editor/contrib/rename/rename
'
;
import
'
vs/editor/contrib/smartSelect/smartSelect
'
;
import
'
vs/editor/contrib/snippet/snippetController2
'
;
...
...
src/vs/editor/standalone/browser/standaloneLanguages.ts
浏览文件 @
f76ca9f6
...
...
@@ -391,6 +391,13 @@ export function registerDocumentHighlightProvider(languageId: string, provider:
return
modes
.
DocumentHighlightProviderRegistry
.
register
(
languageId
,
provider
);
}
/**
* Register an on type rename provider.
*/
export
function
registerOnTypeRenameProvider
(
languageId
:
string
,
provider
:
modes
.
OnTypeRenameProvider
):
IDisposable
{
return
modes
.
OnTypeRenameProviderRegistry
.
register
(
languageId
,
provider
);
}
/**
* Register a definition provider (used by e.g. go to definition).
*/
...
...
@@ -559,6 +566,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
registerHoverProvider
:
<
any
>
registerHoverProvider
,
registerDocumentSymbolProvider
:
<
any
>
registerDocumentSymbolProvider
,
registerDocumentHighlightProvider
:
<
any
>
registerDocumentHighlightProvider
,
registerOnTypeRenameProvider
:
<
any
>
registerOnTypeRenameProvider
,
registerDefinitionProvider
:
<
any
>
registerDefinitionProvider
,
registerImplementationProvider
:
<
any
>
registerImplementationProvider
,
registerTypeDefinitionProvider
:
<
any
>
registerTypeDefinitionProvider
,
...
...
src/vs/monaco.d.ts
浏览文件 @
f76ca9f6
...
...
@@ -2673,6 +2673,11 @@ declare namespace monaco.editor {
* Defaults to false.
*/
readOnly
?:
boolean
;
/**
* Rename matching regions on type.
* Defaults to false.
*/
renameOnType
?:
boolean
;
/**
* Should the editor render validation decorations.
* Defaults to editable.
...
...
@@ -3882,47 +3887,48 @@ declare namespace monaco.editor {
quickSuggestions
=
70
,
quickSuggestionsDelay
=
71
,
readOnly
=
72
,
renderControlCharacters
=
73
,
renderIndentGuides
=
74
,
renderFinalNewline
=
75
,
renderLineHighlight
=
76
,
renderValidationDecorations
=
77
,
renderWhitespace
=
78
,
revealHorizontalRightPadding
=
79
,
roundedSelection
=
80
,
rulers
=
81
,
scrollbar
=
82
,
scrollBeyondLastColumn
=
83
,
scrollBeyondLastLine
=
84
,
scrollPredominantAxis
=
85
,
selectionClipboard
=
86
,
selectionHighlight
=
87
,
selectOnLineNumbers
=
88
,
showFoldingControls
=
89
,
showUnused
=
90
,
snippetSuggestions
=
91
,
smoothScrolling
=
92
,
stopRenderingLineAfter
=
93
,
suggest
=
94
,
suggestFontSize
=
95
,
suggestLineHeight
=
96
,
suggestOnTriggerCharacters
=
97
,
suggestSelection
=
98
,
tabCompletion
=
99
,
useTabStops
=
100
,
wordSeparators
=
101
,
wordWrap
=
102
,
wordWrapBreakAfterCharacters
=
103
,
wordWrapBreakBeforeCharacters
=
104
,
wordWrapColumn
=
105
,
wordWrapMinified
=
106
,
wrappingIndent
=
107
,
wrappingStrategy
=
108
,
editorClassName
=
109
,
pixelRatio
=
110
,
tabFocusMode
=
111
,
layoutInfo
=
112
,
wrappingInfo
=
113
renameOnType
=
73
,
renderControlCharacters
=
74
,
renderIndentGuides
=
75
,
renderFinalNewline
=
76
,
renderLineHighlight
=
77
,
renderValidationDecorations
=
78
,
renderWhitespace
=
79
,
revealHorizontalRightPadding
=
80
,
roundedSelection
=
81
,
rulers
=
82
,
scrollbar
=
83
,
scrollBeyondLastColumn
=
84
,
scrollBeyondLastLine
=
85
,
scrollPredominantAxis
=
86
,
selectionClipboard
=
87
,
selectionHighlight
=
88
,
selectOnLineNumbers
=
89
,
showFoldingControls
=
90
,
showUnused
=
91
,
snippetSuggestions
=
92
,
smoothScrolling
=
93
,
stopRenderingLineAfter
=
94
,
suggest
=
95
,
suggestFontSize
=
96
,
suggestLineHeight
=
97
,
suggestOnTriggerCharacters
=
98
,
suggestSelection
=
99
,
tabCompletion
=
100
,
useTabStops
=
101
,
wordSeparators
=
102
,
wordWrap
=
103
,
wordWrapBreakAfterCharacters
=
104
,
wordWrapBreakBeforeCharacters
=
105
,
wordWrapColumn
=
106
,
wordWrapMinified
=
107
,
wrappingIndent
=
108
,
wrappingStrategy
=
109
,
editorClassName
=
110
,
pixelRatio
=
111
,
tabFocusMode
=
112
,
layoutInfo
=
113
,
wrappingInfo
=
114
}
export
const
EditorOptions
:
{
acceptSuggestionOnCommitCharacter
:
IEditorOption
<
EditorOption
.
acceptSuggestionOnCommitCharacter
,
boolean
>
;
...
...
@@ -3998,6 +4004,7 @@ declare namespace monaco.editor {
quickSuggestions
:
IEditorOption
<
EditorOption
.
quickSuggestions
,
ValidQuickSuggestionsOptions
>
;
quickSuggestionsDelay
:
IEditorOption
<
EditorOption
.
quickSuggestionsDelay
,
number
>
;
readOnly
:
IEditorOption
<
EditorOption
.
readOnly
,
boolean
>
;
renameOnType
:
IEditorOption
<
EditorOption
.
renameOnType
,
boolean
>
;
renderControlCharacters
:
IEditorOption
<
EditorOption
.
renderControlCharacters
,
boolean
>
;
renderIndentGuides
:
IEditorOption
<
EditorOption
.
renderIndentGuides
,
boolean
>
;
renderFinalNewline
:
IEditorOption
<
EditorOption
.
renderFinalNewline
,
boolean
>
;
...
...
@@ -4954,6 +4961,11 @@ declare namespace monaco.languages {
*/
export
function
registerDocumentHighlightProvider
(
languageId
:
string
,
provider
:
DocumentHighlightProvider
):
IDisposable
;
/**
* Register an on type rename provider.
*/
export
function
registerOnTypeRenameProvider
(
languageId
:
string
,
provider
:
OnTypeRenameProvider
):
IDisposable
;
/**
* Register a definition provider (used by e.g. go to definition).
*/
...
...
@@ -5712,6 +5724,18 @@ declare namespace monaco.languages {
provideDocumentHighlights
(
model
:
editor
.
ITextModel
,
position
:
Position
,
token
:
CancellationToken
):
ProviderResult
<
DocumentHighlight
[]
>
;
}
/**
* The rename provider interface defines the contract between extensions and
* the live-rename feature.
*/
export
interface
OnTypeRenameProvider
{
stopPattern
?:
RegExp
;
/**
* Provide a list of ranges that can be live-renamed together.
*/
provideOnTypeRenameRanges
(
model
:
editor
.
ITextModel
,
position
:
Position
,
token
:
CancellationToken
):
ProviderResult
<
IRange
[]
>
;
}
/**
* Value-object that contains additional information when
* requesting references.
...
...
src/vs/vscode.proposed.d.ts
浏览文件 @
f76ca9f6
...
...
@@ -1230,6 +1230,43 @@ declare module 'vscode' {
//#endregion
//#region OnTypeRename: https://github.com/microsoft/vscode/issues/88424
/**
* The rename provider interface defines the contract between extensions and
* the live-rename feature.
*/
export
interface
OnTypeRenameProvider
{
/**
* Provide a list of ranges that can be live renamed together.
*
* @param document The document in which the command was invoked.
* @param position The position at which the command was invoked.
* @param token A cancellation token.
* @return A list of ranges that can be live-renamed togehter. The ranges must have
* identical length and contain identical text content. The ranges cannot overlap.
*/
provideOnTypeRenameRanges
(
document
:
TextDocument
,
position
:
Position
,
token
:
CancellationToken
):
ProviderResult
<
Range
[]
>
;
}
namespace
languages
{
/**
* Register a rename provider that works on type.
*
* Multiple providers can be registered for a language. In that case providers are sorted
* by their [score](#languages.match) and the best-matching provider is used. Failure
* of the selected provider will cause a failure of the whole operation.
*
* @param selector A selector that defines the documents this provider is applicable to.
* @param provider An on type rename provider.
* @param stopPattern Stop on type renaming when input text matches the regular expression. Defaults to `^\s`.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export
function
registerOnTypeRenameProvider
(
selector
:
DocumentSelector
,
provider
:
OnTypeRenameProvider
,
stopPattern
?:
RegExp
):
Disposable
;
}
//#endregion
//#region Custom editors: https://github.com/microsoft/vscode/issues/77131
// TODO:
...
...
src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
浏览文件 @
f76ca9f6
...
...
@@ -261,6 +261,18 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}));
}
// --- on type rename
$registerOnTypeRenameProvider
(
handle
:
number
,
selector
:
IDocumentFilterDto
[],
stopPattern
?:
IRegExpDto
):
void
{
const
revivedStopPattern
=
stopPattern
?
MainThreadLanguageFeatures
.
_reviveRegExp
(
stopPattern
)
:
undefined
;
this
.
_registrations
.
set
(
handle
,
modes
.
OnTypeRenameProviderRegistry
.
register
(
selector
,
<
modes
.
OnTypeRenameProvider
>
{
stopPattern
:
revivedStopPattern
,
provideOnTypeRenameRanges
:
(
model
:
ITextModel
,
position
:
EditorPosition
,
token
:
CancellationToken
):
Promise
<
IRange
[]
|
undefined
>
=>
{
return
this
.
_proxy
.
$provideOnTypeRenameRanges
(
handle
,
model
.
uri
,
position
,
token
);
}
}));
}
// --- references
$registerReferenceSupport
(
handle
:
number
,
selector
:
IDocumentFilterDto
[]):
void
{
...
...
src/vs/workbench/api/common/extHost.api.impl.ts
浏览文件 @
f76ca9f6
...
...
@@ -362,6 +362,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerDocumentHighlightProvider
(
selector
:
vscode
.
DocumentSelector
,
provider
:
vscode
.
DocumentHighlightProvider
):
vscode
.
Disposable
{
return
extHostLanguageFeatures
.
registerDocumentHighlightProvider
(
extension
,
checkSelector
(
selector
),
provider
);
},
registerOnTypeRenameProvider
(
selector
:
vscode
.
DocumentSelector
,
provider
:
vscode
.
OnTypeRenameProvider
,
stopPattern
?:
RegExp
):
vscode
.
Disposable
{
checkProposedApiEnabled
(
extension
);
return
extHostLanguageFeatures
.
registerOnTypeRenameProvider
(
extension
,
checkSelector
(
selector
),
provider
,
stopPattern
);
},
registerReferenceProvider
(
selector
:
vscode
.
DocumentSelector
,
provider
:
vscode
.
ReferenceProvider
):
vscode
.
Disposable
{
return
extHostLanguageFeatures
.
registerReferenceProvider
(
extension
,
checkSelector
(
selector
),
provider
);
},
...
...
src/vs/workbench/api/common/extHost.protocol.ts
浏览文件 @
f76ca9f6
...
...
@@ -362,6 +362,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerHoverProvider
(
handle
:
number
,
selector
:
IDocumentFilterDto
[]):
void
;
$registerEvaluatableExpressionProvider
(
handle
:
number
,
selector
:
IDocumentFilterDto
[]):
void
;
$registerDocumentHighlightProvider
(
handle
:
number
,
selector
:
IDocumentFilterDto
[]):
void
;
$registerOnTypeRenameProvider
(
handle
:
number
,
selector
:
IDocumentFilterDto
[],
stopPattern
:
IRegExpDto
|
undefined
):
void
;
$registerReferenceSupport
(
handle
:
number
,
selector
:
IDocumentFilterDto
[]):
void
;
$registerQuickFixSupport
(
handle
:
number
,
selector
:
IDocumentFilterDto
[],
metadata
:
ICodeActionProviderMetadataDto
,
displayName
:
string
):
void
;
$registerDocumentFormattingSupport
(
handle
:
number
,
selector
:
IDocumentFilterDto
[],
extensionId
:
ExtensionIdentifier
,
displayName
:
string
):
void
;
...
...
@@ -1286,6 +1287,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideHover
(
handle
:
number
,
resource
:
UriComponents
,
position
:
IPosition
,
token
:
CancellationToken
):
Promise
<
modes
.
Hover
|
undefined
>
;
$provideEvaluatableExpression
(
handle
:
number
,
resource
:
UriComponents
,
position
:
IPosition
,
token
:
CancellationToken
):
Promise
<
modes
.
EvaluatableExpression
|
undefined
>
;
$provideDocumentHighlights
(
handle
:
number
,
resource
:
UriComponents
,
position
:
IPosition
,
token
:
CancellationToken
):
Promise
<
modes
.
DocumentHighlight
[]
|
undefined
>
;
$provideOnTypeRenameRanges
(
handle
:
number
,
resource
:
UriComponents
,
position
:
IPosition
,
token
:
CancellationToken
):
Promise
<
IRange
[]
|
undefined
>
;
$provideReferences
(
handle
:
number
,
resource
:
UriComponents
,
position
:
IPosition
,
context
:
modes
.
ReferenceContext
,
token
:
CancellationToken
):
Promise
<
ILocationDto
[]
|
undefined
>
;
$provideCodeActions
(
handle
:
number
,
resource
:
UriComponents
,
rangeOrSelection
:
IRange
|
ISelection
,
context
:
modes
.
CodeActionContext
,
token
:
CancellationToken
):
Promise
<
ICodeActionListDto
|
undefined
>
;
$releaseCodeActions
(
handle
:
number
,
cacheId
:
number
):
void
;
...
...
src/vs/workbench/api/common/extHostLanguageFeatures.ts
浏览文件 @
f76ca9f6
...
...
@@ -318,6 +318,26 @@ class DocumentHighlightAdapter {
}
}
class
OnTypeRenameAdapter
{
constructor
(
private
readonly
_documents
:
ExtHostDocuments
,
private
readonly
_provider
:
vscode
.
OnTypeRenameProvider
)
{
}
provideOnTypeRenameRanges
(
resource
:
URI
,
position
:
IPosition
,
token
:
CancellationToken
):
Promise
<
IRange
[]
|
undefined
>
{
const
doc
=
this
.
_documents
.
getDocument
(
resource
);
const
pos
=
typeConvert
.
Position
.
to
(
position
);
return
asPromise
(()
=>
this
.
_provider
.
provideOnTypeRenameRanges
(
doc
,
pos
,
token
)).
then
(
value
=>
{
if
(
Array
.
isArray
(
value
))
{
return
coalesce
(
value
.
map
(
typeConvert
.
Range
.
from
));
}
return
undefined
;
});
}
}
class
ReferenceAdapter
{
constructor
(
...
...
@@ -1350,7 +1370,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
|
RangeFormattingAdapter
|
OnTypeFormattingAdapter
|
NavigateTypeAdapter
|
RenameAdapter
|
SuggestAdapter
|
SignatureHelpAdapter
|
LinkProviderAdapter
|
ImplementationAdapter
|
TypeDefinitionAdapter
|
ColorProviderAdapter
|
FoldingProviderAdapter
|
DeclarationAdapter
|
SelectionRangeAdapter
|
CallHierarchyAdapter
|
DocumentSemanticTokensAdapter
|
DocumentRangeSemanticTokensAdapter
|
EvaluatableExpressionAdapter
;
|
SelectionRangeAdapter
|
CallHierarchyAdapter
|
DocumentSemanticTokensAdapter
|
DocumentRangeSemanticTokensAdapter
|
EvaluatableExpressionAdapter
|
OnTypeRenameAdapter
;
class
AdapterData
{
constructor
(
...
...
@@ -1594,6 +1615,19 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return
this
.
_withAdapter
(
handle
,
DocumentHighlightAdapter
,
adapter
=>
adapter
.
provideDocumentHighlights
(
URI
.
revive
(
resource
),
position
,
token
),
undefined
);
}
// --- on type rename
registerOnTypeRenameProvider
(
extension
:
IExtensionDescription
,
selector
:
vscode
.
DocumentSelector
,
provider
:
vscode
.
OnTypeRenameProvider
,
stopPattern
?:
RegExp
):
vscode
.
Disposable
{
const
handle
=
this
.
_addNewAdapter
(
new
OnTypeRenameAdapter
(
this
.
_documents
,
provider
),
extension
);
const
serializedStopPattern
=
stopPattern
?
ExtHostLanguageFeatures
.
_serializeRegExp
(
stopPattern
)
:
undefined
;
this
.
_proxy
.
$registerOnTypeRenameProvider
(
handle
,
this
.
_transformDocumentSelector
(
selector
),
serializedStopPattern
);
return
this
.
_createDisposable
(
handle
);
}
$provideOnTypeRenameRanges
(
handle
:
number
,
resource
:
UriComponents
,
position
:
IPosition
,
token
:
CancellationToken
):
Promise
<
IRange
[]
|
undefined
>
{
return
this
.
_withAdapter
(
handle
,
OnTypeRenameAdapter
,
adapter
=>
adapter
.
provideOnTypeRenameRanges
(
URI
.
revive
(
resource
),
position
,
token
),
undefined
);
}
// --- references
registerReferenceProvider
(
extension
:
IExtensionDescription
,
selector
:
vscode
.
DocumentSelector
,
provider
:
vscode
.
ReferenceProvider
):
vscode
.
Disposable
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录