Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
5a27354d
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
5a27354d
编写于
3月 21, 2018
作者:
J
Joao Moreno
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'url-service'
上级
826ea063
94125f91
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
319 addition
and
130 deletion
+319
-130
src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
.../code/electron-browser/sharedProcess/sharedProcessMain.ts
+1
-24
src/vs/code/electron-main/app.ts
src/vs/code/electron-main/app.ts
+23
-7
src/vs/code/electron-main/launch.ts
src/vs/code/electron-main/launch.ts
+37
-13
src/vs/code/electron-main/main.ts
src/vs/code/electron-main/main.ts
+2
-2
src/vs/code/electron-main/windows.ts
src/vs/code/electron-main/windows.ts
+2
-2
src/vs/platform/url/common/url.ts
src/vs/platform/url/common/url.ts
+9
-3
src/vs/platform/url/common/urlIpc.ts
src/vs/platform/url/common/urlIpc.ts
+40
-36
src/vs/platform/url/common/urlService.ts
src/vs/platform/url/common/urlService.ts
+54
-0
src/vs/platform/url/electron-main/electronUrlListener.ts
src/vs/platform/url/electron-main/electronUrlListener.ts
+88
-0
src/vs/platform/windows/common/windows.ts
src/vs/platform/windows/common/windows.ts
+24
-0
src/vs/platform/windows/electron-main/windows.ts
src/vs/platform/windows/electron-main/windows.ts
+1
-1
src/vs/platform/windows/electron-main/windowsService.ts
src/vs/platform/windows/electron-main/windowsService.ts
+15
-31
src/vs/workbench/electron-browser/main.ts
src/vs/workbench/electron-browser/main.ts
+10
-4
src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts
...bench/parts/extensions/node/extensionsWorkbenchService.ts
+13
-7
未找到文件。
src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
浏览文件 @
5a27354d
...
...
@@ -30,10 +30,9 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
import
{
TelemetryAppenderChannel
}
from
'
vs/platform/telemetry/common/telemetryIpc
'
;
import
{
TelemetryService
,
ITelemetryServiceConfig
}
from
'
vs/platform/telemetry/common/telemetryService
'
;
import
{
AppInsightsAppender
}
from
'
vs/platform/telemetry/node/appInsightsAppender
'
;
import
{
IWindowsService
}
from
'
vs/platform/windows/common/windows
'
;
import
{
IWindowsService
,
ActiveWindowManager
}
from
'
vs/platform/windows/common/windows
'
;
import
{
WindowsChannelClient
}
from
'
vs/platform/windows/common/windowsIpc
'
;
import
{
ipcRenderer
}
from
'
electron
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
createSharedProcessContributions
}
from
'
vs/code/electron-browser/sharedProcess/contrib/contributions
'
;
import
{
createSpdLogService
}
from
'
vs/platform/log/node/spdlogService
'
;
import
{
ILogService
,
LogLevel
}
from
'
vs/platform/log/common/log
'
;
...
...
@@ -58,28 +57,6 @@ interface ISharedProcessInitData {
logLevel
:
LogLevel
;
}
class
ActiveWindowManager
implements
IDisposable
{
private
disposables
:
IDisposable
[]
=
[];
private
_activeWindowId
:
number
;
constructor
(@
IWindowsService
windowsService
:
IWindowsService
)
{
windowsService
.
onWindowOpen
(
this
.
setActiveWindow
,
this
,
this
.
disposables
);
windowsService
.
onWindowFocus
(
this
.
setActiveWindow
,
this
,
this
.
disposables
);
}
private
setActiveWindow
(
windowId
:
number
)
{
this
.
_activeWindowId
=
windowId
;
}
public
get
activeClientId
():
string
{
return
`window:
${
this
.
_activeWindowId
}
`
;
}
public
dispose
()
{
this
.
disposables
=
dispose
(
this
.
disposables
);
}
}
const
eventPrefix
=
'
monacoworkbench
'
;
function
main
(
server
:
Server
,
initData
:
ISharedProcessInitData
,
configuration
:
ISharedProcessConfiguration
):
void
{
...
...
src/vs/code/electron-main/app.ts
浏览文件 @
5a27354d
...
...
@@ -8,7 +8,7 @@
import
{
app
,
ipcMain
as
ipc
,
BrowserWindow
}
from
'
electron
'
;
import
*
as
platform
from
'
vs/base/common/platform
'
;
import
{
WindowsManager
}
from
'
vs/code/electron-main/windows
'
;
import
{
IWindowsService
,
OpenContext
}
from
'
vs/platform/windows/common/windows
'
;
import
{
IWindowsService
,
OpenContext
,
ActiveWindowManager
}
from
'
vs/platform/windows/common/windows
'
;
import
{
WindowsChannel
}
from
'
vs/platform/windows/common/windowsIpc
'
;
import
{
WindowsService
}
from
'
vs/platform/windows/electron-main/windowsService
'
;
import
{
ILifecycleService
}
from
'
vs/platform/lifecycle/electron-main/lifecycleMain
'
;
...
...
@@ -29,7 +29,7 @@ import { IStateService } from 'vs/platform/state/common/state';
import
{
IEnvironmentService
}
from
'
vs/platform/environment/common/environment
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
URLChannel
}
from
'
vs/platform/url/common/urlIpc
'
;
import
{
URL
HandlerChannelClient
,
URLService
Channel
}
from
'
vs/platform/url/common/urlIpc
'
;
import
{
ITelemetryService
}
from
'
vs/platform/telemetry/common/telemetry
'
;
import
{
NullTelemetryService
}
from
'
vs/platform/telemetry/common/telemetryUtils
'
;
import
{
ITelemetryAppenderChannel
,
TelemetryAppenderClient
}
from
'
vs/platform/telemetry/common/telemetryIpc
'
;
...
...
@@ -59,6 +59,7 @@ import { IssueChannel } from 'vs/platform/issue/common/issueIpc';
import
{
IssueService
}
from
'
vs/platform/issue/electron-main/issueService
'
;
import
{
LogLevelSetterChannel
}
from
'
vs/platform/log/common/logIpc
'
;
import
{
setUnexpectedErrorHandler
}
from
'
vs/base/common/errors
'
;
import
{
ElectronURLListener
}
from
'
vs/platform/url/electron-main/electronUrlListener
'
;
export
class
CodeApplication
{
...
...
@@ -355,10 +356,6 @@ export class CodeApplication {
const
updateChannel
=
new
UpdateChannel
(
updateService
);
this
.
electronIpcServer
.
registerChannel
(
'
update
'
,
updateChannel
);
const
urlService
=
accessor
.
get
(
IURLService
);
const
urlChannel
=
appInstantiationService
.
createInstance
(
URLChannel
,
urlService
);
this
.
electronIpcServer
.
registerChannel
(
'
url
'
,
urlChannel
);
const
issueService
=
accessor
.
get
(
IIssueService
);
const
issueChannel
=
new
IssueChannel
(
issueService
);
this
.
electronIpcServer
.
registerChannel
(
'
issue
'
,
issueChannel
);
...
...
@@ -372,6 +369,10 @@ export class CodeApplication {
this
.
electronIpcServer
.
registerChannel
(
'
windows
'
,
windowsChannel
);
this
.
sharedProcessClient
.
done
(
client
=>
client
.
registerChannel
(
'
windows
'
,
windowsChannel
));
const
urlService
=
accessor
.
get
(
IURLService
);
const
urlChannel
=
new
URLServiceChannel
(
urlService
);
this
.
electronIpcServer
.
registerChannel
(
'
url
'
,
urlChannel
);
// Log level management
const
logLevelChannel
=
new
LogLevelSetterChannel
(
accessor
.
get
(
ILogService
));
this
.
electronIpcServer
.
registerChannel
(
'
loglevel
'
,
logLevelChannel
);
...
...
@@ -382,10 +383,25 @@ export class CodeApplication {
// Propagate to clients
this
.
windowsMainService
=
accessor
.
get
(
IWindowsMainService
);
// TODO@Joao: unfold this
const
args
=
this
.
environmentService
.
args
;
// Create a URL handler which forwards to the last active window
const
activeWindowManager
=
new
ActiveWindowManager
(
windowsService
);
const
urlHandlerChannel
=
this
.
electronIpcServer
.
getChannel
(
'
urlHandler
'
,
{
route
:
()
=>
activeWindowManager
.
activeClientId
});
const
multiplexURLHandler
=
new
URLHandlerChannelClient
(
urlHandlerChannel
);
// Register the multiple URL handker
urlService
.
registerHandler
(
multiplexURLHandler
);
// Watch Electron URLs and forward them to the UrlService
const
urls
=
args
[
'
open-url
'
]
?
args
.
_urls
:
[];
const
urlListener
=
new
ElectronURLListener
(
urls
,
urlService
,
this
.
windowsMainService
);
this
.
toDispose
.
push
(
urlListener
);
this
.
windowsMainService
.
ready
(
this
.
userEnv
);
// Open our first window
const
args
=
this
.
environmentService
.
args
;
const
context
=
!!
process
.
env
[
'
VSCODE_CLI
'
]
?
OpenContext
.
CLI
:
OpenContext
.
DESKTOP
;
if
(
args
[
'
new-window
'
]
&&
args
.
_
.
length
===
0
)
{
this
.
windowsMainService
.
open
({
context
,
cli
:
args
,
forceNewWindow
:
true
,
forceEmpty
:
true
,
initialStartup
:
true
});
// new window if "-n" was used without paths
...
...
src/vs/code/electron-main/launch.ts
浏览文件 @
5a27354d
...
...
@@ -18,6 +18,7 @@ import { whenDeleted } from 'vs/base/node/pfs';
import
{
IWorkspacesMainService
}
from
'
vs/platform/workspaces/common/workspaces
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
{
IConfigurationService
}
from
'
vs/platform/configuration/common/configuration
'
;
import
URI
from
'
../../base/common/uri
'
;
export
const
ID
=
'
launchService
'
;
export
const
ILaunchService
=
createDecorator
<
ILaunchService
>
(
ID
);
...
...
@@ -39,6 +40,24 @@ export interface IMainProcessInfo {
windows
:
IWindowInfo
[];
}
function
parseOpenUrl
(
args
:
ParsedArgs
):
URI
[]
{
if
(
args
[
'
open-url
'
]
&&
args
.
_urls
&&
args
.
_urls
.
length
>
0
)
{
// --open-url must contain -- followed by the url(s)
// process.argv is used over args._ as args._ are resolved to file paths at this point
return
args
.
_urls
.
map
(
url
=>
{
try
{
return
URI
.
parse
(
url
);
}
catch
(
err
)
{
return
null
;
}
})
.
filter
(
uri
=>
!!
uri
);
}
return
[];
}
export
interface
ILaunchService
{
_serviceBrand
:
any
;
start
(
args
:
ParsedArgs
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
;
...
...
@@ -118,25 +137,30 @@ export class LaunchService implements ILaunchService {
public
start
(
args
:
ParsedArgs
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
{
this
.
logService
.
trace
(
'
Received data from other instance:
'
,
args
,
userEnv
);
const
urlsToOpen
=
parseOpenUrl
(
args
);
// Check early for open-url which is handled in URL service
if
(
this
.
shouldOpenUrl
(
args
))
{
return
TPromise
.
as
(
null
);
}
if
(
urlsToOpen
.
length
)
{
let
whenWindowReady
=
TPromise
.
as
<
any
>
(
null
);
// Otherwise handle in windows service
return
this
.
startOpenWindow
(
args
,
userEnv
);
}
// Create a window if there is none
if
(
this
.
windowsMainService
.
getWindowCount
()
===
0
)
{
const
window
=
this
.
windowsMainService
.
openNewWindow
(
OpenContext
.
DESKTOP
)[
0
];
whenWindowReady
=
window
.
ready
();
}
private
shouldOpenUrl
(
args
:
ParsedArgs
):
boolean
{
if
(
args
[
'
open-url
'
]
&&
args
.
_urls
&&
args
.
_urls
.
length
>
0
)
{
// --open-url must contain -- followed by the url(s)
// process.argv is used over args._ as args._ are resolved to file paths at this point
args
.
_urls
.
forEach
(
url
=>
this
.
urlService
.
open
(
url
));
// Make sure a window is open, ready to receive the url event
whenWindowReady
.
then
(()
=>
{
for
(
const
url
of
urlsToOpen
)
{
this
.
urlService
.
open
(
url
);
}
});
return
true
;
return
TPromise
.
as
(
null
)
;
}
return
false
;
// Otherwise handle in windows service
return
this
.
startOpenWindow
(
args
,
userEnv
);
}
private
startOpenWindow
(
args
:
ParsedArgs
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
{
...
...
src/vs/code/electron-main/main.ts
浏览文件 @
5a27354d
...
...
@@ -34,7 +34,7 @@ import { ConfigurationService } from 'vs/platform/configuration/node/configurati
import
{
IRequestService
}
from
'
vs/platform/request/node/request
'
;
import
{
RequestService
}
from
'
vs/platform/request/electron-main/requestService
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
URLService
}
from
'
vs/platform/url/
electron-mai
n/urlService
'
;
import
{
URLService
}
from
'
vs/platform/url/
commo
n/urlService
'
;
import
*
as
fs
from
'
original-fs
'
;
import
{
CodeApplication
}
from
'
vs/code/electron-main/app
'
;
import
{
HistoryMainService
}
from
'
vs/platform/history/electron-main/historyMainService
'
;
...
...
@@ -71,7 +71,7 @@ function createServices(args: ParsedArgs, bufferLogService: BufferLogService): I
services
.
set
(
IStateService
,
new
SyncDescriptor
(
StateService
));
services
.
set
(
IConfigurationService
,
new
SyncDescriptor
(
ConfigurationService
));
services
.
set
(
IRequestService
,
new
SyncDescriptor
(
RequestService
));
services
.
set
(
IURLService
,
new
SyncDescriptor
(
URLService
,
args
[
'
open-url
'
]
?
args
.
_urls
:
[]
));
services
.
set
(
IURLService
,
new
SyncDescriptor
(
URLService
));
services
.
set
(
IBackupMainService
,
new
SyncDescriptor
(
BackupMainService
));
services
.
set
(
IDialogService
,
new
SyncDescriptor
(
CommandLineDialogService
));
...
...
src/vs/code/electron-main/windows.ts
浏览文件 @
5a27354d
...
...
@@ -1375,8 +1375,8 @@ export class WindowsManager implements IWindowsMainService {
return
getLastActiveWindow
(
WindowsManager
.
WINDOWS
);
}
public
openNewWindow
(
context
:
OpenContext
):
void
{
this
.
open
({
context
,
cli
:
this
.
environmentService
.
args
,
forceNewWindow
:
true
,
forceEmpty
:
true
});
public
openNewWindow
(
context
:
OpenContext
):
ICodeWindow
[]
{
return
this
.
open
({
context
,
cli
:
this
.
environmentService
.
args
,
forceNewWindow
:
true
,
forceEmpty
:
true
});
}
public
waitForWindowCloseOrLoad
(
windowId
:
number
):
TPromise
<
void
>
{
...
...
src/vs/platform/url/common/url.ts
浏览文件 @
5a27354d
...
...
@@ -5,15 +5,21 @@
'
use strict
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
export
const
ID
=
'
urlService
'
;
export
const
IURLService
=
createDecorator
<
IURLService
>
(
ID
);
export
interface
IURLHandler
{
handleURL
(
uri
:
URI
):
TPromise
<
boolean
>
;
}
export
interface
IURLService
{
_serviceBrand
:
any
;
open
(
url
:
string
):
void
;
onOpenURL
:
Event
<
URI
>
;
open
(
url
:
URI
):
TPromise
<
boolean
>
;
registerHandler
(
handler
:
IURLHandler
):
IDisposable
;
}
src/vs/platform/url/common/urlIpc.ts
浏览文件 @
5a27354d
...
...
@@ -6,61 +6,65 @@
'
use strict
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IChannel
,
eventToCall
,
eventFromCall
,
Serializer
,
Deserializer
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
{
IURLService
}
from
'
./url
'
;
import
{
Event
,
filterEvent
}
from
'
vs/base/common/event
'
;
import
{
IWindowsService
}
from
'
vs/platform/windows/common/windows
'
;
import
{
IChannel
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
{
IURLHandler
,
IURLService
}
from
'
./url
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
const
URISerializer
:
Serializer
<
URI
,
any
>
=
uri
=>
uri
.
toJSON
();
const
URIDeserializer
:
Deserializer
<
URI
,
any
>
=
raw
=>
URI
.
revive
(
raw
);
export
interface
IURLChannel
extends
IChannel
{
call
(
command
:
'
event:onOpenURL
'
):
TPromise
<
void
>
;
export
interface
IURLServiceChannel
extends
IChannel
{
call
(
command
:
'
open
'
,
url
:
string
):
TPromise
<
boolean
>
;
call
(
command
:
string
,
arg
?:
any
):
TPromise
<
any
>
;
}
export
class
URLChannel
implements
IURLChannel
{
private
focusedWindowId
:
number
;
export
class
URLServiceChannel
implements
IURLServiceChannel
{
constructor
(
private
service
:
IURLService
,
@
IWindowsService
windowsService
:
IWindowsService
)
{
windowsService
.
onWindowFocus
(
id
=>
this
.
focusedWindowId
=
id
);
}
constructor
(
private
service
:
IURLService
)
{
}
call
(
command
:
string
,
arg
?:
any
):
TPromise
<
any
>
{
switch
(
command
)
{
case
'
event:onOpenURL
'
:
return
eventToCall
(
filterEvent
(
this
.
service
.
onOpenURL
,
()
=>
this
.
isWindowFocused
(
arg
)),
URISerializer
);
case
'
open
'
:
return
this
.
service
.
open
(
URI
.
revive
(
arg
)
);
}
return
undefined
;
}
}
export
class
URLServiceChannelClient
implements
IURLService
{
/**
* We only want the focused window to get pinged with the onOpenUrl event.
* The idea here is to filter the onOpenUrl event with the knowledge of which
* was the last window to be focused. When first listening to the event,
* each client sends its window ID via the arguments to `call(...)`.
* When the event fires, the server has enough knowledge to filter the event
* and fire it only to the focused window.
*/
private
isWindowFocused
(
windowID
:
number
):
boolean
{
return
this
.
focusedWindowId
===
windowID
;
_serviceBrand
:
any
;
constructor
(
private
channel
:
IChannel
)
{
}
open
(
url
:
URI
):
TPromise
<
boolean
,
any
>
{
return
this
.
channel
.
call
(
'
open
'
,
url
.
toJSON
());
}
registerHandler
(
handler
:
IURLHandler
):
IDisposable
{
throw
new
Error
(
'
Not implemented.
'
)
;
}
}
export
class
URLChannelClient
implements
IURLService
{
export
interface
IURLHandlerChannel
extends
IChannel
{
call
(
command
:
'
handleURL
'
,
arg
:
any
):
TPromise
<
boolean
>
;
call
(
command
:
string
,
arg
?:
any
):
TPromise
<
any
>
;
}
_serviceBrand
:
any
;
export
class
URLHandlerChannel
implements
IURLHandlerChannel
{
constructor
(
private
handler
:
IURLHandler
)
{
}
call
(
command
:
string
,
arg
?:
any
):
TPromise
<
any
>
{
switch
(
command
)
{
case
'
handleURL
'
:
return
this
.
handler
.
handleURL
(
URI
.
revive
(
arg
));
}
return
undefined
;
}
}
constructor
(
private
channel
:
IChannel
,
private
windowID
:
number
)
{
}
export
class
URLHandlerChannelClient
implements
IURLHandler
{
private
_onOpenURL
=
eventFromCall
<
URI
>
(
this
.
channel
,
'
event:onOpenURL
'
,
this
.
windowID
,
URIDeserializer
);
get
onOpenURL
():
Event
<
URI
>
{
return
this
.
_onOpenURL
;
}
constructor
(
private
channel
:
IChannel
)
{
}
open
(
url
:
string
):
void
{
return
;
// not implemented
handleURL
(
uri
:
URI
):
TPromise
<
boolean
>
{
return
this
.
channel
.
call
(
'
handleURL
'
,
uri
.
toJSON
());
}
}
\ No newline at end of file
src/vs/platform/url/common/urlService.ts
0 → 100644
浏览文件 @
5a27354d
/*---------------------------------------------------------------------------------------------
* 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
{
IURLService
,
IURLHandler
}
from
'
vs/platform/url/common/url
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
IDisposable
,
toDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
declare
module
Array
{
function
from
<
T
>
(
set
:
Set
<
T
>
):
T
[];
}
export
class
URLService
implements
IURLService
{
_serviceBrand
:
any
;
private
handlers
=
new
Set
<
IURLHandler
>
();
async
open
(
uri
:
URI
):
TPromise
<
boolean
>
{
const
handlers
=
Array
.
from
(
this
.
handlers
);
for
(
const
handler
of
handlers
)
{
if
(
await
handler
.
handleURL
(
uri
))
{
return
true
;
}
}
return
false
;
}
registerHandler
(
handler
:
IURLHandler
):
IDisposable
{
this
.
handlers
.
add
(
handler
);
return
toDisposable
(()
=>
this
.
handlers
.
delete
(
handler
));
}
}
export
class
RelayURLService
extends
URLService
implements
IURLHandler
{
constructor
(
private
urlService
:
IURLService
)
{
super
();
}
async
open
(
uri
:
URI
):
TPromise
<
boolean
>
{
return
this
.
urlService
.
open
(
uri
);
}
handleURL
(
uri
:
URI
):
TPromise
<
boolean
>
{
return
super
.
open
(
uri
);
}
}
\ No newline at end of file
src/vs/platform/url/electron-main/
urlService
.ts
→
src/vs/platform/url/electron-main/
electronUrlListener
.ts
浏览文件 @
5a27354d
...
...
@@ -5,57 +5,84 @@
'
use strict
'
;
import
{
Event
,
mapEvent
,
chain
,
echo
,
Emitter
,
anyEvent
,
fromNodeEventEmitter
}
from
'
vs/base/common/event
'
;
import
{
mapEvent
,
fromNodeEventEmitter
,
filterEvent
}
from
'
vs/base/common/event
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
product
from
'
vs/platform/node/product
'
;
import
{
app
}
from
'
electron
'
;
import
URI
from
'
vs/base/common/uri
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
IWindowsMainService
}
from
'
vs/platform/windows/electron-main/windows
'
;
import
{
ReadyState
}
from
'
vs/platform/windows/common/windows
'
;
export
class
URLService
implements
IURLService
{
function
uriFromRawUrl
(
url
:
string
):
URI
|
null
{
try
{
return
URI
.
parse
(
url
);
}
catch
(
e
)
{
return
null
;
}
}
_serviceBrand
:
any
;
export
class
ElectronURLListener
{
private
readonly
openUrlEmitter
:
Emitter
<
string
>
=
new
Emitter
<
string
>
()
;
onOpenURL
:
Event
<
URI
>
;
private
buffer
:
URI
[]
=
[]
;
private
disposables
:
IDisposable
[]
=
[]
;
constructor
(
initial
:
string
|
string
[],
@
ILogService
private
logService
:
ILogService
@
IURLService
private
urlService
:
IURLService
,
@
IWindowsMainService
private
windowsService
:
IWindowsMainService
)
{
const
globalBuffer
=
(
global
.
getOpenUrls
()
||
[])
as
string
[];
const
initial
Buffer
=
[
const
raw
Buffer
=
[
...(
typeof
initial
===
'
string
'
?
[
initial
]
:
initial
),
...
globalBuffer
];
this
.
buffer
=
rawBuffer
.
map
(
uriFromRawUrl
).
filter
(
uri
=>
!!
uri
);
app
.
setAsDefaultProtocolClient
(
product
.
urlProtocol
,
process
.
execPath
,
[
'
--open-url
'
,
'
--
'
]);
const
rawOnOpenUrl
=
fromNodeEventEmitter
(
app
,
'
open-url
'
,
(
event
:
Electron
.
Event
,
url
:
string
)
=>
({
event
,
url
}));
const
onOpenElectronUrl
=
mapEvent
(
fromNodeEventEmitter
(
app
,
'
open-url
'
,
(
event
:
Electron
.
Event
,
url
:
string
)
=>
({
event
,
url
})),
({
event
,
url
})
=>
{
// always prevent default and return the url as string
event
.
preventDefault
();
return
url
;
});
// always prevent default and return the url as string
const
preventedOnOpenUrl
=
mapEvent
(
rawOnOpenUrl
,
({
event
,
url
})
=>
{
event
.
preventDefault
();
return
url
;
});
const
onOpenUrl
=
filterEvent
(
mapEvent
(
onOpenElectronUrl
,
uriFromRawUrl
),
uri
=>
!!
uri
);
onOpenUrl
(
this
.
open
,
this
,
this
.
disposables
);
this
.
windowsService
.
onWindowReady
(
this
.
flushBuffer
,
this
,
this
.
disposables
);
this
.
flushBuffer
();
}
// echo all `onOpenUrl` events to each listener
const
bufferedOnOpenUrl
=
echo
(
preventedOnOpenUrl
,
true
,
initialBuffer
);
private
open
(
uri
:
URI
):
void
{
const
shouldBuffer
=
this
.
windowsService
.
getWindows
()
.
filter
(
w
=>
w
.
readyState
===
ReadyState
.
READY
)
.
length
===
0
;
this
.
onOpenURL
=
chain
(
anyEvent
(
bufferedOnOpenUrl
,
this
.
openUrlEmitter
.
event
))
.
map
(
url
=>
{
try
{
return
URI
.
parse
(
url
);
}
catch
(
e
)
{
return
null
;
if
(
shouldBuffer
)
{
this
.
buffer
.
push
(
uri
);
}
else
{
this
.
urlService
.
open
(
uri
).
then
(
handled
=>
{
if
(
!
handled
)
{
this
.
buffer
.
push
(
uri
)
;
}
})
.
filter
(
uri
=>
!!
uri
)
.
event
;
});
}
}
open
(
url
:
string
):
void
{
this
.
logService
.
trace
(
'
urlService#open
'
,
url
);
this
.
openUrlEmitter
.
fire
(
url
);
private
flushBuffer
():
void
{
const
buffer
=
this
.
buffer
;
this
.
buffer
=
[];
for
(
const
uri
of
buffer
)
{
this
.
open
(
uri
);
}
}
}
dispose
():
void
{
this
.
disposables
=
dispose
(
this
.
disposables
);
}
}
\ No newline at end of file
src/vs/platform/windows/common/windows.ts
浏览文件 @
5a27354d
...
...
@@ -16,6 +16,7 @@ import { IRecentlyOpened } from 'vs/platform/history/common/history';
import
{
ICommandAction
}
from
'
vs/platform/actions/common/actions
'
;
import
{
PerformanceEntry
}
from
'
vs/base/common/performance
'
;
import
{
LogLevel
}
from
'
vs/platform/log/common/log
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
export
const
IWindowsService
=
createDecorator
<
IWindowsService
>
(
'
windowsService
'
);
...
...
@@ -333,3 +334,26 @@ export interface IRunActionInWindowRequest {
id
:
string
;
from
:
'
menu
'
|
'
touchbar
'
|
'
mouse
'
;
}
export
class
ActiveWindowManager
implements
IDisposable
{
private
disposables
:
IDisposable
[]
=
[];
private
_activeWindowId
:
number
;
constructor
(@
IWindowsService
windowsService
:
IWindowsService
)
{
windowsService
.
onWindowOpen
(
this
.
setActiveWindow
,
this
,
this
.
disposables
);
windowsService
.
onWindowFocus
(
this
.
setActiveWindow
,
this
,
this
.
disposables
);
}
private
setActiveWindow
(
windowId
:
number
)
{
this
.
_activeWindowId
=
windowId
;
}
get
activeClientId
():
string
{
return
`window:
${
this
.
_activeWindowId
}
`
;
}
dispose
()
{
this
.
disposables
=
dispose
(
this
.
disposables
);
}
}
\ No newline at end of file
src/vs/platform/windows/electron-main/windows.ts
浏览文件 @
5a27354d
...
...
@@ -107,7 +107,7 @@ export interface IWindowsMainService {
focusLastActive
(
cli
:
ParsedArgs
,
context
:
OpenContext
):
ICodeWindow
;
getLastActiveWindow
():
ICodeWindow
;
waitForWindowCloseOrLoad
(
windowId
:
number
):
TPromise
<
void
>
;
openNewWindow
(
context
:
OpenContext
):
void
;
openNewWindow
(
context
:
OpenContext
):
ICodeWindow
[]
;
sendToFocused
(
channel
:
string
,
...
args
:
any
[]):
void
;
sendToAll
(
channel
:
string
,
payload
:
any
,
windowIdsToIgnore
?:
number
[]):
void
;
getFocusedWindow
():
ICodeWindow
;
...
...
src/vs/platform/windows/electron-main/windowsService.ts
浏览文件 @
5a27354d
...
...
@@ -14,8 +14,8 @@ import product from 'vs/platform/node/product';
import
{
IWindowsService
,
OpenContext
,
INativeOpenDialogOptions
,
IEnterWorkspaceResult
,
IMessageBoxResult
}
from
'
vs/platform/windows/common/windows
'
;
import
{
IEnvironmentService
,
ParsedArgs
}
from
'
vs/platform/environment/common/environment
'
;
import
{
shell
,
crashReporter
,
app
,
Menu
,
clipboard
}
from
'
electron
'
;
import
{
Event
,
chain
,
fromNodeEventEmitter
}
from
'
vs/base/common/event
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
Event
,
fromNodeEventEmitter
}
from
'
vs/base/common/event
'
;
import
{
IURLService
,
IURLHandler
}
from
'
vs/platform/url/common/url
'
;
import
{
ILifecycleService
}
from
'
vs/platform/lifecycle/electron-main/lifecycleMain
'
;
import
{
IWindowsMainService
,
ISharedProcess
}
from
'
vs/platform/windows/electron-main/windows
'
;
import
{
IHistoryMainService
,
IRecentlyOpened
}
from
'
vs/platform/history/common/history
'
;
...
...
@@ -26,7 +26,7 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels';
import
{
isWindows
}
from
'
vs/base/common/platform
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
export
class
WindowsService
implements
IWindowsService
,
IDisposable
{
export
class
WindowsService
implements
IWindowsService
,
I
URLHandler
,
I
Disposable
{
_serviceBrand
:
any
;
...
...
@@ -45,17 +45,7 @@ export class WindowsService implements IWindowsService, IDisposable {
@
IHistoryMainService
private
historyService
:
IHistoryMainService
,
@
ILogService
private
logService
:
ILogService
)
{
// Catch file URLs
chain
(
urlService
.
onOpenURL
)
.
filter
(
uri
=>
uri
.
authority
===
Schemas
.
file
&&
!!
uri
.
path
)
.
map
(
uri
=>
URI
.
file
(
uri
.
fsPath
))
.
on
(
this
.
openFileForURI
,
this
,
this
.
disposables
);
// Catch extension URLs when there are no windows open
chain
(
urlService
.
onOpenURL
)
.
filter
(
uri
=>
/^extension/
.
test
(
uri
.
path
))
.
filter
(()
=>
this
.
windowsMainService
.
getWindowCount
()
===
0
)
.
on
(
this
.
openExtensionForURI
,
this
,
this
.
disposables
);
urlService
.
registerHandler
(
this
);
}
pickFileFolderAndOpen
(
options
:
INativeOpenDialogOptions
):
TPromise
<
void
>
{
...
...
@@ -496,27 +486,21 @@ export class WindowsService implements IWindowsService, IDisposable {
return
TPromise
.
as
(
null
);
}
private
openFileForURI
(
uri
:
URI
):
TPromise
<
void
>
{
const
cli
=
assign
(
Object
.
create
(
null
),
this
.
environmentService
.
args
,
{
goto
:
true
});
const
pathsToOpen
=
[
uri
.
fsPath
];
async
handleURL
(
uri
:
URI
):
TPromise
<
boolean
>
{
// Catch file URLs
if
(
uri
.
authority
===
Schemas
.
file
&&
!!
uri
.
path
)
{
return
this
.
openFileForURI
(
URI
.
file
(
uri
.
fsPath
));
}
this
.
windowsMainService
.
open
({
context
:
OpenContext
.
API
,
cli
,
pathsToOpen
});
return
TPromise
.
as
(
null
);
return
false
;
}
/**
* This should only fire whenever an extension URL is open
* and there are no windows to handle it.
*/
private
async
openExtensionForURI
(
uri
:
URI
):
TPromise
<
void
>
{
const
cli
=
assign
(
Object
.
create
(
null
),
this
.
environmentService
.
args
);
const
window
=
await
this
.
windowsMainService
.
open
({
context
:
OpenContext
.
API
,
cli
})[
0
];
if
(
!
window
)
{
return
;
}
private
async
openFileForURI
(
uri
:
URI
):
TPromise
<
boolean
>
{
const
cli
=
assign
(
Object
.
create
(
null
),
this
.
environmentService
.
args
,
{
goto
:
true
});
const
pathsToOpen
=
[
uri
.
fsPath
];
window
.
win
.
show
();
this
.
windowsMainService
.
open
({
context
:
OpenContext
.
API
,
cli
,
pathsToOpen
});
return
true
;
}
dispose
():
void
{
...
...
src/vs/workbench/electron-browser/main.ts
浏览文件 @
5a27354d
...
...
@@ -36,17 +36,18 @@ import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/
import
{
webFrame
}
from
'
electron
'
;
import
{
UpdateChannelClient
}
from
'
vs/platform/update/common/updateIpc
'
;
import
{
IUpdateService
}
from
'
vs/platform/update/common/update
'
;
import
{
URLChannelClient
}
from
'
vs/platform/url/common/urlIpc
'
;
import
{
URL
HandlerChannel
,
URLService
ChannelClient
}
from
'
vs/platform/url/common/urlIpc
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
WorkspacesChannelClient
}
from
'
vs/platform/workspaces/common/workspacesIpc
'
;
import
{
IWorkspacesService
}
from
'
vs/platform/workspaces/common/workspaces
'
;
import
{
createSpdLogService
}
from
'
vs/platform/log/node/spdlogService
'
;
import
*
as
fs
from
'
fs
'
;
import
{
ConsoleLogService
,
MultiplexLogService
,
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IssueChannelClient
}
from
'
vs/platform/issue/common/issueIpc
'
;
import
{
IIssueService
}
from
'
vs/platform/issue/common/issue
'
;
import
{
LogLevelSetterChannelClient
,
FollowerLogService
}
from
'
vs/platform/log/common/logIpc
'
;
import
{
RelayURLService
}
from
'
vs/platform/url/common/urlService
'
;
gracefulFs
.
gracefulify
(
fs
);
// enable gracefulFs
export
function
startup
(
configuration
:
IWindowConfiguration
):
TPromise
<
void
>
{
...
...
@@ -72,7 +73,7 @@ export function startup(configuration: IWindowConfiguration): TPromise<void> {
}
function
openWorkbench
(
configuration
:
IWindowConfiguration
):
TPromise
<
void
>
{
const
mainProcessClient
=
new
ElectronIPCClient
(
String
(
`window
${
configuration
.
windowId
}
`
)
);
const
mainProcessClient
=
new
ElectronIPCClient
(
`window:
${
configuration
.
windowId
}
`
);
const
mainServices
=
createMainProcessServices
(
mainProcessClient
,
configuration
);
const
environmentService
=
new
EnvironmentService
(
configuration
,
configuration
.
execPath
);
...
...
@@ -216,7 +217,12 @@ function createMainProcessServices(mainProcessClient: ElectronIPCClient, configu
serviceCollection
.
set
(
IUpdateService
,
new
SyncDescriptor
(
UpdateChannelClient
,
updateChannel
));
const
urlChannel
=
mainProcessClient
.
getChannel
(
'
url
'
);
serviceCollection
.
set
(
IURLService
,
new
SyncDescriptor
(
URLChannelClient
,
urlChannel
,
configuration
.
windowId
));
const
mainUrlService
=
new
URLServiceChannelClient
(
urlChannel
);
const
urlService
=
new
RelayURLService
(
mainUrlService
);
serviceCollection
.
set
(
IURLService
,
urlService
);
const
urlHandlerChannel
=
new
URLHandlerChannel
(
urlService
);
mainProcessClient
.
registerChannel
(
'
urlHandler
'
,
urlHandlerChannel
);
const
issueChannel
=
mainProcessClient
.
getChannel
(
'
issue
'
);
serviceCollection
.
set
(
IIssueService
,
new
SyncDescriptor
(
IssueChannelClient
,
issueChannel
));
...
...
src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts
浏览文件 @
5a27354d
...
...
@@ -9,7 +9,7 @@ import * as nls from 'vs/nls';
import
{
readFile
}
from
'
vs/base/node/pfs
'
;
import
*
as
semver
from
'
semver
'
;
import
*
as
path
from
'
path
'
;
import
{
Event
,
Emitter
,
chain
}
from
'
vs/base/common/event
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
index
}
from
'
vs/base/common/arrays
'
;
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
{
ThrottledDelayer
}
from
'
vs/base/common/async
'
;
...
...
@@ -30,7 +30,7 @@ import Severity from 'vs/base/common/severity';
import
URI
from
'
vs/base/common/uri
'
;
import
{
IExtension
,
IExtensionDependencies
,
ExtensionState
,
IExtensionsWorkbenchService
,
AutoUpdateConfigurationKey
}
from
'
vs/workbench/parts/extensions/common/extensions
'
;
import
{
IWorkbenchEditorService
}
from
'
vs/workbench/services/editor/common/editorService
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
IURLService
,
IURLHandler
}
from
'
vs/platform/url/common/url
'
;
import
{
ExtensionsInput
}
from
'
vs/workbench/parts/extensions/common/extensionsInput
'
;
import
product
from
'
vs/platform/node/product
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
...
...
@@ -345,7 +345,7 @@ function toTelemetryEventName(operation: Operation) {
return
''
;
}
export
class
ExtensionsWorkbenchService
implements
IExtensionsWorkbenchService
{
export
class
ExtensionsWorkbenchService
implements
IExtensionsWorkbenchService
,
IURLHandler
{
private
static
readonly
SyncPeriod
=
1000
*
60
*
60
*
12
;
// 12 hours
...
...
@@ -389,10 +389,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
this
.
syncDelayer
=
new
ThrottledDelayer
<
void
>
(
ExtensionsWorkbenchService
.
SyncPeriod
);
this
.
autoUpdateDelayer
=
new
ThrottledDelayer
<
void
>
(
1000
);
chain
(
urlService
.
onOpenURL
)
.
filter
(
uri
=>
/^extension/
.
test
(
uri
.
path
))
.
on
(
this
.
onOpenExtensionUrl
,
this
,
this
.
disposables
);
urlService
.
registerHandler
(
this
);
this
.
configurationService
.
onDidChangeConfiguration
(
e
=>
{
if
(
e
.
affectsConfiguration
(
AutoUpdateConfigurationKey
))
{
...
...
@@ -970,6 +967,15 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
this
.
notificationService
.
error
(
err
);
}
async
handleURL
(
uri
:
URI
):
TPromise
<
boolean
>
{
if
(
!
/^extension/
.
test
(
uri
.
path
))
{
return
false
;
}
this
.
onOpenExtensionUrl
(
uri
);
return
true
;
}
private
onOpenExtensionUrl
(
uri
:
URI
):
void
{
const
match
=
/^extension
\/([^/]
+
)
$/
.
exec
(
uri
.
path
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录