Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
c3ce6210
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,发现更多精彩内容 >>
提交
c3ce6210
编写于
5月 03, 2017
作者:
A
Alex Dima
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Debt: Simplify TextAreaHandler
上级
9cdd0987
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
172 addition
and
215 deletion
+172
-215
src/vs/editor/browser/controller/keyboardHandler.ts
src/vs/editor/browser/controller/keyboardHandler.ts
+61
-11
src/vs/editor/browser/controller/textAreaHandler.ts
src/vs/editor/browser/controller/textAreaHandler.ts
+100
-137
src/vs/editor/browser/controller/textAreaState.ts
src/vs/editor/browser/controller/textAreaState.ts
+1
-10
src/vs/editor/common/viewModel/viewModel.ts
src/vs/editor/common/viewModel/viewModel.ts
+0
-2
src/vs/editor/common/viewModel/viewModelImpl.ts
src/vs/editor/common/viewModel/viewModelImpl.ts
+1
-9
src/vs/editor/test/browser/controller/imeTester.ts
src/vs/editor/test/browser/controller/imeTester.ts
+9
-23
src/vs/editor/test/browser/controller/textAreaState.test.ts
src/vs/editor/test/browser/controller/textAreaState.test.ts
+0
-23
未找到文件。
src/vs/editor/browser/controller/keyboardHandler.ts
浏览文件 @
c3ce6210
...
...
@@ -7,8 +7,8 @@
import
*
as
browser
from
'
vs/base/browser/browser
'
;
import
*
as
dom
from
'
vs/base/browser/dom
'
;
import
{
GlobalScreenReaderNVDA
}
from
'
vs/editor/common/config/commonEditorConfig
'
;
import
{
TextAreaHandler
}
from
'
vs/editor/browser/controller/textAreaHandler
'
;
import
{
TextAreaStrategy
}
from
'
vs/editor/browser/controller/textAreaState
'
;
import
{
TextAreaHandler
,
ITextAreaHandlerHost
}
from
'
vs/editor/browser/controller/textAreaHandler
'
;
import
{
TextAreaStrategy
,
ISimpleModel
}
from
'
vs/editor/browser/controller/textAreaState
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
ViewEventHandler
}
from
'
vs/editor/common/viewModel/viewEventHandler
'
;
import
{
Configuration
}
from
'
vs/editor/browser/config/configuration
'
;
...
...
@@ -18,6 +18,7 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents';
import
{
FastDomNode
}
from
'
vs/base/browser/fastDomNode
'
;
import
{
VerticalRevealType
}
from
'
vs/editor/common/controller/cursorEvents
'
;
import
{
ViewController
}
from
'
vs/editor/browser/view/viewController
'
;
import
{
EndOfLinePreference
}
from
"
vs/editor/common/editorCommon
"
;
export
interface
IKeyboardHandlerHelper
{
viewDomNode
:
FastDomNode
<
HTMLElement
>
;
...
...
@@ -41,16 +42,20 @@ export class KeyboardHandler extends ViewEventHandler {
private
_context
:
ViewContext
;
private
viewController
:
ViewController
;
private
viewHelper
:
IKeyboardHandlerHelper
;
private
textArea
:
FastDomNode
<
HTMLTextAreaElement
>
;
private
textAreaHandler
:
TextAreaHandler
;
private
viewHelper
:
IKeyboardHandlerHelper
;
private
visiblePosition
:
TextAreaVisiblePosition
;
private
contentLeft
:
number
;
private
contentWidth
:
number
;
private
scrollLeft
:
number
;
private
scrollTop
:
number
;
private
visiblePosition
:
TextAreaVisiblePosition
;
private
_selections
:
Range
[];
private
_lastCopiedValue
:
string
;
private
_lastCopiedValueIsFromEmptySelection
:
boolean
;
private
textAreaHandler
:
TextAreaHandler
;
constructor
(
context
:
ViewContext
,
viewController
:
ViewController
,
viewHelper
:
IKeyboardHandlerHelper
)
{
super
();
...
...
@@ -67,11 +72,55 @@ export class KeyboardHandler extends ViewEventHandler {
this
.
scrollLeft
=
0
;
this
.
scrollTop
=
0
;
this
.
textAreaHandler
=
new
TextAreaHandler
(
this
.
_getStrategy
(),
this
.
textArea
,
this
.
_context
.
model
);
this
.
_selections
=
[
new
Range
(
1
,
1
,
1
,
1
)];
this
.
_lastCopiedValue
=
null
;
this
.
_lastCopiedValueIsFromEmptySelection
=
false
;
const
textAreaHandlerHost
:
ITextAreaHandlerHost
=
{
getPlainTextToCopy
:
():
string
=>
{
const
whatToCopy
=
this
.
_context
.
model
.
getPlainTextToCopy
(
this
.
_selections
,
browser
.
enableEmptySelectionClipboard
);
if
(
browser
.
enableEmptySelectionClipboard
)
{
if
(
browser
.
isFirefox
)
{
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
this
.
_lastCopiedValue
=
whatToCopy
.
replace
(
/
\r\n
/g
,
'
\n
'
);
}
else
{
this
.
_lastCopiedValue
=
whatToCopy
;
}
let
selections
=
this
.
_selections
;
this
.
_lastCopiedValueIsFromEmptySelection
=
(
selections
.
length
===
1
&&
selections
[
0
].
isEmpty
());
}
return
whatToCopy
;
},
getHTMLToCopy
:
():
string
=>
{
return
this
.
_context
.
model
.
getHTMLToCopy
(
this
.
_selections
,
browser
.
enableEmptySelectionClipboard
);
}
};
const
simpleModel
:
ISimpleModel
=
{
getLineCount
:
():
number
=>
{
return
this
.
_context
.
model
.
getLineCount
();
},
getLineMaxColumn
:
(
lineNumber
:
number
):
number
=>
{
return
this
.
_context
.
model
.
getLineMaxColumn
(
lineNumber
);
},
getValueInRange
:
(
range
:
Range
,
eol
:
EndOfLinePreference
):
string
=>
{
return
this
.
_context
.
model
.
getValueInRange
(
range
,
eol
);
}
};
this
.
textAreaHandler
=
new
TextAreaHandler
(
textAreaHandlerHost
,
this
.
_getStrategy
(),
this
.
textArea
,
simpleModel
);
this
.
_register
(
this
.
textAreaHandler
.
onKeyDown
((
e
)
=>
this
.
viewController
.
emitKeyDown
(
e
)));
this
.
_register
(
this
.
textAreaHandler
.
onKeyUp
((
e
)
=>
this
.
viewController
.
emitKeyUp
(
e
)));
this
.
_register
(
this
.
textAreaHandler
.
onPaste
((
e
)
=>
this
.
viewController
.
paste
(
'
keyboard
'
,
e
.
text
,
e
.
pasteOnNewLine
)));
this
.
_register
(
this
.
textAreaHandler
.
onPaste
((
e
)
=>
{
let
pasteOnNewLine
=
false
;
if
(
browser
.
enableEmptySelectionClipboard
)
{
pasteOnNewLine
=
(
e
.
text
===
this
.
_lastCopiedValue
&&
this
.
_lastCopiedValueIsFromEmptySelection
);
}
this
.
viewController
.
paste
(
'
keyboard
'
,
e
.
text
,
pasteOnNewLine
);
}));
this
.
_register
(
this
.
textAreaHandler
.
onCut
((
e
)
=>
this
.
viewController
.
cut
(
'
keyboard
'
)));
this
.
_register
(
this
.
textAreaHandler
.
onType
((
e
)
=>
{
if
(
e
.
replaceCharCnt
)
{
...
...
@@ -80,9 +129,9 @@ export class KeyboardHandler extends ViewEventHandler {
this
.
viewController
.
type
(
'
keyboard
'
,
e
.
text
);
}
}));
this
.
_register
(
this
.
textAreaHandler
.
onCompositionStart
((
e
)
=>
{
const
lineNumber
=
e
.
showA
tLineNumber
;
const
column
=
e
.
showA
tColumn
;
this
.
_register
(
this
.
textAreaHandler
.
onCompositionStart
(()
=>
{
const
lineNumber
=
this
.
_selections
[
0
].
star
tLineNumber
;
const
column
=
this
.
_selections
[
0
].
star
tColumn
;
this
.
_context
.
privateViewEventBus
.
emit
(
new
viewEvents
.
ViewRevealRangeRequestEvent
(
new
Range
(
lineNumber
,
column
,
lineNumber
,
column
),
...
...
@@ -132,7 +181,7 @@ export class KeyboardHandler extends ViewEventHandler {
}
}));
this
.
_register
(
this
.
textAreaHandler
.
onCompositionEnd
((
e
)
=>
{
this
.
_register
(
this
.
textAreaHandler
.
onCompositionEnd
(()
=>
{
this
.
textArea
.
unsetHeight
();
this
.
textArea
.
unsetWidth
();
this
.
textArea
.
setLeft
(
0
);
...
...
@@ -190,6 +239,7 @@ export class KeyboardHandler extends ViewEventHandler {
private
_lastCursorSelectionChanged
:
viewEvents
.
ViewCursorSelectionChangedEvent
=
null
;
public
onCursorSelectionChanged
(
e
:
viewEvents
.
ViewCursorSelectionChangedEvent
):
boolean
{
this
.
_selections
=
[
e
.
selection
].
concat
(
e
.
secondarySelections
);
this
.
_lastCursorSelectionChanged
=
e
;
return
false
;
}
...
...
src/vs/editor/browser/controller/textAreaHandler.ts
浏览文件 @
c3ce6210
...
...
@@ -32,12 +32,6 @@ const enum ReadFromTextArea {
export
interface
IPasteData
{
text
:
string
;
pasteOnNewLine
:
boolean
;
}
export
interface
ICompositionStartData
{
showAtLineNumber
:
number
;
showAtColumn
:
number
;
}
// See https://github.com/Microsoft/monaco-editor/issues/320
...
...
@@ -47,6 +41,11 @@ const isChromev55_v56 = (
&&
navigator
.
userAgent
.
indexOf
(
'
Edge/
'
)
===
-
1
);
export
interface
ITextAreaHandlerHost
{
getPlainTextToCopy
():
string
;
getHTMLToCopy
():
string
;
}
export
class
TextAreaHandler
extends
Disposable
{
private
_onKeyDown
=
this
.
_register
(
new
Emitter
<
IKeyboardEvent
>
());
...
...
@@ -64,72 +63,81 @@ export class TextAreaHandler extends Disposable {
private
_onType
=
this
.
_register
(
new
Emitter
<
ITypeData
>
());
public
onType
:
Event
<
ITypeData
>
=
this
.
_onType
.
event
;
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
ICompositionStartData
>
());
public
onCompositionStart
:
Event
<
ICompositionStartData
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionStart
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionStart
:
Event
<
void
>
=
this
.
_onCompositionStart
.
event
;
private
_onCompositionUpdate
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionUpdate
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionUpdate
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
ICompositionEvent
>
());
public
onCompositionEnd
:
Event
<
ICompositionEvent
>
=
this
.
_onCompositionEnd
.
event
;
private
_onCompositionEnd
=
this
.
_register
(
new
Emitter
<
void
>
());
public
onCompositionEnd
:
Event
<
void
>
=
this
.
_onCompositionEnd
.
event
;
private
textArea
:
TextAreaWrapper
;
private
model
:
ISimpleModel
;
// ---
private
selection
:
Range
;
private
selections
:
Range
[]
;
private
hasFocus
:
boolean
;
private
readonly
_host
:
ITextAreaHandlerHost
;
private
readonly
_textArea
:
TextAreaWrapper
;
private
readonly
_model
:
ISimpleModel
;
private
asyncTriggerCut
:
RunOnceScheduler
;
private
_selection
:
Range
;
private
_hasFocus
:
boolean
;
private
textAreaState
:
TextAreaState
;
private
textareaIsShownAtCursor
:
boolean
;
private
readonly
_asyncTriggerCut
:
RunOnceScheduler
;
private
lastCopiedValue
:
string
;
private
lastCopiedValueIsFromEmptySelec
tion
:
boolean
;
private
_textAreaState
:
TextAreaState
;
private
_isDoingComposi
tion
:
boolean
;
private
_nextCommand
:
ReadFromTextArea
;
constructor
(
strategy
:
TextAreaStrategy
,
textArea
:
FastDomNode
<
HTMLTextAreaElement
>
,
model
:
ISimpleModel
)
{
constructor
(
host
:
ITextAreaHandlerHost
,
strategy
:
TextAreaStrategy
,
textArea
:
FastDomNode
<
HTMLTextAreaElement
>
,
model
:
ISimpleModel
)
{
super
();
this
.
textArea
=
this
.
_register
(
new
TextAreaWrapper
(
textArea
));
this
.
model
=
model
;
this
.
selection
=
new
Range
(
1
,
1
,
1
,
1
);
this
.
selections
=
[
new
Range
(
1
,
1
,
1
,
1
)];
this
.
_nextCommand
=
ReadFromTextArea
.
Type
;
this
.
_host
=
host
;
this
.
_textArea
=
this
.
_register
(
new
TextAreaWrapper
(
textArea
));
this
.
_model
=
model
;
this
.
_selection
=
new
Range
(
1
,
1
,
1
,
1
);
this
.
_hasFocus
=
false
;
this
.
_asyncTriggerCut
=
this
.
_register
(
new
RunOnceScheduler
(()
=>
this
.
_onCut
.
fire
(),
0
));
this
.
_textAreaState
=
createTextAreaState
(
strategy
);
this
.
_isDoingComposition
=
false
;
this
.
asyncTriggerCut
=
this
.
_register
(
new
RunOnceScheduler
(()
=>
this
.
_onCut
.
fire
(),
0
))
;
this
.
_nextCommand
=
ReadFromTextArea
.
Type
;
this
.
lastCopiedValue
=
null
;
this
.
lastCopiedValueIsFromEmptySelection
=
false
;
this
.
textAreaState
=
createTextAreaState
(
strategy
);
this
.
_register
(
dom
.
addStandardDisposableListener
(
textArea
.
domNode
,
'
keydown
'
,
(
e
:
IKeyboardEvent
)
=>
{
if
(
this
.
_isDoingComposition
&&
e
.
equals
(
KeyCode
.
KEY_IN_COMPOSITION
))
{
// Stop propagation for keyDown events if the IME is processing key input
e
.
stopPropagation
();
}
this
.
hasFocus
=
false
;
if
(
e
.
equals
(
KeyCode
.
Escape
))
{
// Prevent default always for `Esc`, otherwise it will generate a keypress
// See https://msdn.microsoft.com/en-us/library/ie/ms536939(v=vs.85).aspx
e
.
preventDefault
();
}
this
.
_onKeyDown
.
fire
(
e
);
}));
this
.
_register
(
dom
.
addStandardDisposableListener
(
textArea
.
domNode
,
'
key
down
'
,
(
e
:
IKeyboardEvent
)
=>
this
.
_onKeyDownHandler
(
e
)));
this
.
_register
(
dom
.
addStandardDisposableListener
(
textArea
.
domNode
,
'
keyup
'
,
(
e
:
IKeyboardEvent
)
=>
this
.
_onKeyUp
.
fire
(
e
))
);
this
.
_register
(
dom
.
addStandardDisposableListener
(
textArea
.
domNode
,
'
keypress
'
,
(
e
:
IKeyboardEvent
)
=>
this
.
_onKeyPressHandler
(
e
)
));
this
.
_register
(
dom
.
addStandardDisposableListener
(
textArea
.
domNode
,
'
key
up
'
,
(
e
:
IKeyboardEvent
)
=>
{
this
.
_onKeyUp
.
fire
(
e
);
}
));
this
.
textareaIsShownAtCursor
=
false
;
let
compositionLocale
=
null
;
this
.
_register
(
dom
.
addDisposableListener
(
textArea
.
domNode
,
'
compositionstart
'
,
(
e
:
CompositionEvent
)
=>
{
if
(
this
.
textareaIsShownAtCursor
)
{
if
(
this
.
_isDoingComposition
)
{
return
;
}
this
.
textareaIsShownAtCursor
=
true
;
this
.
_isDoingComposition
=
true
;
// In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled.
if
(
!
browser
.
isEdgeOrIE
)
{
this
.
setTextAreaState
(
'
compositionstart
'
,
this
.
textAreaState
.
toEmpty
(),
false
);
this
.
setTextAreaState
(
'
compositionstart
'
,
this
.
_
textAreaState
.
toEmpty
(),
false
);
}
this
.
_onCompositionStart
.
fire
({
showAtLineNumber
:
this
.
selection
.
startLineNumber
,
showAtColumn
:
this
.
selection
.
startColumn
});
this
.
_onCompositionStart
.
fire
();
}));
this
.
_register
(
dom
.
addDisposableListener
(
textArea
.
domNode
,
'
compositionupdate
'
,
(
e
:
CompositionEvent
)
=>
{
...
...
@@ -148,75 +156,55 @@ export class TextAreaHandler extends Disposable {
// Multi-part Japanese compositions reset cursor in Edge/IE, Chinese and Korean IME don't have this issue.
// The reason that we can't use this path for all CJK IME is IE and Edge behave differently when handling Korean IME,
// which breaks this path of code.
this
.
textAreaState
=
this
.
textAreaState
.
fromTextArea
(
this
.
textArea
);
let
typeInput
=
this
.
textAreaState
.
deduceInput
();
this
.
_textAreaState
=
this
.
_textAreaState
.
fromTextArea
(
this
.
_
textArea
);
let
typeInput
=
this
.
_
textAreaState
.
deduceInput
();
this
.
_onType
.
fire
(
typeInput
);
this
.
_onCompositionUpdate
.
fire
(
e
);
return
;
}
this
.
textAreaState
=
this
.
textAreaState
.
fromText
(
e
.
data
);
let
typeInput
=
this
.
textAreaState
.
updateComposition
();
this
.
_textAreaState
=
this
.
_
textAreaState
.
fromText
(
e
.
data
);
let
typeInput
=
this
.
_
textAreaState
.
updateComposition
();
this
.
_onType
.
fire
(
typeInput
);
this
.
_onCompositionUpdate
.
fire
(
e
);
}));
let
readFromTextArea
=
()
=>
{
let
tempTextAreaState
=
this
.
textAreaState
.
fromTextArea
(
this
.
textArea
);
let
typeInput
=
tempTextAreaState
.
deduceInput
();
if
(
typeInput
.
replaceCharCnt
===
0
&&
typeInput
.
text
.
length
===
1
&&
strings
.
isHighSurrogate
(
typeInput
.
text
.
charCodeAt
(
0
)))
{
// Ignore invalid input but keep it around for next time
return
;
}
this
.
textAreaState
=
tempTextAreaState
;
// console.log('==> DEDUCED INPUT: ' + JSON.stringify(typeInput));
if
(
this
.
_nextCommand
===
ReadFromTextArea
.
Type
)
{
if
(
typeInput
.
text
!==
''
)
{
this
.
_onType
.
fire
(
typeInput
);
}
}
else
{
this
.
executePaste
(
typeInput
.
text
);
this
.
_nextCommand
=
ReadFromTextArea
.
Type
;
}
};
this
.
_register
(
dom
.
addDisposableListener
(
textArea
.
domNode
,
'
compositionend
'
,
(
e
:
CompositionEvent
)
=>
{
// console.log('onCompositionEnd: ' + e.data);
if
(
browser
.
isEdgeOrIE
&&
e
.
locale
===
'
ja
'
)
{
// https://github.com/Microsoft/monaco-editor/issues/339
this
.
textAreaState
=
this
.
textAreaState
.
fromTextArea
(
this
.
textArea
);
let
typeInput
=
this
.
textAreaState
.
deduceInput
();
this
.
_textAreaState
=
this
.
_textAreaState
.
fromTextArea
(
this
.
_
textArea
);
let
typeInput
=
this
.
_
textAreaState
.
deduceInput
();
this
.
_onType
.
fire
(
typeInput
);
}
else
{
this
.
textAreaState
=
this
.
textAreaState
.
fromText
(
e
.
data
);
let
typeInput
=
this
.
textAreaState
.
updateComposition
();
this
.
_textAreaState
=
this
.
_
textAreaState
.
fromText
(
e
.
data
);
let
typeInput
=
this
.
_
textAreaState
.
updateComposition
();
this
.
_onType
.
fire
(
typeInput
);
}
// Due to isEdgeOrIE (where the textarea was not cleared initially) and isChrome (the textarea is not updated correctly when composition ends)
// we cannot assume the text at the end consists only of the composited text
if
(
browser
.
isEdgeOrIE
||
browser
.
isChrome
)
{
this
.
textAreaState
=
this
.
textAreaState
.
fromTextArea
(
this
.
textArea
);
this
.
_textAreaState
=
this
.
_textAreaState
.
fromTextArea
(
this
.
_
textArea
);
}
if
(
!
this
.
textareaIsShownAtCursor
)
{
if
(
!
this
.
_isDoingComposition
)
{
return
;
}
this
.
textareaIsShownAtCursor
=
false
;
this
.
_isDoingComposition
=
false
;
this
.
_onCompositionEnd
.
fire
();
}));
this
.
_register
(
dom
.
addDisposableListener
(
textArea
.
domNode
,
'
input
'
,
()
=>
{
// console.log('onInput: ' + this.textArea.getValue());
if
(
this
.
textareaIsShownAtCursor
)
{
if
(
this
.
_isDoingComposition
)
{
// See https://github.com/Microsoft/monaco-editor/issues/320
if
(
isChromev55_v56
)
{
let
text
=
this
.
textArea
.
getValue
();
this
.
textAreaState
=
this
.
textAreaState
.
fromText
(
text
);
let
typeInput
=
this
.
textAreaState
.
updateComposition
();
let
text
=
this
.
_
textArea
.
getValue
();
this
.
_textAreaState
=
this
.
_
textAreaState
.
fromText
(
text
);
let
typeInput
=
this
.
_
textAreaState
.
updateComposition
();
this
.
_onType
.
fire
(
typeInput
);
let
e
=
{
locale
:
compositionLocale
,
...
...
@@ -228,14 +216,30 @@ export class TextAreaHandler extends Disposable {
return
;
}
readFromTextArea
();
let
tempTextAreaState
=
this
.
_textAreaState
.
fromTextArea
(
this
.
_textArea
);
let
typeInput
=
tempTextAreaState
.
deduceInput
();
if
(
typeInput
.
replaceCharCnt
===
0
&&
typeInput
.
text
.
length
===
1
&&
strings
.
isHighSurrogate
(
typeInput
.
text
.
charCodeAt
(
0
)))
{
// Ignore invalid input but keep it around for next time
return
;
}
this
.
_textAreaState
=
tempTextAreaState
;
// console.log('==> DEDUCED INPUT: ' + JSON.stringify(typeInput));
if
(
this
.
_nextCommand
===
ReadFromTextArea
.
Type
)
{
if
(
typeInput
.
text
!==
''
)
{
this
.
_onType
.
fire
(
typeInput
);
}
}
else
{
this
.
executePaste
(
typeInput
.
text
);
this
.
_nextCommand
=
ReadFromTextArea
.
Type
;
}
}));
// --- Clipboard operations
this
.
_register
(
dom
.
addDisposableListener
(
textArea
.
domNode
,
'
cut
'
,
(
e
:
ClipboardEvent
)
=>
{
this
.
_ensureClipboardGetsEditorSelection
(
e
);
this
.
asyncTriggerCut
.
schedule
();
this
.
_
asyncTriggerCut
.
schedule
();
}));
this
.
_register
(
dom
.
addDisposableListener
(
textArea
.
domNode
,
'
copy
'
,
(
e
:
ClipboardEvent
)
=>
{
...
...
@@ -246,9 +250,9 @@ export class TextAreaHandler extends Disposable {
if
(
ClipboardEventUtils
.
canUseTextData
(
e
))
{
this
.
executePaste
(
ClipboardEventUtils
.
getTextData
(
e
));
}
else
{
if
(
this
.
textArea
.
getSelectionStart
()
!==
this
.
textArea
.
getSelectionEnd
())
{
if
(
this
.
_textArea
.
getSelectionStart
()
!==
this
.
_
textArea
.
getSelectionEnd
())
{
// Clean up the textarea, to get a clean paste
this
.
setTextAreaState
(
'
paste
'
,
this
.
textAreaState
.
toEmpty
(),
false
);
this
.
setTextAreaState
(
'
paste
'
,
this
.
_
textAreaState
.
toEmpty
(),
false
);
}
this
.
_nextCommand
=
ReadFromTextArea
.
Paste
;
}
...
...
@@ -264,56 +268,34 @@ export class TextAreaHandler extends Disposable {
// --- begin event handlers
public
setStrategy
(
strategy
:
TextAreaStrategy
):
void
{
this
.
textAreaState
=
this
.
textAreaState
.
toStrategy
(
strategy
);
this
.
_textAreaState
=
this
.
_
textAreaState
.
toStrategy
(
strategy
);
}
public
setHasFocus
(
isFocused
:
boolean
):
void
{
if
(
this
.
hasFocus
===
isFocused
)
{
if
(
this
.
_
hasFocus
===
isFocused
)
{
// no change
return
;
}
this
.
hasFocus
=
isFocused
;
if
(
this
.
hasFocus
)
{
this
.
_
hasFocus
=
isFocused
;
if
(
this
.
_
hasFocus
)
{
this
.
_writePlaceholderAndSelectTextArea
(
'
focusgain
'
,
false
);
}
}
public
setCursorSelections
(
primary
:
Range
,
secondary
:
Range
[]):
void
{
this
.
selection
=
primary
;
this
.
selections
=
[
primary
].
concat
(
secondary
);
this
.
_selection
=
primary
;
this
.
_writePlaceholderAndSelectTextArea
(
'
selection changed
'
,
false
);
}
// --- end event handlers
private
setTextAreaState
(
reason
:
string
,
textAreaState
:
TextAreaState
,
forceFocus
:
boolean
):
void
{
if
(
!
this
.
hasFocus
)
{
if
(
!
this
.
_
hasFocus
)
{
textAreaState
=
textAreaState
.
resetSelection
();
}
textAreaState
.
applyToTextArea
(
reason
,
this
.
textArea
,
this
.
hasFocus
||
forceFocus
);
this
.
textAreaState
=
textAreaState
;
}
private
_onKeyDownHandler
(
e
:
IKeyboardEvent
):
void
{
if
(
this
.
textareaIsShownAtCursor
&&
e
.
equals
(
KeyCode
.
KEY_IN_COMPOSITION
))
{
// Stop propagation for keyDown events if the IME is processing key input
e
.
stopPropagation
();
}
if
(
e
.
equals
(
KeyCode
.
Escape
))
{
// Prevent default always for `Esc`, otherwise it will generate a keypress
// See https://msdn.microsoft.com/en-us/library/ie/ms536939(v=vs.85).aspx
e
.
preventDefault
();
}
this
.
_onKeyDown
.
fire
(
e
);
}
private
_onKeyPressHandler
(
e
:
IKeyboardEvent
):
void
{
if
(
!
this
.
hasFocus
)
{
// Sometimes, when doing Alt-Tab, in FF, a 'keypress' is sent before a 'focus'
return
;
}
textAreaState
.
applyToTextArea
(
reason
,
this
.
_textArea
,
this
.
_hasFocus
||
forceFocus
);
this
.
_textAreaState
=
textAreaState
;
}
// ------------- Operations that are always executed asynchronously
...
...
@@ -322,14 +304,8 @@ export class TextAreaHandler extends Disposable {
if
(
txt
===
''
)
{
return
;
}
let
pasteOnNewLine
=
false
;
if
(
browser
.
enableEmptySelectionClipboard
)
{
pasteOnNewLine
=
(
txt
===
this
.
lastCopiedValue
&&
this
.
lastCopiedValueIsFromEmptySelection
);
}
this
.
_onPaste
.
fire
({
text
:
txt
,
pasteOnNewLine
:
pasteOnNewLine
text
:
txt
});
}
...
...
@@ -338,13 +314,13 @@ export class TextAreaHandler extends Disposable {
}
private
_writePlaceholderAndSelectTextArea
(
reason
:
string
,
forceFocus
:
boolean
):
void
{
if
(
!
this
.
textareaIsShownAtCursor
)
{
if
(
!
this
.
_isDoingComposition
)
{
// Do not write to the textarea if it is visible.
if
(
browser
.
isIPad
)
{
// Do not place anything in the textarea for the iPad
this
.
setTextAreaState
(
reason
,
this
.
textAreaState
.
toEmpty
(),
forceFocus
);
this
.
setTextAreaState
(
reason
,
this
.
_
textAreaState
.
toEmpty
(),
forceFocus
);
}
else
{
this
.
setTextAreaState
(
reason
,
this
.
textAreaState
.
fromEditorSelection
(
this
.
model
,
this
.
selection
),
forceFocus
);
this
.
setTextAreaState
(
reason
,
this
.
_textAreaState
.
fromEditorSelection
(
this
.
_model
,
this
.
_
selection
),
forceFocus
);
}
}
}
...
...
@@ -352,28 +328,15 @@ export class TextAreaHandler extends Disposable {
// ------------- Clipboard operations
private
_ensureClipboardGetsEditorSelection
(
e
:
ClipboardEvent
):
void
{
let
whatToCopy
=
this
.
model
.
getPlainTextToCopy
(
this
.
selections
,
browser
.
enableEmptySelectionClipboard
);
let
whatToCopy
=
this
.
_host
.
getPlainTextToCopy
(
);
if
(
ClipboardEventUtils
.
canUseTextData
(
e
))
{
let
whatHTMLToCopy
:
string
=
null
;
if
(
!
browser
.
isEdgeOrIE
&&
(
whatToCopy
.
length
<
65536
||
CopyOptions
.
forceCopyWithSyntaxHighlighting
))
{
whatHTMLToCopy
=
this
.
model
.
getHTMLToCopy
(
this
.
selections
,
browser
.
enableEmptySelectionClipboard
);
whatHTMLToCopy
=
this
.
_host
.
getHTMLToCopy
(
);
}
ClipboardEventUtils
.
setTextData
(
e
,
whatToCopy
,
whatHTMLToCopy
);
}
else
{
this
.
setTextAreaState
(
'
copy or cut
'
,
this
.
textAreaState
.
fromText
(
whatToCopy
),
false
);
}
if
(
browser
.
enableEmptySelectionClipboard
)
{
if
(
browser
.
isFirefox
)
{
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
this
.
lastCopiedValue
=
whatToCopy
.
replace
(
/
\r\n
/g
,
'
\n
'
);
}
else
{
this
.
lastCopiedValue
=
whatToCopy
;
}
let
selections
=
this
.
selections
;
this
.
lastCopiedValueIsFromEmptySelection
=
(
selections
.
length
===
1
&&
selections
[
0
].
isEmpty
());
this
.
setTextAreaState
(
'
copy or cut
'
,
this
.
_textAreaState
.
fromText
(
whatToCopy
),
false
);
}
}
}
...
...
src/vs/editor/browser/controller/textAreaState.ts
浏览文件 @
c3ce6210
...
...
@@ -7,7 +7,6 @@
import
{
commonPrefixLength
,
commonSuffixLength
}
from
'
vs/base/common/strings
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
EndOfLinePreference
}
from
'
vs/editor/common/editorCommon
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
Constants
}
from
'
vs/editor/common/core/uint
'
;
export
interface
ITextAreaWrapper
{
...
...
@@ -21,17 +20,9 @@ export interface ITextAreaWrapper {
}
export
interface
ISimpleModel
{
getLineCount
():
number
;
getLineMaxColumn
(
lineNumber
:
number
):
number
;
getEOL
():
string
;
getValueInRange
(
range
:
Range
,
eol
:
EndOfLinePreference
):
string
;
getModelLineContent
(
lineNumber
:
number
):
string
;
getLineCount
():
number
;
getPlainTextToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
;
getHTMLToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
;
coordinatesConverter
:
{
convertViewPositionToModelPosition
(
viewPosition
:
Position
):
Position
;
};
}
export
interface
ITypeData
{
...
...
src/vs/editor/common/viewModel/viewModel.ts
浏览文件 @
c3ce6210
...
...
@@ -112,10 +112,8 @@ export interface IViewModel {
getLineMaxColumn
(
lineNumber
:
number
):
number
;
getLineRenderLineNumber
(
lineNumber
:
number
):
string
;
getAllOverviewRulerDecorations
():
ViewModelDecoration
[];
getEOL
():
string
;
getValueInRange
(
range
:
Range
,
eol
:
EndOfLinePreference
):
string
;
getModelLineContent
(
modelLineNumber
:
number
):
string
;
getModelLineMaxColumn
(
modelLineNumber
:
number
):
number
;
validateModelPosition
(
modelPosition
:
IPosition
):
Position
;
...
...
src/vs/editor/common/viewModel/viewModelImpl.ts
浏览文件 @
c3ce6210
...
...
@@ -539,19 +539,11 @@ export class ViewModel extends Disposable implements IViewModel {
return
this
.
decorations
.
getAllOverviewRulerDecorations
();
}
public
getEOL
():
string
{
return
this
.
model
.
getEOL
();
}
public
getValueInRange
(
range
:
Range
,
eol
:
editorCommon
.
EndOfLinePreference
):
string
{
var
modelRange
=
this
.
coordinatesConverter
.
convertViewRangeToModelRange
(
range
);
return
this
.
model
.
getValueInRange
(
modelRange
,
eol
);
}
public
getModelLineContent
(
modelLineNumber
:
number
):
string
{
return
this
.
model
.
getLineContent
(
modelLineNumber
);
}
public
getModelLineMaxColumn
(
modelLineNumber
:
number
):
number
{
return
this
.
model
.
getLineMaxColumn
(
modelLineNumber
);
}
...
...
@@ -561,7 +553,7 @@ export class ViewModel extends Disposable implements IViewModel {
}
public
getPlainTextToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
{
let
newLineCharacter
=
this
.
getEOL
();
let
newLineCharacter
=
this
.
model
.
getEOL
();
if
(
ranges
.
length
===
1
)
{
let
range
:
Range
=
ranges
[
0
];
...
...
src/vs/editor/test/browser/controller/imeTester.ts
浏览文件 @
c3ce6210
...
...
@@ -4,11 +4,10 @@
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
TextAreaHandler
}
from
'
vs/editor/browser/controller/textAreaHandler
'
;
import
{
TextAreaHandler
,
ITextAreaHandlerHost
}
from
'
vs/editor/browser/controller/textAreaHandler
'
;
import
{
TextAreaStrategy
,
ISimpleModel
}
from
'
vs/editor/browser/controller/textAreaState
'
;
import
{
Range
,
IRange
}
from
'
vs/editor/common/core/range
'
;
import
*
as
editorCommon
from
'
vs/editor/common/editorCommon
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
createFastDomNode
}
from
'
vs/base/browser/fastDomNode
'
;
// To run this test, open imeTester.html
...
...
@@ -18,18 +17,12 @@ class SingleLineTestModel implements ISimpleModel {
private
_line
:
string
;
private
_eol
:
string
;
public
coordinatesConverter
=
{
convertViewPositionToModelPosition
:
(
viewPosition
:
Position
):
Position
=>
{
return
viewPosition
;
}
};
constructor
(
line
:
string
)
{
this
.
_line
=
line
;
this
.
_eol
=
'
\n
'
;
}
setText
(
text
:
string
)
{
_
setText
(
text
:
string
)
{
this
.
_line
=
text
;
}
...
...
@@ -37,10 +30,6 @@ class SingleLineTestModel implements ISimpleModel {
return
this
.
_line
.
length
+
1
;
}
getEOL
():
string
{
return
this
.
_eol
;
}
getValueInRange
(
range
:
IRange
,
eol
:
editorCommon
.
EndOfLinePreference
):
string
{
return
this
.
_line
.
substring
(
range
.
startColumn
-
1
,
range
.
endColumn
-
1
);
}
...
...
@@ -52,14 +41,6 @@ class SingleLineTestModel implements ISimpleModel {
getLineCount
():
number
{
return
1
;
}
public
getPlainTextToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
{
return
''
;
}
public
getHTMLToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
{
return
''
;
}
}
class
TestView
{
...
...
@@ -101,7 +82,12 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr:
let
model
=
new
SingleLineTestModel
(
'
some text
'
);
let
handler
=
new
TextAreaHandler
(
strategy
,
createFastDomNode
(
input
),
model
);
const
textAreaHandlerHost
:
ITextAreaHandlerHost
=
{
getPlainTextToCopy
:
():
string
=>
''
,
getHTMLToCopy
:
():
string
=>
''
};
let
handler
=
new
TextAreaHandler
(
textAreaHandlerHost
,
strategy
,
createFastDomNode
(
input
),
model
);
input
.
onfocus
=
()
=>
{
handler
.
setHasFocus
(
true
);
...
...
@@ -135,7 +121,7 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr:
};
let
updateModelAndPosition
=
(
text
:
string
,
off
:
number
,
len
:
number
)
=>
{
model
.
setText
(
text
);
model
.
_
setText
(
text
);
updatePosition
(
off
,
len
);
view
.
paint
(
output
);
...
...
src/vs/editor/test/browser/controller/textAreaState.test.ts
浏览文件 @
c3ce6210
...
...
@@ -6,7 +6,6 @@
import
*
as
assert
from
'
assert
'
;
import
{
IENarratorTextAreaState
,
ISimpleModel
,
TextAreaState
,
ITextAreaWrapper
}
from
'
vs/editor/browser/controller/textAreaState
'
;
import
{
Position
}
from
'
vs/editor/common/core/position
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
EndOfLinePreference
}
from
'
vs/editor/common/editorCommon
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
...
...
@@ -466,12 +465,6 @@ class SimpleModel implements ISimpleModel {
private
_lines
:
string
[];
private
_eol
:
string
;
public
coordinatesConverter
=
{
convertViewPositionToModelPosition
:
(
viewPosition
:
Position
):
Position
=>
{
return
viewPosition
;
}
};
constructor
(
lines
:
string
[],
eol
:
string
)
{
this
.
_lines
=
lines
;
this
.
_eol
=
eol
;
...
...
@@ -493,10 +486,6 @@ class SimpleModel implements ISimpleModel {
throw
new
Error
(
'
Unknown EOL preference
'
);
}
public
getEOL
():
string
{
return
this
.
_eol
;
}
public
getValueInRange
(
range
:
Range
,
eol
:
EndOfLinePreference
):
string
{
if
(
Range
.
isEmpty
(
range
))
{
return
''
;
...
...
@@ -520,19 +509,7 @@ class SimpleModel implements ISimpleModel {
return
resultLines
.
join
(
lineEnding
);
}
public
getModelLineContent
(
lineNumber
:
number
):
string
{
return
this
.
_lines
[
lineNumber
-
1
];
}
public
getLineCount
():
number
{
return
this
.
_lines
.
length
;
}
public
getPlainTextToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
{
return
''
;
}
public
getHTMLToCopy
(
ranges
:
Range
[],
enableEmptySelectionClipboard
:
boolean
):
string
{
return
''
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录