Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
c948b410
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,发现更多精彩内容 >>
未验证
提交
c948b410
编写于
10月 17, 2019
作者:
A
Alexandru Dima
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fixes #43012: Write vscode specific metadata to clipboard
上级
47c84f3f
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
124 addition
and
90 deletion
+124
-90
src/vs/editor/browser/controller/textAreaHandler.ts
src/vs/editor/browser/controller/textAreaHandler.ts
+19
-68
src/vs/editor/browser/controller/textAreaInput.ts
src/vs/editor/browser/controller/textAreaInput.ts
+97
-20
src/vs/editor/test/browser/controller/imeTester.ts
src/vs/editor/test/browser/controller/imeTester.ts
+8
-2
未找到文件。
src/vs/editor/browser/controller/textAreaHandler.ts
浏览文件 @
c948b410
...
...
@@ -11,7 +11,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
*
as
strings
from
'
vs/base/common/strings
'
;
import
{
Configuration
}
from
'
vs/editor/browser/config/configuration
'
;
import
{
CopyOptions
,
ICompositionData
,
IPasteData
,
ITextAreaInputHost
,
TextAreaInput
}
from
'
vs/editor/browser/controller/textAreaInput
'
;
import
{
CopyOptions
,
ICompositionData
,
IPasteData
,
ITextAreaInputHost
,
TextAreaInput
,
ClipboardDataToCopy
}
from
'
vs/editor/browser/controller/textAreaInput
'
;
import
{
ISimpleModel
,
ITypeData
,
PagedScreenReaderStrategy
,
TextAreaState
}
from
'
vs/editor/browser/controller/textAreaState
'
;
import
{
ViewController
}
from
'
vs/editor/browser/view/viewController
'
;
import
{
PartFingerprint
,
PartFingerprints
,
ViewPart
}
from
'
vs/editor/browser/view/viewPart
'
;
...
...
@@ -54,40 +54,6 @@ class VisibleTextAreaData {
const
canUseZeroSizeTextarea
=
(
browser
.
isEdgeOrIE
||
browser
.
isFirefox
);
interface
LocalClipboardMetadata
{
lastCopiedValue
:
string
;
isFromEmptySelection
:
boolean
;
multicursorText
:
string
[]
|
null
;
}
/**
* Every time we write to the clipboard, we record a bit of extra metadata here.
* Every time we read from the cipboard, if the text matches our last written text,
* we can fetch the previous metadata.
*/
class
LocalClipboardMetadataManager
{
public
static
readonly
INSTANCE
=
new
LocalClipboardMetadataManager
();
private
_lastState
:
LocalClipboardMetadata
|
null
;
constructor
()
{
this
.
_lastState
=
null
;
}
public
set
(
state
:
LocalClipboardMetadata
|
null
):
void
{
this
.
_lastState
=
state
;
}
public
get
(
pastedText
:
string
):
LocalClipboardMetadata
|
null
{
if
(
this
.
_lastState
&&
this
.
_lastState
.
lastCopiedValue
===
pastedText
)
{
// match!
return
this
.
_lastState
;
}
this
.
_lastState
=
null
;
return
null
;
}
}
export
class
TextAreaHandler
extends
ViewPart
{
private
readonly
_viewController
:
ViewController
;
...
...
@@ -172,39 +138,26 @@ export class TextAreaHandler extends ViewPart {
};
const
textAreaInputHost
:
ITextAreaInputHost
=
{
get
PlainTextToCopy
:
():
string
=>
{
const
raw
Wha
tToCopy
=
this
.
_context
.
model
.
getPlainTextToCopy
(
this
.
_selections
,
this
.
_emptySelectionClipboard
,
platform
.
isWindows
);
get
DataToCopy
:
(
generateHTML
:
boolean
):
ClipboardDataToCopy
=>
{
const
raw
Tex
tToCopy
=
this
.
_context
.
model
.
getPlainTextToCopy
(
this
.
_selections
,
this
.
_emptySelectionClipboard
,
platform
.
isWindows
);
const
newLineCharacter
=
this
.
_context
.
model
.
getEOL
();
const
isFromEmptySelection
=
(
this
.
_emptySelectionClipboard
&&
this
.
_selections
.
length
===
1
&&
this
.
_selections
[
0
].
isEmpty
());
const
multicursorText
=
(
Array
.
isArray
(
rawWhatToCopy
)
?
rawWhatToCopy
:
null
);
const
whatToCopy
=
(
Array
.
isArray
(
rawWhatToCopy
)
?
rawWhatToCopy
.
join
(
newLineCharacter
)
:
rawWhatToCopy
);
let
metadata
:
LocalClipboardMetadata
|
null
=
null
;
if
(
isFromEmptySelection
||
multicursorText
)
{
// Only store the non-default metadata
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
const
lastCopiedValue
=
(
browser
.
isFirefox
?
whatToCopy
.
replace
(
/
\r\n
/g
,
'
\n
'
)
:
whatToCopy
);
metadata
=
{
lastCopiedValue
:
lastCopiedValue
,
isFromEmptySelection
:
(
this
.
_emptySelectionClipboard
&&
this
.
_selections
.
length
===
1
&&
this
.
_selections
[
0
].
isEmpty
()),
multicursorText
:
multicursorText
};
}
const
multicursorText
=
(
Array
.
isArray
(
rawTextToCopy
)
?
rawTextToCopy
:
null
);
const
text
=
(
Array
.
isArray
(
rawTextToCopy
)
?
rawTextToCopy
.
join
(
newLineCharacter
)
:
rawTextToCopy
);
LocalClipboardMetadataManager
.
INSTANCE
.
set
(
metadata
);
return
whatToCopy
;
},
getHTMLToCopy
:
():
string
|
null
=>
{
if
(
!
this
.
_copyWithSyntaxHighlighting
&&
!
CopyOptions
.
forceCopyWithSyntaxHighlighting
)
{
return
null
;
let
html
:
string
|
null
|
undefined
=
undefined
;
if
(
generateHTML
)
{
if
(
CopyOptions
.
forceCopyWithSyntaxHighlighting
||
(
this
.
_copyWithSyntaxHighlighting
&&
text
.
length
<
65536
))
{
html
=
this
.
_context
.
model
.
getHTMLToCopy
(
this
.
_selections
,
this
.
_emptySelectionClipboard
);
}
}
return
this
.
_context
.
model
.
getHTMLToCopy
(
this
.
_selections
,
this
.
_emptySelectionClipboard
);
return
{
isFromEmptySelection
,
multicursorText
,
text
,
html
};
},
getScreenReaderContent
:
(
currentState
:
TextAreaState
):
TextAreaState
=>
{
...
...
@@ -255,13 +208,11 @@ export class TextAreaHandler extends ViewPart {
}));
this
.
_register
(
this
.
_textAreaInput
.
onPaste
((
e
:
IPasteData
)
=>
{
const
metadata
=
LocalClipboardMetadataManager
.
INSTANCE
.
get
(
e
.
text
);
let
pasteOnNewLine
=
false
;
let
multicursorText
:
string
[]
|
null
=
null
;
if
(
metadata
)
{
pasteOnNewLine
=
(
this
.
_emptySelectionClipboard
&&
metadata
.
isFromEmptySelection
);
multicursorText
=
metadata
.
multicursorText
;
if
(
e
.
metadata
)
{
pasteOnNewLine
=
(
this
.
_emptySelectionClipboard
&&
!!
e
.
metadata
.
isFromEmptySelection
);
multicursorText
=
(
typeof
e
.
metadata
.
multicursorText
!==
'
undefined
'
?
e
.
metadata
.
multicursorText
:
null
)
;
}
this
.
_viewController
.
paste
(
'
keyboard
'
,
e
.
text
,
pasteOnNewLine
,
multicursorText
);
}));
...
...
src/vs/editor/browser/controller/textAreaInput.ts
浏览文件 @
c948b410
...
...
@@ -32,11 +32,24 @@ const enum ReadFromTextArea {
export
interface
IPasteData
{
text
:
string
;
metadata
:
ClipboardStoredMetadata
|
null
;
}
export
interface
ClipboardDataToCopy
{
isFromEmptySelection
:
boolean
;
multicursorText
:
string
[]
|
null
|
undefined
;
text
:
string
;
html
:
string
|
null
|
undefined
;
}
export
interface
ClipboardStoredMetadata
{
version
:
1
;
isFromEmptySelection
:
boolean
|
undefined
;
multicursorText
:
string
[]
|
null
|
undefined
;
}
export
interface
ITextAreaInputHost
{
getPlainTextToCopy
():
string
;
getHTMLToCopy
():
string
|
null
;
getDataToCopy
(
html
:
boolean
):
ClipboardDataToCopy
;
getScreenReaderContent
(
currentState
:
TextAreaState
):
TextAreaState
;
deduceModelPosition
(
viewAnchorPosition
:
Position
,
deltaOffset
:
number
,
lineFeedCnt
:
number
):
Position
;
}
...
...
@@ -59,6 +72,39 @@ interface CompositionEvent extends UIEvent {
readonly
locale
:
string
;
}
interface
InMemoryClipboardMetadata
{
lastCopiedValue
:
string
;
data
:
ClipboardStoredMetadata
;
}
/**
* Every time we write to the clipboard, we record a bit of extra metadata here.
* Every time we read from the cipboard, if the text matches our last written text,
* we can fetch the previous metadata.
*/
class
InMemoryClipboardMetadataManager
{
public
static
readonly
INSTANCE
=
new
InMemoryClipboardMetadataManager
();
private
_lastState
:
InMemoryClipboardMetadata
|
null
;
constructor
()
{
this
.
_lastState
=
null
;
}
public
set
(
lastCopiedValue
:
string
,
data
:
ClipboardStoredMetadata
):
void
{
this
.
_lastState
=
{
lastCopiedValue
,
data
};
}
public
get
(
pastedText
:
string
):
ClipboardStoredMetadata
|
null
{
if
(
this
.
_lastState
&&
this
.
_lastState
.
lastCopiedValue
===
pastedText
)
{
// match!
return
this
.
_lastState
.
data
;
}
this
.
_lastState
=
null
;
return
null
;
}
}
/**
* Writes screen reader content to the textarea and is able to analyze its input events to generate:
* - onCut
...
...
@@ -279,9 +325,7 @@ export class TextAreaInput extends Disposable {
}
}
else
{
if
(
typeInput
.
text
!==
''
)
{
this
.
_onPaste
.
fire
({
text
:
typeInput
.
text
});
this
.
_firePaste
(
typeInput
.
text
,
null
);
}
this
.
_nextCommand
=
ReadFromTextArea
.
Type
;
}
...
...
@@ -314,11 +358,9 @@ export class TextAreaInput extends Disposable {
this
.
_textArea
.
setIgnoreSelectionChangeTime
(
'
received paste event
'
);
if
(
ClipboardEventUtils
.
canUseTextData
(
e
))
{
const
pastePlainText
=
ClipboardEventUtils
.
getTextData
(
e
);
const
[
pastePlainText
,
metadata
]
=
ClipboardEventUtils
.
getTextData
(
e
);
if
(
pastePlainText
!==
''
)
{
this
.
_onPaste
.
fire
({
text
:
pastePlainText
});
this
.
_firePaste
(
pastePlainText
,
metadata
);
}
}
else
{
if
(
this
.
_textArea
.
getSelectionStart
()
!==
this
.
_textArea
.
getSelectionEnd
())
{
...
...
@@ -491,19 +533,38 @@ export class TextAreaInput extends Disposable {
}
private
_ensureClipboardGetsEditorSelection
(
e
:
ClipboardEvent
):
void
{
const
copyPlainText
=
this
.
_host
.
getPlainTextToCopy
();
const
dataToCopy
=
this
.
_host
.
getDataToCopy
(
ClipboardEventUtils
.
canUseTextData
(
e
)
&&
browser
.
hasClipboardSupport
());
const
storedMetadata
:
ClipboardStoredMetadata
=
{
version
:
1
,
isFromEmptySelection
:
dataToCopy
.
isFromEmptySelection
,
multicursorText
:
dataToCopy
.
multicursorText
};
InMemoryClipboardMetadataManager
.
INSTANCE
.
set
(
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
(
browser
.
isFirefox
?
dataToCopy
.
text
.
replace
(
/
\r\n
/g
,
'
\n
'
)
:
dataToCopy
.
text
),
storedMetadata
);
if
(
!
ClipboardEventUtils
.
canUseTextData
(
e
))
{
// Looks like an old browser. The strategy is to place the text
// we'd like to be copied to the clipboard in the textarea and select it.
this
.
_setAndWriteTextAreaState
(
'
copy or cut
'
,
TextAreaState
.
selectedText
(
copyPlainT
ext
));
this
.
_setAndWriteTextAreaState
(
'
copy or cut
'
,
TextAreaState
.
selectedText
(
dataToCopy
.
t
ext
));
return
;
}
let
copyHTML
:
string
|
null
=
null
;
if
(
browser
.
hasClipboardSupport
()
&&
(
copyPlainText
.
length
<
65536
||
CopyOptions
.
forceCopyWithSyntaxHighlighting
))
{
copyHTML
=
this
.
_host
.
getHTMLToCopy
();
ClipboardEventUtils
.
setTextData
(
e
,
dataToCopy
.
text
,
dataToCopy
.
html
,
storedMetadata
);
}
private
_firePaste
(
text
:
string
,
metadata
:
ClipboardStoredMetadata
|
null
):
void
{
if
(
!
metadata
)
{
// try the in-memory store
metadata
=
InMemoryClipboardMetadataManager
.
INSTANCE
.
get
(
text
);
}
ClipboardEventUtils
.
setTextData
(
e
,
copyPlainText
,
copyHTML
);
this
.
_onPaste
.
fire
({
text
:
text
,
metadata
:
metadata
});
}
}
...
...
@@ -519,10 +580,25 @@ class ClipboardEventUtils {
return
false
;
}
public
static
getTextData
(
e
:
ClipboardEvent
):
string
{
public
static
getTextData
(
e
:
ClipboardEvent
):
[
string
,
ClipboardStoredMetadata
|
null
]
{
if
(
e
.
clipboardData
)
{
e
.
preventDefault
();
return
e
.
clipboardData
.
getData
(
'
text/plain
'
);
const
text
=
e
.
clipboardData
.
getData
(
'
text/plain
'
);
let
metadata
:
ClipboardStoredMetadata
|
null
=
null
;
const
rawmetadata
=
e
.
clipboardData
.
getData
(
'
vscode-editor-data
'
);
if
(
typeof
rawmetadata
===
'
string
'
)
{
try
{
metadata
=
<
ClipboardStoredMetadata
>
JSON
.
parse
(
rawmetadata
);
if
(
metadata
.
version
!==
1
)
{
metadata
=
null
;
}
}
catch
(
err
)
{
// no problem!
}
}
return
[
text
,
metadata
];
}
if
((
<
any
>
window
).
clipboardData
)
{
...
...
@@ -533,12 +609,13 @@ class ClipboardEventUtils {
throw
new
Error
(
'
ClipboardEventUtils.getTextData: Cannot use text data!
'
);
}
public
static
setTextData
(
e
:
ClipboardEvent
,
text
:
string
,
richText
:
string
|
null
):
void
{
public
static
setTextData
(
e
:
ClipboardEvent
,
text
:
string
,
html
:
string
|
null
|
undefined
,
metadata
:
ClipboardStoredMetadata
):
void
{
if
(
e
.
clipboardData
)
{
e
.
clipboardData
.
setData
(
'
text/plain
'
,
text
);
if
(
richText
!==
null
)
{
e
.
clipboardData
.
setData
(
'
text/html
'
,
richText
);
if
(
typeof
html
===
'
string
'
)
{
e
.
clipboardData
.
setData
(
'
text/html
'
,
html
);
}
e
.
clipboardData
.
setData
(
'
vscode-editor-data
'
,
JSON
.
stringify
(
metadata
));
e
.
preventDefault
();
return
;
}
...
...
src/vs/editor/test/browser/controller/imeTester.ts
浏览文件 @
c948b410
...
...
@@ -86,8 +86,14 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string
let
model
=
new
SingleLineTestModel
(
'
some text
'
);
const
textAreaInputHost
:
ITextAreaInputHost
=
{
getPlainTextToCopy
:
():
string
=>
''
,
getHTMLToCopy
:
():
string
=>
''
,
getDataToCopy
:
()
=>
{
return
{
isFromEmptySelection
:
false
,
multicursorText
:
null
,
text
:
''
,
html
:
undefined
};
},
getScreenReaderContent
:
(
currentState
:
TextAreaState
):
TextAreaState
=>
{
if
(
browser
.
isIPad
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录