Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
6daf4d36
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,发现更多精彩内容 >>
提交
6daf4d36
编写于
5月 23, 2017
作者:
C
Christof Marti
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'better-merge-extension'
上级
59fc592f
7966de7a
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
2085 addition
and
100 deletion
+2085
-100
build/npm/postinstall.js
build/npm/postinstall.js
+2
-1
extensions/git/src/main.ts
extensions/git/src/main.ts
+0
-3
extensions/git/src/merge.ts
extensions/git/src/merge.ts
+0
-96
extensions/merge-conflict/package.json
extensions/merge-conflict/package.json
+127
-0
extensions/merge-conflict/package.nls.json
extensions/merge-conflict/package.nls.json
+15
-0
extensions/merge-conflict/src/codelensProvider.ts
extensions/merge-conflict/src/codelensProvider.ts
+102
-0
extensions/merge-conflict/src/commandHandler.ts
extensions/merge-conflict/src/commandHandler.ts
+278
-0
extensions/merge-conflict/src/contentProvider.ts
extensions/merge-conflict/src/contentProvider.ts
+38
-0
extensions/merge-conflict/src/delayer.ts
extensions/merge-conflict/src/delayer.ts
+80
-0
extensions/merge-conflict/src/documentMergeConflict.ts
extensions/merge-conflict/src/documentMergeConflict.ts
+76
-0
extensions/merge-conflict/src/documentTracker.ts
extensions/merge-conflict/src/documentTracker.ts
+138
-0
extensions/merge-conflict/src/extension.ts
extensions/merge-conflict/src/extension.ts
+18
-0
extensions/merge-conflict/src/interfaces.ts
extensions/merge-conflict/src/interfaces.ts
+47
-0
extensions/merge-conflict/src/mergeConflictParser.ts
extensions/merge-conflict/src/mergeConflictParser.ts
+141
-0
extensions/merge-conflict/src/mergeDecorator.ts
extensions/merge-conflict/src/mergeDecorator.ts
+211
-0
extensions/merge-conflict/src/package.json
extensions/merge-conflict/src/package.json
+722
-0
extensions/merge-conflict/src/services.ts
extensions/merge-conflict/src/services.ts
+67
-0
extensions/merge-conflict/src/typings/refs.d.ts
extensions/merge-conflict/src/typings/refs.d.ts
+8
-0
extensions/merge-conflict/tsconfig.json
extensions/merge-conflict/tsconfig.json
+15
-0
未找到文件。
build/npm/postinstall.js
浏览文件 @
6daf4d36
...
...
@@ -34,7 +34,8 @@ const extensions = [
'
git
'
,
'
gulp
'
,
'
grunt
'
,
'
jake
'
'
jake
'
,
'
merge-conflict
'
];
extensions
.
forEach
(
extension
=>
npmInstall
(
`extensions/
${
extension
}
`
));
...
...
extensions/git/src/main.ts
浏览文件 @
6daf4d36
...
...
@@ -13,7 +13,6 @@ import { CommandCenter } from './commands';
import
{
StatusBarCommands
}
from
'
./statusbar
'
;
import
{
GitContentProvider
}
from
'
./contentProvider
'
;
import
{
AutoFetcher
}
from
'
./autofetch
'
;
import
{
MergeDecorator
}
from
'
./merge
'
;
import
{
Askpass
}
from
'
./askpass
'
;
import
{
toDisposable
}
from
'
./util
'
;
import
TelemetryReporter
from
'
vscode-extension-telemetry
'
;
...
...
@@ -58,14 +57,12 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
const
provider
=
new
GitSCMProvider
(
model
,
commandCenter
,
statusBarCommands
);
const
contentProvider
=
new
GitContentProvider
(
model
);
const
autoFetcher
=
new
AutoFetcher
(
model
);
const
mergeDecorator
=
new
MergeDecorator
(
model
);
disposables
.
push
(
commandCenter
,
provider
,
contentProvider
,
autoFetcher
,
mergeDecorator
,
model
);
...
...
extensions/git/src/merge.ts
已删除
100644 → 0
浏览文件 @
59fc592f
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
{
window
,
workspace
,
Disposable
,
TextEditor
,
TextDocument
,
Range
}
from
'
vscode
'
;
import
{
Model
,
Status
}
from
'
./model
'
;
import
{
filterEvent
}
from
'
./util
'
;
import
{
debounce
}
from
'
./decorators
'
;
import
{
iterate
}
from
'
./iterators
'
;
function
*
lines
(
document
:
TextDocument
):
IterableIterator
<
string
>
{
for
(
let
i
=
0
;
i
<
document
.
lineCount
;
i
++
)
{
yield
document
.
lineAt
(
i
).
text
;
}
}
const
pattern
=
/^<<<<<<<|^=======|^>>>>>>>/
;
function
decorate
(
document
:
TextDocument
):
Range
[]
{
return
iterate
(
lines
(
document
))
.
map
((
line
,
i
)
=>
pattern
.
test
(
line
)
?
i
:
null
)
.
filter
(
i
=>
i
!==
null
)
.
map
((
i
:
number
)
=>
new
Range
(
i
,
1
,
i
,
1
))
.
toArray
();
}
class
TextEditorMergeDecorator
{
private
static
DecorationType
=
window
.
createTextEditorDecorationType
({
backgroundColor
:
'
rgba(255, 139, 0, 0.3)
'
,
isWholeLine
:
true
,
dark
:
{
backgroundColor
:
'
rgba(235, 59, 0, 0.3)
'
}
});
private
uri
:
string
;
private
disposables
:
Disposable
[]
=
[];
constructor
(
private
model
:
Model
,
private
editor
:
TextEditor
)
{
this
.
uri
=
this
.
editor
.
document
.
uri
.
toString
();
const
onDidChange
=
filterEvent
(
workspace
.
onDidChangeTextDocument
,
e
=>
e
.
document
&&
e
.
document
.
uri
.
toString
()
===
this
.
uri
);
onDidChange
(
this
.
redecorate
,
this
,
this
.
disposables
);
model
.
onDidChange
(
this
.
redecorate
,
this
,
this
.
disposables
);
this
.
redecorate
();
}
@
debounce
(
300
)
private
redecorate
():
void
{
let
decorations
:
Range
[]
=
[];
if
(
window
.
visibleTextEditors
.
every
(
e
=>
e
!==
this
.
editor
))
{
this
.
dispose
();
return
;
}
if
(
this
.
model
.
mergeGroup
.
resources
.
some
(
r
=>
r
.
type
===
Status
.
BOTH_MODIFIED
&&
r
.
resourceUri
.
toString
()
===
this
.
uri
))
{
decorations
=
decorate
(
this
.
editor
.
document
);
}
this
.
editor
.
setDecorations
(
TextEditorMergeDecorator
.
DecorationType
,
decorations
);
}
dispose
():
void
{
this
.
disposables
.
forEach
(
d
=>
d
.
dispose
());
}
}
export
class
MergeDecorator
{
private
textEditorDecorators
:
TextEditorMergeDecorator
[]
=
[];
private
disposables
:
Disposable
[]
=
[];
constructor
(
private
model
:
Model
)
{
window
.
onDidChangeVisibleTextEditors
(
this
.
onDidChangeVisibleTextEditors
,
this
,
this
.
disposables
);
this
.
onDidChangeVisibleTextEditors
(
window
.
visibleTextEditors
);
}
private
onDidChangeVisibleTextEditors
(
editors
:
TextEditor
[]):
void
{
this
.
textEditorDecorators
.
forEach
(
d
=>
d
.
dispose
());
this
.
textEditorDecorators
=
editors
.
map
(
e
=>
new
TextEditorMergeDecorator
(
this
.
model
,
e
));
}
dispose
():
void
{
this
.
textEditorDecorators
.
forEach
(
d
=>
d
.
dispose
());
this
.
disposables
.
forEach
(
d
=>
d
.
dispose
());
}
}
extensions/merge-conflict/package.json
0 → 100644
浏览文件 @
6daf4d36
{
"name"
:
"merge-conflict"
,
"publisher"
:
"vscode"
,
"displayName"
:
"merge-conflict"
,
"description"
:
"Merge Conflict"
,
"version"
:
"0.7.0"
,
"aiKey"
:
"AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217"
,
"engines"
:
{
"vscode"
:
"^1.5.0"
},
"categories"
:
[
"Other"
],
"activationEvents"
:
[
"*"
],
"main"
:
"./out/extension"
,
"scripts"
:
{
"compile"
:
"gulp compile-extension:merge-conflict"
,
"watch"
:
"gulp watch-extension:merge-conflict"
},
"contributes"
:
{
"commands"
:
[
{
"category"
:
"%command.category%"
,
"title"
:
"%command.accept.all-incoming%"
,
"command"
:
"merge-conflict.accept.all-incoming"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.accept.all-both%"
,
"command"
:
"merge-conflict.accept.all-both"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.accept.current%"
,
"command"
:
"merge-conflict.accept.current"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.accept.incoming%"
,
"command"
:
"merge-conflict.accept.incoming"
},
{
"category"
:
"%command.category%"
,
"title"
:
"Accept selection"
,
"command"
:
"merge-conflict.accept.selection"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.accept.both%"
,
"command"
:
"merge-conflict.accept.both"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.next%"
,
"command"
:
"merge-conflict.next"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.previous%"
,
"command"
:
"merge-conflict.previous"
},
{
"category"
:
"%command.category%"
,
"title"
:
"%command.compare%"
,
"command"
:
"merge-conflict.compare"
}
],
"keybindings"
:
[
{
"command"
:
"merge-conflict.next"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m down"
},
{
"command"
:
"merge-conflict.previous"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m up"
},
{
"command"
:
"merge-conflict.accept.selection"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m enter"
},
{
"command"
:
"merge-conflict.accept.current"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m 1"
},
{
"command"
:
"merge-conflict.accept.incoming"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m 2"
},
{
"command"
:
"merge-conflict.accept.both"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m 3"
}
],
"configuration"
:
{
"title"
:
"%config.title%"
,
"properties"
:
{
"merge-conflict.codeLens.enabled"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.codeLensEnabled%"
,
"default"
:
true
},
"merge-conflict.decorators.enabled"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.decoratorsEnabled%"
,
"default"
:
true
}
}
}
},
"dependencies"
:
{
"vscode-extension-telemetry"
:
"^0.0.7"
,
"vscode-nls"
:
"^2.0.2"
},
"devDependencies"
:
{
"@types/mocha"
:
"^2.2.41"
,
"@types/node"
:
"^7.0.4"
,
"mocha"
:
"^3.2.0"
}
}
\ No newline at end of file
extensions/merge-conflict/package.nls.json
0 → 100644
浏览文件 @
6daf4d36
{
"command.category"
:
"Merge Conflict"
,
"command.accept.all-incoming"
:
"Accept all incoming"
,
"command.accept.all-both"
:
"Accept all both"
,
"command.accept.current"
:
"Accept current"
,
"command.accept.incoming"
:
"Accept incoming"
,
"command.accept.selection"
:
"Accept selection"
,
"command.accept.both"
:
"Accept Both"
,
"command.next"
:
"Next conflict"
,
"command.previous"
:
"Previous conflict"
,
"command.compare"
:
"Compare current conflict"
,
"config.title"
:
"Merge Conflict"
,
"config.codeLensEnabled"
:
"Enable/disable merge conflict block CodeLens within editor"
,
"config.decoratorsEnabled"
:
"Enable/disable merge conflict decorators within editor"
}
\ No newline at end of file
extensions/merge-conflict/src/codelensProvider.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
import
{
loadMessageBundle
}
from
'
vscode-nls
'
;
const
localize
=
loadMessageBundle
();
export
default
class
MergeConflictCodeLensProvider
implements
vscode
.
CodeLensProvider
,
vscode
.
Disposable
{
private
codeLensRegistrationHandle
:
vscode
.
Disposable
|
null
;
private
config
:
interfaces
.
IExtensionConfiguration
;
private
tracker
:
interfaces
.
IDocumentMergeConflictTracker
;
constructor
(
private
context
:
vscode
.
ExtensionContext
,
trackerService
:
interfaces
.
IDocumentMergeConflictTrackerService
)
{
this
.
tracker
=
trackerService
.
createTracker
(
'
codelens
'
);
}
begin
(
config
:
interfaces
.
IExtensionConfiguration
)
{
this
.
config
=
config
;
if
(
this
.
config
.
enableCodeLens
)
{
this
.
registerCodeLensProvider
();
}
}
configurationUpdated
(
updatedConfig
:
interfaces
.
IExtensionConfiguration
)
{
if
(
updatedConfig
.
enableCodeLens
===
false
&&
this
.
codeLensRegistrationHandle
)
{
this
.
codeLensRegistrationHandle
.
dispose
();
this
.
codeLensRegistrationHandle
=
null
;
}
else
if
(
updatedConfig
.
enableCodeLens
===
true
&&
!
this
.
codeLensRegistrationHandle
)
{
this
.
registerCodeLensProvider
();
}
this
.
config
=
updatedConfig
;
}
dispose
()
{
if
(
this
.
codeLensRegistrationHandle
)
{
this
.
codeLensRegistrationHandle
.
dispose
();
this
.
codeLensRegistrationHandle
=
null
;
}
}
async
provideCodeLenses
(
document
:
vscode
.
TextDocument
,
token
:
vscode
.
CancellationToken
):
Promise
<
vscode
.
CodeLens
[]
|
null
>
{
if
(
!
this
.
config
||
!
this
.
config
.
enableCodeLens
)
{
return
null
;
}
let
conflicts
=
await
this
.
tracker
.
getConflicts
(
document
);
if
(
!
conflicts
||
conflicts
.
length
===
0
)
{
return
null
;
}
let
items
:
vscode
.
CodeLens
[]
=
[];
conflicts
.
forEach
(
conflict
=>
{
let
acceptCurrentCommand
:
vscode
.
Command
=
{
command
:
'
merge-conflict.accept.current
'
,
title
:
localize
(
'
acceptCurrentChange
'
,
'
Accept current change
'
),
arguments
:
[
'
known-conflict
'
,
conflict
]
};
let
acceptIncomingCommand
:
vscode
.
Command
=
{
command
:
'
merge-conflict.accept.incoming
'
,
title
:
localize
(
'
acceptIncomingChange
'
,
'
Accept incoming change
'
),
arguments
:
[
'
known-conflict
'
,
conflict
]
};
let
acceptBothCommand
:
vscode
.
Command
=
{
command
:
'
merge-conflict.accept.both
'
,
title
:
localize
(
'
acceptBothChanges
'
,
'
Accept both changes
'
),
arguments
:
[
'
known-conflict
'
,
conflict
]
};
let
diffCommand
:
vscode
.
Command
=
{
command
:
'
merge-conflict.compare
'
,
title
:
localize
(
'
compareChanges
'
,
'
Compare changes
'
),
arguments
:
[
conflict
]
};
items
.
push
(
new
vscode
.
CodeLens
(
conflict
.
range
,
acceptCurrentCommand
),
new
vscode
.
CodeLens
(
conflict
.
range
.
with
(
conflict
.
range
.
start
.
with
({
character
:
conflict
.
range
.
start
.
character
+
1
})),
acceptIncomingCommand
),
new
vscode
.
CodeLens
(
conflict
.
range
.
with
(
conflict
.
range
.
start
.
with
({
character
:
conflict
.
range
.
start
.
character
+
2
})),
acceptBothCommand
),
new
vscode
.
CodeLens
(
conflict
.
range
.
with
(
conflict
.
range
.
start
.
with
({
character
:
conflict
.
range
.
start
.
character
+
3
})),
diffCommand
)
);
});
return
items
;
}
private
registerCodeLensProvider
()
{
this
.
codeLensRegistrationHandle
=
vscode
.
languages
.
registerCodeLensProvider
({
pattern
:
'
**/*
'
},
this
);
}
}
extensions/merge-conflict/src/commandHandler.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
import
ContentProvider
from
'
./contentProvider
'
;
import
*
as
path
from
'
path
'
;
import
{
loadMessageBundle
}
from
'
vscode-nls
'
;
const
localize
=
loadMessageBundle
();
const
messages
=
{
cursorNotInConflict
:
'
Editor cursor is not within a merge conflict
'
,
cursorOnSplitterRange
:
'
Editor cursor is within the merge conflict splitter, please move it to either the "current" or "incoming" block
'
,
noConflicts
:
'
No merge conflicts found in this file
'
,
noOtherConflictsInThisFile
:
'
No other merge conflicts within this file
'
};
interface
IDocumentMergeConflictNavigationResults
{
canNavigate
:
boolean
;
conflict
?:
interfaces
.
IDocumentMergeConflict
;
}
enum
NavigationDirection
{
Forwards
,
Backwards
}
export
default
class
CommandHandler
implements
vscode
.
Disposable
{
private
disposables
:
vscode
.
Disposable
[]
=
[];
private
tracker
:
interfaces
.
IDocumentMergeConflictTracker
;
constructor
(
private
context
:
vscode
.
ExtensionContext
,
trackerService
:
interfaces
.
IDocumentMergeConflictTrackerService
)
{
this
.
tracker
=
trackerService
.
createTracker
(
'
commands
'
);
}
begin
()
{
this
.
disposables
.
push
(
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.current
'
,
this
.
acceptCurrent
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.incoming
'
,
this
.
acceptIncoming
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.selection
'
,
this
.
acceptSelection
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.both
'
,
this
.
acceptBoth
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.all-current
'
,
this
.
acceptAllCurrent
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.all-incoming
'
,
this
.
acceptAllIncoming
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.accept.all-both
'
,
this
.
acceptAllBoth
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.next
'
,
this
.
navigateNext
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.previous
'
,
this
.
navigatePrevious
,
this
),
vscode
.
commands
.
registerTextEditorCommand
(
'
merge-conflict.compare
'
,
this
.
compare
,
this
)
);
}
acceptCurrent
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
accept
(
interfaces
.
CommitType
.
Current
,
editor
,
...
args
);
}
acceptIncoming
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
accept
(
interfaces
.
CommitType
.
Incoming
,
editor
,
...
args
);
}
acceptBoth
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
accept
(
interfaces
.
CommitType
.
Both
,
editor
,
...
args
);
}
acceptAllCurrent
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
acceptAll
(
interfaces
.
CommitType
.
Current
,
editor
);
}
acceptAllIncoming
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
acceptAll
(
interfaces
.
CommitType
.
Incoming
,
editor
);
}
acceptAllBoth
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
acceptAll
(
interfaces
.
CommitType
.
Both
,
editor
);
}
async
compare
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
conflict
:
interfaces
.
IDocumentMergeConflict
|
null
,
...
args
)
{
const
fileName
=
path
.
basename
(
editor
.
document
.
uri
.
fsPath
);
// No conflict, command executed from command palette
if
(
!
conflict
)
{
conflict
=
await
this
.
findConflictContainingSelection
(
editor
);
// Still failed to find conflict, warn the user and exit
if
(
!
conflict
)
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
cursorNotInConflict
'
,
messages
.
cursorNotInConflict
));
return
;
}
}
let
range
=
conflict
.
current
.
content
;
const
leftUri
=
editor
.
document
.
uri
.
with
({
scheme
:
ContentProvider
.
scheme
,
query
:
JSON
.
stringify
(
range
)
});
range
=
conflict
.
incoming
.
content
;
const
rightUri
=
leftUri
.
with
({
query
:
JSON
.
stringify
(
range
)
});
const
title
=
localize
(
'
compareChangesTitle
'
,
'
{0}: Current changes
\
u2194 Incoming changes
'
,
fileName
);
vscode
.
commands
.
executeCommand
(
'
vscode.diff
'
,
leftUri
,
rightUri
,
title
);
}
navigateNext
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
navigate
(
editor
,
NavigationDirection
.
Forwards
);
}
navigatePrevious
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
return
this
.
navigate
(
editor
,
NavigationDirection
.
Backwards
);
}
async
acceptSelection
(
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
,
...
args
):
Promise
<
void
>
{
let
conflict
=
await
this
.
findConflictContainingSelection
(
editor
);
if
(
!
conflict
)
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
cursorNotInConflict
'
,
messages
.
cursorNotInConflict
));
return
;
}
let
typeToAccept
:
interfaces
.
CommitType
;
// Figure out if the cursor is in current or incoming, we do this by seeing if
// the active position is before or after the range of the splitter. We can
// use this trick as the previous check in findConflictByActiveSelection will
// ensure it's within the conflict range, so we don't falsely identify "current"
// or "incoming" if outside of a conflict range.
if
(
editor
.
selection
.
active
.
isBefore
(
conflict
.
splitter
.
start
))
{
typeToAccept
=
interfaces
.
CommitType
.
Current
;
}
else
if
(
editor
.
selection
.
active
.
isAfter
(
conflict
.
splitter
.
end
))
{
typeToAccept
=
interfaces
.
CommitType
.
Incoming
;
}
else
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
cursorOnSplitterRange
'
,
messages
.
cursorOnSplitterRange
));
return
;
}
this
.
tracker
.
forget
(
editor
.
document
);
conflict
.
commitEdit
(
typeToAccept
,
editor
);
}
dispose
()
{
this
.
disposables
.
forEach
(
disposable
=>
disposable
.
dispose
());
this
.
disposables
=
[];
}
private
async
navigate
(
editor
:
vscode
.
TextEditor
,
direction
:
NavigationDirection
):
Promise
<
void
>
{
let
navigationResult
=
await
this
.
findConflictForNavigation
(
editor
,
direction
);
if
(
!
navigationResult
)
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
noConflicts
'
,
messages
.
noConflicts
));
return
;
}
else
if
(
!
navigationResult
.
canNavigate
)
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
noOtherConflictsInThisFile
'
,
messages
.
noOtherConflictsInThisFile
));
return
;
}
else
if
(
!
navigationResult
.
conflict
)
{
// TODO: Show error message?
return
;
}
// Move the selection to the first line of the conflict
editor
.
selection
=
new
vscode
.
Selection
(
navigationResult
.
conflict
.
range
.
start
,
navigationResult
.
conflict
.
range
.
start
);
editor
.
revealRange
(
navigationResult
.
conflict
.
range
,
vscode
.
TextEditorRevealType
.
Default
);
}
private
async
accept
(
type
:
interfaces
.
CommitType
,
editor
:
vscode
.
TextEditor
,
...
args
):
Promise
<
void
>
{
let
conflict
:
interfaces
.
IDocumentMergeConflict
|
null
;
// If launched with known context, take the conflict from that
if
(
args
[
0
]
===
'
known-conflict
'
)
{
conflict
=
args
[
1
];
}
else
{
// Attempt to find a conflict that matches the current curosr position
conflict
=
await
this
.
findConflictContainingSelection
(
editor
);
}
if
(
!
conflict
)
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
cursorNotInConflict
'
,
messages
.
cursorNotInConflict
));
return
;
}
// Tracker can forget as we know we are going to do an edit
this
.
tracker
.
forget
(
editor
.
document
);
conflict
.
commitEdit
(
type
,
editor
);
}
private
async
acceptAll
(
type
:
interfaces
.
CommitType
,
editor
:
vscode
.
TextEditor
):
Promise
<
void
>
{
let
conflicts
=
await
this
.
tracker
.
getConflicts
(
editor
.
document
);
if
(
!
conflicts
||
conflicts
.
length
===
0
)
{
vscode
.
window
.
showWarningMessage
(
localize
(
'
noConflicts
'
,
messages
.
noConflicts
));
return
;
}
// For get the current state of the document, as we know we are doing to do a large edit
this
.
tracker
.
forget
(
editor
.
document
);
// Apply all changes as one edit
await
editor
.
edit
((
edit
)
=>
conflicts
.
forEach
(
conflict
=>
{
conflict
.
applyEdit
(
type
,
editor
,
edit
);
}));
}
private
async
findConflictContainingSelection
(
editor
:
vscode
.
TextEditor
,
conflicts
?:
interfaces
.
IDocumentMergeConflict
[]):
Promise
<
interfaces
.
IDocumentMergeConflict
|
null
>
{
if
(
!
conflicts
)
{
conflicts
=
await
this
.
tracker
.
getConflicts
(
editor
.
document
);
}
if
(
!
conflicts
||
conflicts
.
length
===
0
)
{
return
null
;
}
for
(
let
i
=
0
;
i
<
conflicts
.
length
;
i
++
)
{
if
(
conflicts
[
i
].
range
.
contains
(
editor
.
selection
.
active
))
{
return
conflicts
[
i
];
}
}
return
null
;
}
private
async
findConflictForNavigation
(
editor
:
vscode
.
TextEditor
,
direction
:
NavigationDirection
,
conflicts
?:
interfaces
.
IDocumentMergeConflict
[]):
Promise
<
IDocumentMergeConflictNavigationResults
|
null
>
{
if
(
!
conflicts
)
{
conflicts
=
await
this
.
tracker
.
getConflicts
(
editor
.
document
);
}
if
(
!
conflicts
||
conflicts
.
length
===
0
)
{
return
null
;
}
let
selection
=
editor
.
selection
.
active
;
if
(
conflicts
.
length
===
1
)
{
if
(
conflicts
[
0
].
range
.
contains
(
selection
))
{
return
{
canNavigate
:
false
};
}
return
{
canNavigate
:
true
,
conflict
:
conflicts
[
0
]
};
}
let
predicate
:
(
conflict
)
=>
boolean
;
let
fallback
:
()
=>
interfaces
.
IDocumentMergeConflict
;
if
(
direction
===
NavigationDirection
.
Forwards
)
{
predicate
=
(
conflict
)
=>
selection
.
isBefore
(
conflict
.
range
.
start
);
fallback
=
()
=>
conflicts
!
[
0
];
}
else
if
(
direction
===
NavigationDirection
.
Backwards
)
{
predicate
=
(
conflict
)
=>
selection
.
isAfter
(
conflict
.
range
.
start
);
fallback
=
()
=>
conflicts
!
[
conflicts
!
.
length
-
1
];
}
else
{
throw
new
Error
(
`Unsupported direction
${
direction
}
`
);
}
for
(
let
i
=
0
;
i
<
conflicts
.
length
;
i
++
)
{
if
(
predicate
(
conflicts
[
i
])
&&
!
conflicts
[
i
].
range
.
contains
(
selection
))
{
return
{
canNavigate
:
true
,
conflict
:
conflicts
[
i
]
};
}
}
// Went all the way to the end, return the head
return
{
canNavigate
:
true
,
conflict
:
fallback
()
};
}
}
\ No newline at end of file
extensions/merge-conflict/src/contentProvider.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
import
*
as
vscode
from
'
vscode
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
export
default
class
MergeConflictContentProvider
implements
vscode
.
TextDocumentContentProvider
,
vscode
.
Disposable
{
static
scheme
=
'
merge-conflict.conflict-diff
'
;
constructor
(
private
context
:
vscode
.
ExtensionContext
)
{
}
begin
(
config
:
interfaces
.
IExtensionConfiguration
)
{
this
.
context
.
subscriptions
.
push
(
vscode
.
workspace
.
registerTextDocumentContentProvider
(
MergeConflictContentProvider
.
scheme
,
this
)
);
}
dispose
()
{
}
async
provideTextDocumentContent
(
uri
:
vscode
.
Uri
):
Promise
<
string
|
null
>
{
try
{
const
[
start
,
end
]
=
JSON
.
parse
(
uri
.
query
)
as
{
line
:
number
,
character
:
number
}[];
const
document
=
await
vscode
.
workspace
.
openTextDocument
(
uri
.
with
({
scheme
:
'
file
'
,
query
:
''
}));
const
text
=
document
.
getText
(
new
vscode
.
Range
(
start
.
line
,
start
.
character
,
end
.
line
,
end
.
character
));
return
text
;
}
catch
(
ex
)
{
await
vscode
.
window
.
showErrorMessage
(
'
Unable to show comparison
'
);
return
null
;
}
}
}
\ No newline at end of file
extensions/merge-conflict/src/delayer.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'
use strict
'
;
export
interface
ITask
<
T
>
{
():
T
;
}
export
class
Delayer
<
T
>
{
public
defaultDelay
:
number
;
private
timeout
:
any
;
// Timer
private
completionPromise
:
Promise
<
T
>
|
null
;
private
onSuccess
:
((
value
?:
T
|
Thenable
<
T
>
|
null
)
=>
void
)
|
null
;
private
task
:
ITask
<
T
>
|
null
;
constructor
(
defaultDelay
:
number
)
{
this
.
defaultDelay
=
defaultDelay
;
this
.
timeout
=
null
;
this
.
completionPromise
=
null
;
this
.
onSuccess
=
null
;
this
.
task
=
null
;
}
public
trigger
(
task
:
ITask
<
T
>
,
delay
:
number
=
this
.
defaultDelay
):
Promise
<
T
>
{
this
.
task
=
task
;
if
(
delay
>=
0
)
{
this
.
cancelTimeout
();
}
if
(
!
this
.
completionPromise
)
{
this
.
completionPromise
=
new
Promise
<
T
>
((
resolve
)
=>
{
this
.
onSuccess
=
resolve
;
}).
then
(()
=>
{
this
.
completionPromise
=
null
;
this
.
onSuccess
=
null
;
var
result
=
this
.
task
!
();
this
.
task
=
null
;
return
result
;
});
}
if
(
delay
>=
0
||
this
.
timeout
===
null
)
{
this
.
timeout
=
setTimeout
(()
=>
{
this
.
timeout
=
null
;
this
.
onSuccess
!
(
null
);
},
delay
>=
0
?
delay
:
this
.
defaultDelay
);
}
return
this
.
completionPromise
;
}
public
forceDelivery
():
Promise
<
T
>
|
null
{
if
(
!
this
.
completionPromise
)
{
return
null
;
}
this
.
cancelTimeout
();
let
result
=
this
.
completionPromise
;
this
.
onSuccess
!
(
null
);
return
result
;
}
public
isTriggered
():
boolean
{
return
this
.
timeout
!==
null
;
}
public
cancel
():
void
{
this
.
cancelTimeout
();
this
.
completionPromise
=
null
;
}
private
cancelTimeout
():
void
{
if
(
this
.
timeout
!==
null
)
{
clearTimeout
(
this
.
timeout
);
this
.
timeout
=
null
;
}
}
}
\ No newline at end of file
extensions/merge-conflict/src/documentMergeConflict.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
interfaces
from
'
./interfaces
'
;
import
*
as
vscode
from
'
vscode
'
;
export
class
DocumentMergeConflict
implements
interfaces
.
IDocumentMergeConflict
{
public
range
:
vscode
.
Range
;
public
current
:
interfaces
.
IMergeRegion
;
public
incoming
:
interfaces
.
IMergeRegion
;
public
splitter
:
vscode
.
Range
;
constructor
(
document
:
vscode
.
TextDocument
,
descriptor
:
interfaces
.
IDocumentMergeConflictDescriptor
)
{
this
.
range
=
descriptor
.
range
;
this
.
current
=
descriptor
.
current
;
this
.
incoming
=
descriptor
.
incoming
;
this
.
splitter
=
descriptor
.
splitter
;
}
public
commitEdit
(
type
:
interfaces
.
CommitType
,
editor
:
vscode
.
TextEditor
,
edit
?:
vscode
.
TextEditorEdit
):
Thenable
<
boolean
>
{
if
(
edit
)
{
this
.
applyEdit
(
type
,
editor
,
edit
);
return
Promise
.
resolve
(
true
);
};
return
editor
.
edit
((
edit
)
=>
this
.
applyEdit
(
type
,
editor
,
edit
));
}
public
applyEdit
(
type
:
interfaces
.
CommitType
,
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
):
void
{
// Each conflict is a set of ranges as follows, note placements or newlines
// which may not in in spans
// [ Conflict Range -- (Entire content below)
// [ Current Header ]\n -- >>>>> Header
// [ Current Content ] -- (content)
// [ Splitter ]\n -- =====
// [ Incoming Content ] -- (content)
// [ Incoming Header ]\n -- <<<<< Incoming
// ]
if
(
type
===
interfaces
.
CommitType
.
Current
)
{
// Replace [ Conflict Range ] with [ Current Content ]
let
content
=
editor
.
document
.
getText
(
this
.
current
.
content
);
this
.
replaceRangeWithContent
(
content
,
edit
);
}
else
if
(
type
===
interfaces
.
CommitType
.
Incoming
)
{
let
content
=
editor
.
document
.
getText
(
this
.
incoming
.
content
);
this
.
replaceRangeWithContent
(
content
,
edit
);
}
else
if
(
type
===
interfaces
.
CommitType
.
Both
)
{
// Replace [ Conflict Range ] with [ Current Content ] + \n + [ Incoming Content ]
const
currentContent
=
editor
.
document
.
getText
(
this
.
current
.
content
);
const
incomingContent
=
editor
.
document
.
getText
(
this
.
incoming
.
content
);
edit
.
replace
(
this
.
range
,
currentContent
.
concat
(
incomingContent
));
}
}
private
replaceRangeWithContent
(
content
:
string
,
edit
:
vscode
.
TextEditorEdit
)
{
if
(
this
.
isNewlineOnly
(
content
))
{
edit
.
replace
(
this
.
range
,
''
);
return
;
}
// Replace [ Conflict Range ] with [ Current Content ]
edit
.
replace
(
this
.
range
,
content
);
}
private
isNewlineOnly
(
text
:
string
)
{
return
text
===
'
\n
'
||
text
===
'
\r\n
'
;
}
}
\ No newline at end of file
extensions/merge-conflict/src/documentTracker.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
{
MergeConflictParser
}
from
'
./mergeConflictParser
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
import
{
Delayer
}
from
'
./delayer
'
;
class
ScanTask
{
public
origins
:
Set
<
string
>
=
new
Set
<
string
>
();
public
delayTask
:
Delayer
<
interfaces
.
IDocumentMergeConflict
[]
>
;
constructor
(
delayTime
:
number
,
initialOrigin
:
string
)
{
this
.
origins
.
add
(
initialOrigin
);
this
.
delayTask
=
new
Delayer
<
interfaces
.
IDocumentMergeConflict
[]
>
(
delayTime
);
}
public
addOrigin
(
name
:
string
):
boolean
{
if
(
this
.
origins
.
has
(
name
))
{
return
false
;
}
return
false
;
}
public
hasOrigin
(
name
:
string
):
boolean
{
return
this
.
origins
.
has
(
name
);
}
}
class
OriginDocumentMergeConflictTracker
implements
interfaces
.
IDocumentMergeConflictTracker
{
constructor
(
private
parent
:
DocumentMergeConflictTracker
,
private
origin
:
string
)
{
}
getConflicts
(
document
:
vscode
.
TextDocument
):
PromiseLike
<
interfaces
.
IDocumentMergeConflict
[]
>
{
return
this
.
parent
.
getConflicts
(
document
,
this
.
origin
);
}
isPending
(
document
:
vscode
.
TextDocument
):
boolean
{
return
this
.
parent
.
isPending
(
document
,
this
.
origin
);
}
forget
(
document
:
vscode
.
TextDocument
)
{
this
.
parent
.
forget
(
document
);
}
}
export
default
class
DocumentMergeConflictTracker
implements
vscode
.
Disposable
,
interfaces
.
IDocumentMergeConflictTrackerService
{
private
cache
:
Map
<
string
,
ScanTask
>
=
new
Map
();
private
delayExpireTime
:
number
=
250
;
getConflicts
(
document
:
vscode
.
TextDocument
,
origin
:
string
):
PromiseLike
<
interfaces
.
IDocumentMergeConflict
[]
>
{
// Attempt from cache
let
key
=
this
.
getCacheKey
(
document
);
if
(
!
key
)
{
// Document doesnt have a uri, can't cache it, so return
return
Promise
.
resolve
(
this
.
getConflictsOrEmpty
(
document
,
[
origin
]));
}
let
cacheItem
=
this
.
cache
.
get
(
key
);
if
(
!
cacheItem
)
{
cacheItem
=
new
ScanTask
(
this
.
delayExpireTime
,
origin
);
this
.
cache
.
set
(
key
,
cacheItem
);
}
else
{
cacheItem
.
addOrigin
(
origin
);
}
return
cacheItem
.
delayTask
.
trigger
(()
=>
{
let
conflicts
=
this
.
getConflictsOrEmpty
(
document
,
Array
.
from
(
cacheItem
!
.
origins
));
if
(
this
.
cache
)
{
this
.
cache
.
delete
(
key
!
);
}
return
conflicts
;
});
}
isPending
(
document
:
vscode
.
TextDocument
,
origin
:
string
):
boolean
{
if
(
!
document
)
{
return
false
;
}
let
key
=
this
.
getCacheKey
(
document
);
if
(
!
key
)
{
return
false
;
}
var
task
=
this
.
cache
.
get
(
key
);
if
(
!
task
)
{
return
false
;
}
return
task
.
hasOrigin
(
origin
);
}
createTracker
(
origin
:
string
):
interfaces
.
IDocumentMergeConflictTracker
{
return
new
OriginDocumentMergeConflictTracker
(
this
,
origin
);
}
forget
(
document
:
vscode
.
TextDocument
)
{
let
key
=
this
.
getCacheKey
(
document
);
if
(
key
)
{
this
.
cache
.
delete
(
key
);
}
}
dispose
()
{
this
.
cache
.
clear
();
}
private
getConflictsOrEmpty
(
document
:
vscode
.
TextDocument
,
origins
:
string
[]):
interfaces
.
IDocumentMergeConflict
[]
{
const
containsConflict
=
MergeConflictParser
.
containsConflict
(
document
);
if
(
!
containsConflict
)
{
return
[];
}
const
conflicts
=
MergeConflictParser
.
scanDocument
(
document
);
return
conflicts
;
}
private
getCacheKey
(
document
:
vscode
.
TextDocument
):
string
|
null
{
if
(
document
.
uri
&&
document
.
uri
)
{
return
document
.
uri
.
toString
();
}
return
null
;
}
}
extensions/merge-conflict/src/extension.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
MergeConflictServices
from
'
./services
'
;
export
function
activate
(
context
:
vscode
.
ExtensionContext
)
{
// Register disposables
const
services
=
new
MergeConflictServices
(
context
);
services
.
begin
();
context
.
subscriptions
.
push
(
services
);
}
export
function
deactivate
()
{
}
extensions/merge-conflict/src/interfaces.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
export
interface
IMergeRegion
{
name
:
string
;
header
:
vscode
.
Range
;
content
:
vscode
.
Range
;
decoratorContent
:
vscode
.
Range
;
}
export
enum
CommitType
{
Current
,
Incoming
,
Both
}
export
interface
IExtensionConfiguration
{
enableCodeLens
:
boolean
;
enableDecorations
:
boolean
;
enableEditorOverview
:
boolean
;
}
export
interface
IDocumentMergeConflict
extends
IDocumentMergeConflictDescriptor
{
commitEdit
(
type
:
CommitType
,
editor
:
vscode
.
TextEditor
,
edit
?:
vscode
.
TextEditorEdit
);
applyEdit
(
type
:
CommitType
,
editor
:
vscode
.
TextEditor
,
edit
:
vscode
.
TextEditorEdit
);
}
export
interface
IDocumentMergeConflictDescriptor
{
range
:
vscode
.
Range
;
current
:
IMergeRegion
;
incoming
:
IMergeRegion
;
splitter
:
vscode
.
Range
;
}
export
interface
IDocumentMergeConflictTracker
{
getConflicts
(
document
:
vscode
.
TextDocument
):
PromiseLike
<
IDocumentMergeConflict
[]
>
;
isPending
(
document
:
vscode
.
TextDocument
):
boolean
;
forget
(
document
:
vscode
.
TextDocument
);
}
export
interface
IDocumentMergeConflictTrackerService
{
createTracker
(
origin
:
string
):
IDocumentMergeConflictTracker
;
forget
(
document
:
vscode
.
TextDocument
);
}
extensions/merge-conflict/src/mergeConflictParser.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
import
{
DocumentMergeConflict
}
from
'
./documentMergeConflict
'
;
const
startHeaderMarker
=
'
<<<<<<<
'
;
const
splitterMarker
=
'
=======
'
;
const
endFooterMarker
=
'
>>>>>>>
'
;
interface
IScanMergedConflict
{
startHeader
:
vscode
.
TextLine
;
splitter
?:
vscode
.
TextLine
;
endFooter
?:
vscode
.
TextLine
;
}
export
class
MergeConflictParser
{
static
scanDocument
(
document
:
vscode
.
TextDocument
):
interfaces
.
IDocumentMergeConflict
[]
{
// Scan each line in the document, we already know there is atleast a <<<<<<< and
// >>>>>> marker within the document, we need to group these into conflict ranges.
// We initially build a scan match, that references the lines of the header, splitter
// and footer. This is then converted into a full descriptor containing all required
// ranges.
let
currentConflict
:
IScanMergedConflict
|
null
=
null
;
const
conflictDescriptors
:
interfaces
.
IDocumentMergeConflictDescriptor
[]
=
[];
for
(
let
i
=
0
;
i
<
document
.
lineCount
;
i
++
)
{
const
line
=
document
.
lineAt
(
i
);
// Ignore empty lines
if
(
!
line
||
line
.
isEmptyOrWhitespace
)
{
continue
;
}
// Is this a start line? <<<<<<<
if
(
line
.
text
.
startsWith
(
startHeaderMarker
))
{
if
(
currentConflict
!==
null
)
{
// Error, we should not see a startMarker before we've seen an endMarker
currentConflict
=
null
;
// Give up parsing, anything matched up this to this point will be decorated
// anything after will not
break
;
}
// Create a new conflict starting at this line
currentConflict
=
{
startHeader
:
line
};
}
// Are we within a conflict block and is this a splitter? =======
else
if
(
currentConflict
&&
line
.
text
.
startsWith
(
splitterMarker
))
{
currentConflict
.
splitter
=
line
;
}
// Are we withon a conflict block and is this a footer? >>>>>>>
else
if
(
currentConflict
&&
line
.
text
.
startsWith
(
endFooterMarker
))
{
currentConflict
.
endFooter
=
line
;
// Create a full descriptor from the lines that we matched. This can return
// null if the descriptor could not be completed.
let
completeDescriptor
=
MergeConflictParser
.
scanItemTolMergeConflictDescriptor
(
document
,
currentConflict
);
if
(
completeDescriptor
!==
null
)
{
conflictDescriptors
.
push
(
completeDescriptor
);
}
// Reset the current conflict to be empty, so we can match the next
// starting header marker.
currentConflict
=
null
;
}
}
return
conflictDescriptors
.
filter
(
Boolean
)
.
map
(
descriptor
=>
new
DocumentMergeConflict
(
document
,
descriptor
));
}
private
static
scanItemTolMergeConflictDescriptor
(
document
:
vscode
.
TextDocument
,
scanned
:
IScanMergedConflict
):
interfaces
.
IDocumentMergeConflictDescriptor
|
null
{
// Validate we have all the required lines within the scan item.
if
(
!
scanned
.
startHeader
||
!
scanned
.
splitter
||
!
scanned
.
endFooter
)
{
return
null
;
}
// Assume that descriptor.current.header, descriptor.incoming.header and descriptor.spliiter
// have valid ranges, fill in content and total ranges from these parts.
// NOTE: We need to shift the decortator range back one character so the splitter does not end up with
// two decoration colors (current and splitter), if we take the new line from the content into account
// the decorator will wrap to the next line.
return
{
current
:
{
header
:
scanned
.
startHeader
.
range
,
decoratorContent
:
new
vscode
.
Range
(
scanned
.
startHeader
.
rangeIncludingLineBreak
.
end
,
MergeConflictParser
.
shiftBackOneCharacter
(
document
,
scanned
.
splitter
.
range
.
start
)),
// Current content is range between header (shifted for linebreak) and splitter start
content
:
new
vscode
.
Range
(
scanned
.
startHeader
.
rangeIncludingLineBreak
.
end
,
scanned
.
splitter
.
range
.
start
),
name
:
scanned
.
startHeader
.
text
.
substring
(
startHeaderMarker
.
length
)
},
splitter
:
scanned
.
splitter
.
range
,
incoming
:
{
header
:
scanned
.
endFooter
.
range
,
decoratorContent
:
new
vscode
.
Range
(
scanned
.
splitter
.
rangeIncludingLineBreak
.
end
,
MergeConflictParser
.
shiftBackOneCharacter
(
document
,
scanned
.
endFooter
.
range
.
start
)),
// Incoming content is range between splitter (shifted for linebreak) and footer start
content
:
new
vscode
.
Range
(
scanned
.
splitter
.
rangeIncludingLineBreak
.
end
,
scanned
.
endFooter
.
range
.
start
),
name
:
scanned
.
endFooter
.
text
.
substring
(
endFooterMarker
.
length
)
},
// Entire range is between current header start and incoming header end (including line break)
range
:
new
vscode
.
Range
(
scanned
.
startHeader
.
range
.
start
,
scanned
.
endFooter
.
rangeIncludingLineBreak
.
end
)
};
}
static
containsConflict
(
document
:
vscode
.
TextDocument
):
boolean
{
if
(
!
document
)
{
return
false
;
}
let
text
=
document
.
getText
();
return
text
.
includes
(
startHeaderMarker
)
&&
text
.
includes
(
endFooterMarker
);
}
private
static
shiftBackOneCharacter
(
document
:
vscode
.
TextDocument
,
range
:
vscode
.
Position
):
vscode
.
Position
{
let
line
=
range
.
line
;
let
character
=
range
.
character
-
1
;
if
(
character
<
0
)
{
line
--
;
character
=
document
.
lineAt
(
line
).
range
.
end
.
character
;
}
return
new
vscode
.
Position
(
line
,
character
);
}
}
extensions/merge-conflict/src/mergeDecorator.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
import
{
loadMessageBundle
}
from
'
vscode-nls
'
;
const
localize
=
loadMessageBundle
();
export
default
class
MergeDectorator
implements
vscode
.
Disposable
{
private
decorations
:
{
[
key
:
string
]:
vscode
.
TextEditorDecorationType
}
=
{};
private
decorationUsesWholeLine
:
boolean
=
true
;
// Useful for debugging, set to false to see exact match ranges
// TODO: Move to config?
private
currentColorRgb
=
`32,200,94`
;
private
incomingColorRgb
=
`24,134,255`
;
private
config
:
interfaces
.
IExtensionConfiguration
;
private
tracker
:
interfaces
.
IDocumentMergeConflictTracker
;
constructor
(
private
context
:
vscode
.
ExtensionContext
,
trackerService
:
interfaces
.
IDocumentMergeConflictTrackerService
)
{
this
.
tracker
=
trackerService
.
createTracker
(
'
decorator
'
);
}
begin
(
config
:
interfaces
.
IExtensionConfiguration
)
{
this
.
config
=
config
;
this
.
registerDecorationTypes
(
config
);
// Check if we already have a set of active windows, attempt to track these.
vscode
.
window
.
visibleTextEditors
.
forEach
(
e
=>
this
.
applyDecorations
(
e
));
vscode
.
workspace
.
onDidOpenTextDocument
(
event
=>
{
this
.
applyDecorationsFromEvent
(
event
);
},
null
,
this
.
context
.
subscriptions
);
vscode
.
workspace
.
onDidChangeTextDocument
(
event
=>
{
this
.
applyDecorationsFromEvent
(
event
.
document
);
},
null
,
this
.
context
.
subscriptions
);
vscode
.
window
.
onDidChangeActiveTextEditor
((
e
)
=>
{
// New editor attempt to apply
this
.
applyDecorations
(
e
);
},
null
,
this
.
context
.
subscriptions
);
}
configurationUpdated
(
config
:
interfaces
.
IExtensionConfiguration
)
{
this
.
config
=
config
;
this
.
registerDecorationTypes
(
config
);
// Re-apply the decoration
vscode
.
window
.
visibleTextEditors
.
forEach
(
e
=>
{
this
.
removeDecorations
(
e
);
this
.
applyDecorations
(
e
);
});
}
private
registerDecorationTypes
(
config
:
interfaces
.
IExtensionConfiguration
)
{
// Dispose of existing decorations
Object
.
keys
(
this
.
decorations
).
forEach
(
k
=>
this
.
decorations
[
k
].
dispose
());
this
.
decorations
=
{};
// None of our features are enabled
if
(
!
config
.
enableDecorations
||
!
config
.
enableEditorOverview
)
{
return
;
}
// Create decorators
if
(
config
.
enableDecorations
||
config
.
enableEditorOverview
)
{
this
.
decorations
[
'
current.content
'
]
=
vscode
.
window
.
createTextEditorDecorationType
(
this
.
generateBlockRenderOptions
(
this
.
currentColorRgb
,
config
)
);
this
.
decorations
[
'
incoming.content
'
]
=
vscode
.
window
.
createTextEditorDecorationType
(
this
.
generateBlockRenderOptions
(
this
.
incomingColorRgb
,
config
)
);
}
if
(
config
.
enableDecorations
)
{
this
.
decorations
[
'
current.header
'
]
=
vscode
.
window
.
createTextEditorDecorationType
({
// backgroundColor: 'rgba(255, 0, 0, 0.01)',
// border: '2px solid red',
isWholeLine
:
this
.
decorationUsesWholeLine
,
backgroundColor
:
`rgba(
${
this
.
currentColorRgb
}
, 1.0)`
,
color
:
'
white
'
,
after
:
{
contentText
:
'
'
+
localize
(
'
currentChange
'
,
'
(Current change)
'
),
color
:
'
rgba(0, 0, 0, 0.7)
'
}
});
this
.
decorations
[
'
splitter
'
]
=
vscode
.
window
.
createTextEditorDecorationType
({
backgroundColor
:
'
rgba(0, 0, 0, 0.25)
'
,
color
:
'
white
'
,
isWholeLine
:
this
.
decorationUsesWholeLine
,
});
this
.
decorations
[
'
incoming.header
'
]
=
vscode
.
window
.
createTextEditorDecorationType
({
backgroundColor
:
`rgba(
${
this
.
incomingColorRgb
}
, 1.0)`
,
color
:
'
white
'
,
isWholeLine
:
this
.
decorationUsesWholeLine
,
after
:
{
contentText
:
'
'
+
localize
(
'
incomingChange
'
,
'
(Incoming change)
'
),
color
:
'
rgba(0, 0, 0, 0.7)
'
}
});
}
}
dispose
()
{
// TODO: Replace with Map<string, T>
Object
.
keys
(
this
.
decorations
).
forEach
(
name
=>
{
this
.
decorations
[
name
].
dispose
();
});
this
.
decorations
=
{};
}
private
generateBlockRenderOptions
(
color
:
string
,
config
:
interfaces
.
IExtensionConfiguration
):
vscode
.
DecorationRenderOptions
{
let
renderOptions
:
any
=
{};
if
(
config
.
enableDecorations
)
{
renderOptions
.
backgroundColor
=
`rgba(
${
color
}
, 0.2)`
;
renderOptions
.
isWholeLine
=
this
.
decorationUsesWholeLine
;
}
if
(
config
.
enableEditorOverview
)
{
renderOptions
.
overviewRulerColor
=
`rgba(
${
color
}
, 0.5)`
;
renderOptions
.
overviewRulerLane
=
vscode
.
OverviewRulerLane
.
Full
;
}
return
renderOptions
;
}
private
applyDecorationsFromEvent
(
eventDocument
:
vscode
.
TextDocument
)
{
for
(
var
i
=
0
;
i
<
vscode
.
window
.
visibleTextEditors
.
length
;
i
++
)
{
if
(
vscode
.
window
.
visibleTextEditors
[
i
].
document
===
eventDocument
)
{
// Attempt to apply
this
.
applyDecorations
(
vscode
.
window
.
visibleTextEditors
[
i
]);
}
}
}
private
async
applyDecorations
(
editor
:
vscode
.
TextEditor
)
{
if
(
!
editor
||
!
editor
.
document
)
{
return
;
}
if
(
!
this
.
config
||
(
!
this
.
config
.
enableDecorations
&&
!
this
.
config
.
enableEditorOverview
))
{
return
;
}
// If we have a pending scan from the same origin, exit early.
if
(
this
.
tracker
.
isPending
(
editor
.
document
))
{
return
;
}
let
conflicts
=
await
this
.
tracker
.
getConflicts
(
editor
.
document
);
if
(
conflicts
.
length
===
0
)
{
this
.
removeDecorations
(
editor
);
return
;
}
// Store decorations keyed by the type of decoration, set decoration wants a "style"
// to go with it, which will match this key (see constructor);
let
matchDecorations
:
{
[
key
:
string
]:
vscode
.
DecorationOptions
[]
}
=
{};
let
pushDecoration
=
(
key
:
string
,
d
:
vscode
.
DecorationOptions
)
=>
{
matchDecorations
[
key
]
=
matchDecorations
[
key
]
||
[];
matchDecorations
[
key
].
push
(
d
);
};
conflicts
.
forEach
(
conflict
=>
{
// TODO, this could be more effective, just call getMatchPositions once with a map of decoration to position
pushDecoration
(
'
current.content
'
,
{
range
:
conflict
.
current
.
decoratorContent
});
pushDecoration
(
'
incoming.content
'
,
{
range
:
conflict
.
incoming
.
decoratorContent
});
if
(
this
.
config
.
enableDecorations
)
{
pushDecoration
(
'
current.header
'
,
{
range
:
conflict
.
current
.
header
});
pushDecoration
(
'
splitter
'
,
{
range
:
conflict
.
splitter
});
pushDecoration
(
'
incoming.header
'
,
{
range
:
conflict
.
incoming
.
header
});
}
});
// For each match we've generated, apply the generated decoration with the matching decoration type to the
// editor instance. Keys in both matches and decorations should match.
Object
.
keys
(
matchDecorations
).
forEach
(
decorationKey
=>
{
let
decorationType
=
this
.
decorations
[
decorationKey
];
if
(
decorationType
)
{
editor
.
setDecorations
(
decorationType
,
matchDecorations
[
decorationKey
]);
}
});
}
private
removeDecorations
(
editor
:
vscode
.
TextEditor
)
{
// Remove all decorations, there might be none
Object
.
keys
(
this
.
decorations
).
forEach
(
decorationKey
=>
{
// Race condition, while editing the settings, it's possible to
// generate regions before the configuration has been refreshed
let
decorationType
=
this
.
decorations
[
decorationKey
];
if
(
decorationType
)
{
editor
.
setDecorations
(
decorationType
,
[]);
}
});
}
}
\ No newline at end of file
extensions/merge-conflict/src/package.json
0 → 100644
浏览文件 @
6daf4d36
{
"name"
:
"git"
,
"publisher"
:
"vscode"
,
"displayName"
:
"git"
,
"description"
:
"Git"
,
"version"
:
"0.0.1"
,
"engines"
:
{
"vscode"
:
"^1.5.0"
},
"aiKey"
:
"AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217"
,
"enableProposedApi"
:
true
,
"categories"
:
[
"Other"
],
"activationEvents"
:
[
"*"
],
"main"
:
"./out/main"
,
"scripts"
:
{
"compile"
:
"gulp compile-extension:git"
,
"watch"
:
"gulp watch-extension:git"
},
"contributes"
:
{
"commands"
:
[
{
"command"
:
"git.clone"
,
"title"
:
"%command.clone%"
,
"category"
:
"Git"
},
{
"command"
:
"git.init"
,
"title"
:
"%command.init%"
,
"category"
:
"Git"
},
{
"command"
:
"git.refresh"
,
"title"
:
"%command.refresh%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/refresh.svg"
,
"dark"
:
"resources/icons/dark/refresh.svg"
}
},
{
"command"
:
"git.openChange"
,
"title"
:
"%command.openChange%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/open-change.svg"
,
"dark"
:
"resources/icons/dark/open-change.svg"
}
},
{
"command"
:
"git.openFile"
,
"title"
:
"%command.openFile%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/open-file.svg"
,
"dark"
:
"resources/icons/dark/open-file.svg"
}
},
{
"command"
:
"git.stage"
,
"title"
:
"%command.stage%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/stage.svg"
,
"dark"
:
"resources/icons/dark/stage.svg"
}
},
{
"command"
:
"git.stageAll"
,
"title"
:
"%command.stageAll%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/stage.svg"
,
"dark"
:
"resources/icons/dark/stage.svg"
}
},
{
"command"
:
"git.stageSelectedRanges"
,
"title"
:
"%command.stageSelectedRanges%"
,
"category"
:
"Git"
},
{
"command"
:
"git.revertSelectedRanges"
,
"title"
:
"%command.revertSelectedRanges%"
,
"category"
:
"Git"
},
{
"command"
:
"git.unstage"
,
"title"
:
"%command.unstage%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/unstage.svg"
,
"dark"
:
"resources/icons/dark/unstage.svg"
}
},
{
"command"
:
"git.unstageAll"
,
"title"
:
"%command.unstageAll%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/unstage.svg"
,
"dark"
:
"resources/icons/dark/unstage.svg"
}
},
{
"command"
:
"git.unstageSelectedRanges"
,
"title"
:
"%command.unstageSelectedRanges%"
,
"category"
:
"Git"
},
{
"command"
:
"git.clean"
,
"title"
:
"%command.clean%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/clean.svg"
,
"dark"
:
"resources/icons/dark/clean.svg"
}
},
{
"command"
:
"git.cleanAll"
,
"title"
:
"%command.cleanAll%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/clean.svg"
,
"dark"
:
"resources/icons/dark/clean.svg"
}
},
{
"command"
:
"git.commit"
,
"title"
:
"%command.commit%"
,
"category"
:
"Git"
,
"icon"
:
{
"light"
:
"resources/icons/light/check.svg"
,
"dark"
:
"resources/icons/dark/check.svg"
}
},
{
"command"
:
"git.commitStaged"
,
"title"
:
"%command.commitStaged%"
,
"category"
:
"Git"
},
{
"command"
:
"git.commitStagedSigned"
,
"title"
:
"%command.commitStagedSigned%"
,
"category"
:
"Git"
},
{
"command"
:
"git.commitAll"
,
"title"
:
"%command.commitAll%"
,
"category"
:
"Git"
},
{
"command"
:
"git.commitAllSigned"
,
"title"
:
"%command.commitAllSigned%"
,
"category"
:
"Git"
},
{
"command"
:
"git.undoCommit"
,
"title"
:
"%command.undoCommit%"
,
"category"
:
"Git"
},
{
"command"
:
"git.checkout"
,
"title"
:
"%command.checkout%"
,
"category"
:
"Git"
},
{
"command"
:
"git.branch"
,
"title"
:
"%command.branch%"
,
"category"
:
"Git"
},
{
"command"
:
"git.pull"
,
"title"
:
"%command.pull%"
,
"category"
:
"Git"
},
{
"command"
:
"git.pullRebase"
,
"title"
:
"%command.pullRebase%"
,
"category"
:
"Git"
},
{
"command"
:
"git.push"
,
"title"
:
"%command.push%"
,
"category"
:
"Git"
},
{
"command"
:
"git.pushTo"
,
"title"
:
"%command.pushTo%"
,
"category"
:
"Git"
},
{
"command"
:
"git.sync"
,
"title"
:
"%command.sync%"
,
"category"
:
"Git"
},
{
"command"
:
"git.publish"
,
"title"
:
"%command.publish%"
,
"category"
:
"Git"
},
{
"command"
:
"git.showOutput"
,
"title"
:
"%command.showOutput%"
,
"category"
:
"Git"
},
{
"command"
:
"git.merge.accept.all-current"
,
"title"
:
"Accept all current"
,
"category"
:
"Git Merge"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Accept all incoming"
,
"command"
:
"git.merge.accept.all-incoming"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Accept all both"
,
"command"
:
"git.merge.accept.all-both"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Accept current"
,
"command"
:
"git.merge.accept.current"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Accept incoming"
,
"command"
:
"git.merge.accept.incoming"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Accept selection"
,
"command"
:
"git.merge.accept.selection"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Accept both"
,
"command"
:
"git.merge.accept.both"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Next conflict"
,
"command"
:
"git.merge.next"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Previous conflict"
,
"command"
:
"git.merge.previous"
},
{
"category"
:
"Git Merge"
,
"title"
:
"Compare current conflict"
,
"command"
:
"git.merge.compare"
}
],
"keybindings"
:
[
{
"command"
:
"git.merge.next"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m down"
},
{
"command"
:
"git.merge.previous"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m up"
},
{
"command"
:
"git.merge.accept.selection"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m enter"
},
{
"command"
:
"git.merge.accept.current"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m 1"
},
{
"command"
:
"git.merge.accept.incoming"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m 2"
},
{
"command"
:
"git.merge.accept.both"
,
"when"
:
"editorTextFocus"
,
"key"
:
"alt+m 3"
}
],
"menus"
:
{
"commandPalette"
:
[
{
"command"
:
"git.clone"
,
"when"
:
"config.git.enabled"
},
{
"command"
:
"git.init"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == norepo"
},
{
"command"
:
"git.refresh"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.openFile"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.openChange"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.stageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.stageSelectedRanges"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.revertSelectedRanges"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.unstage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.unstageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.unstageSelectedRanges"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.clean"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.cleanAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitStaged"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitStagedSigned"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitAllSigned"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.undoCommit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.checkout"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.branch"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.pull"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.pullRebase"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.push"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.pushTo"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.sync"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.publish"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.showOutput"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
}
],
"scm/title"
:
[
{
"command"
:
"git.init"
,
"group"
:
"navigation"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == norepo"
},
{
"command"
:
"git.commit"
,
"group"
:
"navigation"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.refresh"
,
"group"
:
"navigation"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.sync"
,
"group"
:
"1_sync"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.pull"
,
"group"
:
"1_sync"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.pullRebase"
,
"group"
:
"1_sync"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.push"
,
"group"
:
"1_sync"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.pushTo"
,
"group"
:
"1_sync"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.publish"
,
"group"
:
"2_publish"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitStaged"
,
"group"
:
"3_commit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitStagedSigned"
,
"group"
:
"3_commit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitAll"
,
"group"
:
"3_commit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.commitAllSigned"
,
"group"
:
"3_commit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.undoCommit"
,
"group"
:
"3_commit"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.unstageAll"
,
"group"
:
"4_stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.cleanAll"
,
"group"
:
"4_stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
},
{
"command"
:
"git.showOutput"
,
"group"
:
"5_output"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle"
}
],
"scm/resourceGroup/context"
:
[
{
"command"
:
"git.stageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == merge"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.stageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == merge"
,
"group"
:
"inline"
},
{
"command"
:
"git.unstageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == index"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.unstageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == index"
,
"group"
:
"inline"
},
{
"command"
:
"git.cleanAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.stageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.cleanAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"inline"
},
{
"command"
:
"git.stageAll"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"inline"
}
],
"scm/resourceState/context"
:
[
{
"command"
:
"git.stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == merge"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == merge"
,
"group"
:
"inline"
},
{
"command"
:
"git.openChange"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == index"
,
"group"
:
"navigation"
},
{
"command"
:
"git.openFile"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == index"
,
"group"
:
"navigation"
},
{
"command"
:
"git.unstage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == index"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.unstage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == index"
,
"group"
:
"inline"
},
{
"command"
:
"git.openChange"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"navigation"
},
{
"command"
:
"git.openFile"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"navigation"
},
{
"command"
:
"git.stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.clean"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"1_modification"
},
{
"command"
:
"git.clean"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"inline"
},
{
"command"
:
"git.stage"
,
"when"
:
"config.git.enabled && scmProvider == git && gitState == idle && scmResourceGroup == workingTree"
,
"group"
:
"inline"
}
],
"editor/title"
:
[
{
"command"
:
"git.openFile"
,
"group"
:
"navigation"
,
"when"
:
"config.git.enabled && scmProvider == git && isInDiffEditor && resourceScheme != extension"
},
{
"command"
:
"git.openChange"
,
"group"
:
"navigation"
,
"when"
:
"config.git.enabled && scmProvider == git && !isInDiffEditor && resourceScheme != extension"
},
{
"command"
:
"git.stageSelectedRanges"
,
"group"
:
"2_git@1"
,
"when"
:
"config.git.enabled && scmProvider == git && isInDiffEditor"
},
{
"command"
:
"git.unstageSelectedRanges"
,
"group"
:
"2_git@2"
,
"when"
:
"config.git.enabled && scmProvider == git && isInDiffEditor"
},
{
"command"
:
"git.revertSelectedRanges"
,
"group"
:
"2_git@3"
,
"when"
:
"config.git.enabled && scmProvider == git && isInDiffEditor"
}
]
},
"configuration"
:
{
"title"
:
"Git"
,
"properties"
:
{
"git.enabled"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.enabled%"
,
"default"
:
true
},
"git.path"
:
{
"type"
:
[
"string"
,
"null"
],
"description"
:
"%config.path%"
,
"default"
:
null
,
"isExecutable"
:
true
},
"git.autorefresh"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.autorefresh%"
,
"default"
:
true
},
"git.autofetch"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.autofetch%"
,
"default"
:
true
},
"git.confirmSync"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.confirmSync%"
,
"default"
:
true
},
"git.countBadge"
:
{
"type"
:
"string"
,
"enum"
:
[
"all"
,
"tracked"
,
"off"
],
"description"
:
"%config.countBadge%"
,
"default"
:
"all"
},
"git.checkoutType"
:
{
"type"
:
"string"
,
"enum"
:
[
"all"
,
"local"
,
"tags"
,
"remote"
],
"description"
:
"%config.checkoutType%"
,
"default"
:
"all"
},
"git.ignoreLegacyWarning"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.ignoreLegacyWarning%"
,
"default"
:
false
},
"git.ignoreLimitWarning"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.ignoreLimitWarning%"
,
"default"
:
false
},
"git.defaultCloneDirectory"
:
{
"type"
:
"string"
,
"default"
:
null
,
"description"
:
"%config.defaultCloneDirectory%"
},
"git.enableSmartCommit"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.enableSmartCommit%"
,
"default"
:
false
},
"git.enableEditorMerge"
:
{
"type"
:
"boolean"
,
"description"
:
"%config.enableEditorMerge%"
,
"default"
:
true
}
}
}
},
"dependencies"
:
{
"iconv-lite"
:
"0.4.15"
,
"vscode-extension-telemetry"
:
"^0.0.7"
,
"vscode-nls"
:
"^2.0.1"
},
"devDependencies"
:
{
"@types/mocha"
:
"^2.2.41"
,
"@types/node"
:
"^7.0.4"
,
"mocha"
:
"^3.2.0"
}
}
\ No newline at end of file
extensions/merge-conflict/src/services.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
DocumentTracker
from
'
./documentTracker
'
;
import
CodeLensProvider
from
'
./codelensProvider
'
;
import
CommandHandler
from
'
./commandHandler
'
;
import
ContentProvider
from
'
./contentProvider
'
;
import
Decorator
from
'
./mergeDecorator
'
;
import
*
as
interfaces
from
'
./interfaces
'
;
const
ConfigurationSectionName
=
'
merge-conflict
'
;
export
default
class
ServiceWrapper
implements
vscode
.
Disposable
{
private
services
:
vscode
.
Disposable
[]
=
[];
constructor
(
private
context
:
vscode
.
ExtensionContext
)
{
}
begin
()
{
let
configuration
=
this
.
createExtensionConfiguration
();
const
documentTracker
=
new
DocumentTracker
();
this
.
services
.
push
(
documentTracker
,
new
CommandHandler
(
this
.
context
,
documentTracker
),
new
CodeLensProvider
(
this
.
context
,
documentTracker
),
new
ContentProvider
(
this
.
context
),
new
Decorator
(
this
.
context
,
documentTracker
),
);
this
.
services
.
forEach
((
service
:
any
)
=>
{
if
(
service
.
begin
&&
service
.
begin
instanceof
Function
)
{
service
.
begin
(
configuration
);
}
});
vscode
.
workspace
.
onDidChangeConfiguration
(()
=>
{
this
.
services
.
forEach
((
service
:
any
)
=>
{
if
(
service
.
configurationUpdated
&&
service
.
configurationUpdated
instanceof
Function
)
{
service
.
configurationUpdated
(
this
.
createExtensionConfiguration
());
}
});
});
}
createExtensionConfiguration
():
interfaces
.
IExtensionConfiguration
{
const
workspaceConfiguration
=
vscode
.
workspace
.
getConfiguration
(
ConfigurationSectionName
);
const
codeLensEnabled
:
boolean
=
workspaceConfiguration
.
get
(
'
codeLens.enabled
'
,
true
);
const
decoratorsEnabled
:
boolean
=
workspaceConfiguration
.
get
(
'
decorators.enabled
'
,
true
);
return
{
enableCodeLens
:
codeLensEnabled
,
enableDecorations
:
decoratorsEnabled
,
enableEditorOverview
:
decoratorsEnabled
};
}
dispose
()
{
this
.
services
.
forEach
(
disposable
=>
disposable
.
dispose
());
this
.
services
=
[];
}
}
extensions/merge-conflict/src/typings/refs.d.ts
0 → 100644
浏览文件 @
6daf4d36
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference types='@types/node'/>
/// <reference types='@types/mocha'/>
extensions/merge-conflict/tsconfig.json
0 → 100644
浏览文件 @
6daf4d36
{
"compilerOptions"
:
{
"target"
:
"es6"
,
"lib"
:
[
"es2016"
],
"module"
:
"commonjs"
,
"outDir"
:
"./out"
,
"strictNullChecks"
:
true
,
"experimentalDecorators"
:
true
},
"include"
:
[
"src/**/*"
]
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录