Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
f4321ecf
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,发现更多精彩内容 >>
提交
f4321ecf
编写于
4月 25, 2016
作者:
J
João Moreno
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #5658 from joaomoreno/main-services
Introduce services in Electron main process
上级
b717d96a
2de4f42d
变更
15
展开全部
隐藏空白更改
内联
并排
Showing
15 changed file
with
906 addition
and
738 deletion
+906
-738
src/vs/workbench/electron-main/auto-updater.linux.ts
src/vs/workbench/electron-main/auto-updater.linux.ts
+12
-9
src/vs/workbench/electron-main/auto-updater.win32.ts
src/vs/workbench/electron-main/auto-updater.win32.ts
+13
-9
src/vs/workbench/electron-main/env.ts
src/vs/workbench/electron-main/env.ts
+201
-157
src/vs/workbench/electron-main/launch.ts
src/vs/workbench/electron-main/launch.ts
+90
-0
src/vs/workbench/electron-main/lifecycle.ts
src/vs/workbench/electron-main/lifecycle.ts
+40
-24
src/vs/workbench/electron-main/log.ts
src/vs/workbench/electron-main/log.ts
+33
-0
src/vs/workbench/electron-main/main.ts
src/vs/workbench/electron-main/main.ts
+99
-138
src/vs/workbench/electron-main/menus.ts
src/vs/workbench/electron-main/menus.ts
+82
-82
src/vs/workbench/electron-main/settings.ts
src/vs/workbench/electron-main/settings.ts
+20
-9
src/vs/workbench/electron-main/sharedProcess.ts
src/vs/workbench/electron-main/sharedProcess.ts
+27
-22
src/vs/workbench/electron-main/storage.ts
src/vs/workbench/electron-main/storage.ts
+68
-50
src/vs/workbench/electron-main/update-manager.ts
src/vs/workbench/electron-main/update-manager.ts
+40
-21
src/vs/workbench/electron-main/window.ts
src/vs/workbench/electron-main/window.ts
+18
-12
src/vs/workbench/electron-main/windows.ts
src/vs/workbench/electron-main/windows.ts
+163
-121
src/vs/workbench/parts/git/electron-main/index.ts
src/vs/workbench/parts/git/electron-main/index.ts
+0
-84
未找到文件。
src/vs/workbench/electron-main/auto-updater.linux.ts
浏览文件 @
f4321ecf
...
...
@@ -6,12 +6,12 @@
'
use strict
'
;
import
events
=
require
(
'
events
'
);
import
{
isString
}
from
'
vs/base/common/types
'
;
import
{
Promise
}
from
'
vs/base/common/winjs.base
'
;
import
{
json
}
from
'
vs/base/node/request
'
;
import
{
isString
}
from
'
vs/base/common/types
'
;
import
{
Promise
}
from
'
vs/base/common/winjs.base
'
;
import
{
json
}
from
'
vs/base/node/request
'
;
import
{
getProxyAgent
}
from
'
vs/base/node/proxy
'
;
import
{
manager
as
Settings
}
from
'
vs/workbench/electron-main/settings
'
;
import
env
=
require
(
'
vs/workbench/electron-main/env
'
)
;
import
{
ISettingsManager
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
IEnvService
}
from
'
vs/workbench/electron-main/env
'
;
export
interface
IUpdate
{
url
:
string
;
...
...
@@ -25,7 +25,10 @@ export class LinuxAutoUpdaterImpl extends events.EventEmitter {
private
url
:
string
;
private
currentRequest
:
Promise
;
constructor
()
{
constructor
(
@
IEnvService
private
envService
:
IEnvService
,
@
ISettingsManager
private
settingsManager
:
ISettingsManager
)
{
super
();
this
.
url
=
null
;
...
...
@@ -47,8 +50,8 @@ export class LinuxAutoUpdaterImpl extends events.EventEmitter {
this
.
emit
(
'
checking-for-update
'
);
const
proxyUrl
=
Settings
.
getValue
(
'
http.proxy
'
);
const
strictSSL
=
Settings
.
getValue
(
'
http.proxyStrictSSL
'
,
true
);
const
proxyUrl
=
this
.
settingsManager
.
getValue
(
'
http.proxy
'
);
const
strictSSL
=
this
.
settingsManager
.
getValue
(
'
http.proxyStrictSSL
'
,
true
);
const
agent
=
getProxyAgent
(
this
.
url
,
{
proxyUrl
,
strictSSL
});
this
.
currentRequest
=
json
<
IUpdate
>
({
url
:
this
.
url
,
agent
})
...
...
@@ -56,7 +59,7 @@ export class LinuxAutoUpdaterImpl extends events.EventEmitter {
if
(
!
update
||
!
update
.
url
||
!
update
.
version
)
{
this
.
emit
(
'
update-not-available
'
);
}
else
{
this
.
emit
(
'
update-available
'
,
null
,
env
.
product
.
downloadUrl
);
this
.
emit
(
'
update-available
'
,
null
,
this
.
envService
.
product
.
downloadUrl
);
}
})
.
then
(
null
,
e
=>
{
...
...
src/vs/workbench/electron-main/auto-updater.win32.ts
浏览文件 @
f4321ecf
...
...
@@ -15,9 +15,9 @@ import { isString } from 'vs/base/common/types';
import
{
Promise
,
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
download
,
json
}
from
'
vs/base/node/request
'
;
import
{
getProxyAgent
}
from
'
vs/base/node/proxy
'
;
import
{
manager
as
Settings
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
manager
as
Lifecycl
e
}
from
'
vs/workbench/electron-main/lifecycle
'
;
import
{
quality
}
from
'
./env
'
;
import
{
ISettingsManager
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
ILifecycleServic
e
}
from
'
vs/workbench/electron-main/lifecycle
'
;
import
{
IEnvService
}
from
'
./env
'
;
export
interface
IUpdate
{
url
:
string
;
...
...
@@ -31,7 +31,11 @@ export class Win32AutoUpdaterImpl extends events.EventEmitter {
private
url
:
string
;
private
currentRequest
:
Promise
;
constructor
()
{
constructor
(
@
ILifecycleService
private
lifecycleService
:
ILifecycleService
,
@
IEnvService
private
envService
:
IEnvService
,
@
ISettingsManager
private
settingsManager
:
ISettingsManager
)
{
super
();
this
.
url
=
null
;
...
...
@@ -58,8 +62,8 @@ export class Win32AutoUpdaterImpl extends events.EventEmitter {
this
.
emit
(
'
checking-for-update
'
);
const
proxyUrl
=
Settings
.
getValue
(
'
http.proxy
'
);
const
strictSSL
=
Settings
.
getValue
(
'
http.proxyStrictSSL
'
,
true
);
const
proxyUrl
=
this
.
settingsManager
.
getValue
(
'
http.proxy
'
);
const
strictSSL
=
this
.
settingsManager
.
getValue
(
'
http.proxyStrictSSL
'
,
true
);
const
agent
=
getProxyAgent
(
this
.
url
,
{
proxyUrl
,
strictSSL
});
this
.
currentRequest
=
json
<
IUpdate
>
({
url
:
this
.
url
,
agent
})
...
...
@@ -110,11 +114,11 @@ export class Win32AutoUpdaterImpl extends events.EventEmitter {
}
private
getUpdatePackagePath
(
version
:
string
):
TPromise
<
string
>
{
return
this
.
cachePath
.
then
(
cachePath
=>
path
.
join
(
cachePath
,
`CodeSetup-
${
quality
}
-
${
version
}
.exe`
));
return
this
.
cachePath
.
then
(
cachePath
=>
path
.
join
(
cachePath
,
`CodeSetup-
${
this
.
envService
.
quality
}
-
${
version
}
.exe`
));
}
private
quitAndUpdate
(
updatePackagePath
:
string
):
void
{
Lifecycl
e
.
quit
().
done
(
vetod
=>
{
this
.
lifecycleServic
e
.
quit
().
done
(
vetod
=>
{
if
(
vetod
)
{
return
;
}
...
...
@@ -127,7 +131,7 @@ export class Win32AutoUpdaterImpl extends events.EventEmitter {
}
private
cleanup
(
exceptVersion
:
string
=
null
):
Promise
{
const
filter
=
exceptVersion
?
one
=>
!
(
new
RegExp
(
`
${
quality
}
-
${
exceptVersion
}
\\.exe$`
).
test
(
one
))
:
()
=>
true
;
const
filter
=
exceptVersion
?
one
=>
!
(
new
RegExp
(
`
${
this
.
envService
.
quality
}
-
${
exceptVersion
}
\\.exe$`
).
test
(
one
))
:
()
=>
true
;
return
this
.
cachePath
.
then
(
cachePath
=>
pfs
.
readdir
(
cachePath
)
...
...
src/vs/workbench/electron-main/env.ts
浏览文件 @
f4321ecf
...
...
@@ -10,17 +10,14 @@ import fs = require('fs');
import
path
=
require
(
'
path
'
);
import
os
=
require
(
'
os
'
);
import
{
app
}
from
'
electron
'
;
import
arrays
=
require
(
'
vs/base/common/arrays
'
);
import
strings
=
require
(
'
vs/base/common/strings
'
);
import
paths
=
require
(
'
vs/base/common/paths
'
);
import
platform
=
require
(
'
vs/base/common/platform
'
);
import
uri
from
'
vs/base/common/uri
'
;
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
types
=
require
(
'
vs/base/common/types
'
);
export
interface
IUpdateInfo
{
baseUrl
:
string
;
}
import
{
ServiceIdentifier
,
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
export
interface
IProductConfiguration
{
nameShort
:
string
;
...
...
@@ -60,60 +57,6 @@ export interface IProductConfiguration {
privacyStatementUrl
:
string
;
}
export
const
isBuilt
=
!
process
.
env
.
VSCODE_DEV
;
export
const
appRoot
=
path
.
dirname
(
uri
.
parse
(
require
.
toUrl
(
''
)).
fsPath
);
export
const
currentWorkingDirectory
=
process
.
env
.
VSCODE_CWD
||
process
.
cwd
();
let
productContents
:
IProductConfiguration
;
try
{
productContents
=
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
appRoot
,
'
product.json
'
),
'
utf8
'
));
}
catch
(
error
)
{
productContents
=
Object
.
create
(
null
);
}
export
const
product
:
IProductConfiguration
=
productContents
;
product
.
nameShort
=
product
.
nameShort
+
(
isBuilt
?
''
:
'
Dev
'
);
product
.
nameLong
=
product
.
nameLong
+
(
isBuilt
?
''
:
'
Dev
'
);
product
.
dataFolderName
=
product
.
dataFolderName
+
(
isBuilt
?
''
:
'
-dev
'
);
export
const
updateUrl
=
product
.
updateUrl
;
export
const
quality
=
product
.
quality
;
export
const
mainIPCHandle
=
getMainIPCHandle
();
export
const
sharedIPCHandle
=
getSharedIPCHandle
();
export
const
version
=
app
.
getVersion
();
export
const
cliArgs
=
parseCli
();
export
const
appHome
=
app
.
getPath
(
'
userData
'
);
export
const
appSettingsHome
=
path
.
join
(
appHome
,
'
User
'
);
if
(
!
fs
.
existsSync
(
appSettingsHome
))
{
fs
.
mkdirSync
(
appSettingsHome
);
}
export
const
appSettingsPath
=
path
.
join
(
appSettingsHome
,
'
settings.json
'
);
export
const
appKeybindingsPath
=
path
.
join
(
appSettingsHome
,
'
keybindings.json
'
);
export
const
userHome
=
path
.
join
(
app
.
getPath
(
'
home
'
),
product
.
dataFolderName
);
if
(
!
fs
.
existsSync
(
userHome
))
{
fs
.
mkdirSync
(
userHome
);
}
export
const
userExtensionsHome
=
cliArgs
.
extensionsHomePath
||
path
.
join
(
userHome
,
'
extensions
'
);
if
(
!
fs
.
existsSync
(
userExtensionsHome
))
{
fs
.
mkdirSync
(
userExtensionsHome
);
}
// Helper to identify if we have extension tests to run from the command line without debugger
export
const
isTestingFromCli
=
cliArgs
.
extensionTestsPath
&&
!
cliArgs
.
debugBrkExtensionHost
;
export
function
log
(...
a
:
any
[]):
void
{
if
(
cliArgs
.
verboseLogging
)
{
console
.
log
.
call
(
null
,
`(
${
new
Date
().
toLocaleTimeString
()}
)`
,
...
a
);
}
}
export
interface
IProcessEnvironment
{
[
key
:
string
]:
string
;
}
...
...
@@ -124,139 +67,240 @@ export interface ICommandLineArguments {
debugBrkExtensionHost
:
boolean
;
logExtensionHostCommunication
:
boolean
;
disableExtensions
:
boolean
;
extensionsHomePath
:
string
;
extensionDevelopmentPath
:
string
;
extensionTestsPath
:
string
;
programStart
:
number
;
pathArguments
?:
string
[];
enablePerformance
?:
boolean
;
firstrun
?:
boolean
;
openNewWindow
?:
boolean
;
openInSameWindow
?:
boolean
;
gotoLineMode
?:
boolean
;
diffMode
?:
boolean
;
locale
?:
string
;
waitForWindowClose
?:
boolean
;
}
function
parseCli
():
ICommandLineArguments
{
export
const
IEnvService
=
createDecorator
<
IEnvService
>
(
'
environmentService
'
);
export
interface
IEnvService
{
serviceId
:
ServiceIdentifier
<
any
>
;
cliArgs
:
ICommandLineArguments
;
userExtensionsHome
:
string
;
isTestingFromCli
:
boolean
;
isBuilt
:
boolean
;
product
:
IProductConfiguration
;
updateUrl
:
string
;
quality
:
string
;
userHome
:
string
;
appRoot
:
string
;
currentWorkingDirectory
:
string
;
version
:
string
;
appHome
:
string
;
appSettingsHome
:
string
;
appSettingsPath
:
string
;
appKeybindingsPath
:
string
;
mainIPCHandle
:
string
;
sharedIPCHandle
:
string
;
}
// We need to do some argv massaging. First, remove the Electron executable
let
args
=
Array
.
prototype
.
slice
.
call
(
process
.
argv
,
1
);
export
class
EnvService
implements
IEnvService
{
// Then, when in dev, remove the first non option argument, it will be the app location
if
(
!
isBuilt
)
{
let
i
=
(()
=>
{
for
(
let
j
=
0
;
j
<
args
.
length
;
j
++
)
{
if
(
args
[
j
][
0
]
!==
'
-
'
)
{
return
j
;
}
}
serviceId
=
IEnvService
;
private
_cliArgs
:
ICommandLineArguments
;
get
cliArgs
():
ICommandLineArguments
{
return
this
.
_cliArgs
;
}
private
_userExtensionsHome
:
string
;
get
userExtensionsHome
():
string
{
return
this
.
_userExtensionsHome
;
}
private
_isTestingFromCli
:
boolean
;
get
isTestingFromCli
():
boolean
{
return
this
.
_isTestingFromCli
;
}
get
isBuilt
():
boolean
{
return
!
process
.
env
[
'
VSCODE_DEV
'
];
}
private
_product
:
IProductConfiguration
;
get
product
():
IProductConfiguration
{
return
this
.
_product
;
}
get
updateUrl
():
string
{
return
this
.
product
.
updateUrl
;
}
get
quality
():
string
{
return
this
.
product
.
quality
;
}
private
_userHome
:
string
;
get
userHome
():
string
{
return
this
.
_userHome
;
}
private
_appRoot
:
string
;
get
appRoot
():
string
{
return
this
.
_appRoot
;
}
private
_currentWorkingDirectory
:
string
;
get
currentWorkingDirectory
():
string
{
return
this
.
_currentWorkingDirectory
;
}
return
-
1
;
})();
private
_version
:
string
;
get
version
():
string
{
return
this
.
_version
;
}
if
(
i
>
-
1
)
{
args
.
splice
(
i
,
1
);
private
_appHome
:
string
;
get
appHome
():
string
{
return
this
.
_appHome
;
}
private
_appSettingsHome
:
string
;
get
appSettingsHome
():
string
{
return
this
.
_appSettingsHome
;
}
private
_appSettingsPath
:
string
;
get
appSettingsPath
():
string
{
return
this
.
_appSettingsPath
;
}
private
_appKeybindingsPath
:
string
;
get
appKeybindingsPath
():
string
{
return
this
.
_appKeybindingsPath
;
}
private
_mainIPCHandle
:
string
;
get
mainIPCHandle
():
string
{
return
this
.
_mainIPCHandle
;
}
private
_sharedIPCHandle
:
string
;
get
sharedIPCHandle
():
string
{
return
this
.
_sharedIPCHandle
;
}
constructor
()
{
this
.
_appRoot
=
path
.
dirname
(
uri
.
parse
(
require
.
toUrl
(
''
)).
fsPath
);
this
.
_currentWorkingDirectory
=
process
.
env
[
'
VSCODE_CWD
'
]
||
process
.
cwd
();
this
.
_version
=
app
.
getVersion
();
this
.
_appHome
=
app
.
getPath
(
'
userData
'
);
this
.
_appSettingsHome
=
path
.
join
(
this
.
_appHome
,
'
User
'
);
// TODO move out of here!
if
(
!
fs
.
existsSync
(
this
.
_appSettingsHome
))
{
fs
.
mkdirSync
(
this
.
_appSettingsHome
);
}
}
// Finally, any extra arguments in the 'argv' file should be prepended
if
(
fs
.
existsSync
(
path
.
join
(
appRoot
,
'
argv
'
)))
{
let
extraargs
:
string
[]
=
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
appRoot
,
'
argv
'
),
'
utf8
'
));
args
=
extraargs
.
concat
(
args
);
}
this
.
_appSettingsPath
=
path
.
join
(
this
.
_appSettingsHome
,
'
settings.json
'
);
this
.
_appKeybindingsPath
=
path
.
join
(
this
.
_appSettingsHome
,
'
keybindings.json
'
);
let
opts
=
parseOpts
(
args
);
// Remove the Electron executable
let
[,
...
args
]
=
process
.
argv
;
let
gotoLineMode
=
!!
opts
[
'
g
'
]
||
!!
opts
[
'
goto
'
];
// Id dev, remove the first argument: it's the app location
if
(
!
this
.
isBuilt
)
{
[,
...
args
]
=
args
;
}
let
debugBrkExtensionHostPort
=
parseNumber
(
args
,
'
--debugBrkPluginHost
'
,
5870
);
let
debugExtensionHostPort
:
number
;
let
debugBrkExtensionHost
:
boolean
;
if
(
debugBrkExtensionHostPort
)
{
debugExtensionHostPort
=
debugBrkExtensionHostPort
;
debugBrkExtensionHost
=
true
;
}
else
{
debugExtensionHostPort
=
parseNumber
(
args
,
'
--debugPluginHost
'
,
5870
,
isBuilt
?
void
0
:
5870
);
}
// Finally, prepend any extra arguments from the 'argv' file
if
(
fs
.
existsSync
(
path
.
join
(
this
.
_appRoot
,
'
argv
'
)))
{
const
extraargs
:
string
[]
=
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
this
.
_appRoot
,
'
argv
'
),
'
utf8
'
));
args
=
[...
extraargs
,
...
args
];
}
let
pathArguments
=
parsePathArguments
(
args
,
gotoLineMode
);
const
opts
=
parseOpts
(
args
);
return
{
pathArguments
:
pathArguments
,
programStart
:
parseNumber
(
args
,
'
--timestamp
'
,
0
,
0
),
enablePerformance
:
!!
opts
[
'
p
'
],
verboseLogging
:
!!
opts
[
'
verbose
'
],
debugExtensionHostPort
:
debugExtensionHostPort
,
debugBrkExtensionHost
:
debugBrkExtensionHost
,
logExtensionHostCommunication
:
!!
opts
[
'
logExtensionHostCommunication
'
],
firstrun
:
!!
opts
[
'
squirrel-firstrun
'
],
openNewWindow
:
!!
opts
[
'
n
'
]
||
!!
opts
[
'
new-window
'
],
openInSameWindow
:
!!
opts
[
'
r
'
]
||
!!
opts
[
'
reuse-window
'
],
gotoLineMode
:
gotoLineMode
,
diffMode
:
(
!!
opts
[
'
d
'
]
||
!!
opts
[
'
diff
'
])
&&
pathArguments
.
length
===
2
,
extensionsHomePath
:
normalizePath
(
parseString
(
args
,
'
--extensionHomePath
'
)),
extensionDevelopmentPath
:
normalizePath
(
parseString
(
args
,
'
--extensionDevelopmentPath
'
)),
extensionTestsPath
:
normalizePath
(
parseString
(
args
,
'
--extensionTestsPath
'
)),
disableExtensions
:
!!
opts
[
'
disableExtensions
'
]
||
!!
opts
[
'
disable-extensions
'
],
locale
:
parseString
(
args
,
'
--locale
'
),
waitForWindowClose
:
!!
opts
[
'
w
'
]
||
!!
opts
[
'
wait
'
]
};
}
const
gotoLineMode
=
!!
opts
[
'
g
'
]
||
!!
opts
[
'
goto
'
];
const
debugBrkExtensionHostPort
=
parseNumber
(
args
,
'
--debugBrkPluginHost
'
,
5870
);
let
debugExtensionHostPort
:
number
;
let
debugBrkExtensionHost
:
boolean
;
function
getIPCHandleName
():
string
{
let
handleName
=
app
.
getName
();
if
(
debugBrkExtensionHostPort
)
{
debugExtensionHostPort
=
debugBrkExtensionHostPort
;
debugBrkExtensionHost
=
true
;
}
else
{
debugExtensionHostPort
=
parseNumber
(
args
,
'
--debugPluginHost
'
,
5870
,
this
.
isBuilt
?
void
0
:
5870
);
}
const
pathArguments
=
parsePathArguments
(
this
.
_currentWorkingDirectory
,
args
,
gotoLineMode
);
this
.
_cliArgs
=
Object
.
freeze
({
pathArguments
:
pathArguments
,
programStart
:
parseNumber
(
args
,
'
--timestamp
'
,
0
,
0
),
enablePerformance
:
!!
opts
[
'
p
'
],
verboseLogging
:
!!
opts
[
'
verbose
'
],
debugExtensionHostPort
:
debugExtensionHostPort
,
debugBrkExtensionHost
:
debugBrkExtensionHost
,
logExtensionHostCommunication
:
!!
opts
[
'
logExtensionHostCommunication
'
],
firstrun
:
!!
opts
[
'
squirrel-firstrun
'
],
openNewWindow
:
!!
opts
[
'
n
'
]
||
!!
opts
[
'
new-window
'
],
openInSameWindow
:
!!
opts
[
'
r
'
]
||
!!
opts
[
'
reuse-window
'
],
gotoLineMode
:
gotoLineMode
,
diffMode
:
(
!!
opts
[
'
d
'
]
||
!!
opts
[
'
diff
'
])
&&
pathArguments
.
length
===
2
,
extensionsHomePath
:
normalizePath
(
parseString
(
args
,
'
--extensionHomePath
'
)),
extensionDevelopmentPath
:
normalizePath
(
parseString
(
args
,
'
--extensionDevelopmentPath
'
)),
extensionTestsPath
:
normalizePath
(
parseString
(
args
,
'
--extensionTestsPath
'
)),
disableExtensions
:
!!
opts
[
'
disableExtensions
'
]
||
!!
opts
[
'
disable-extensions
'
],
locale
:
parseString
(
args
,
'
--locale
'
),
waitForWindowClose
:
!!
opts
[
'
w
'
]
||
!!
opts
[
'
wait
'
]
});
this
.
_isTestingFromCli
=
this
.
cliArgs
.
extensionTestsPath
&&
!
this
.
cliArgs
.
debugBrkExtensionHost
;
try
{
this
.
_product
=
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
this
.
_appRoot
,
'
product.json
'
),
'
utf8
'
));
}
catch
(
error
)
{
this
.
_product
=
Object
.
create
(
null
);
}
if
(
!
isBuilt
)
{
handleName
+=
'
-dev
'
;
if
(
!
this
.
isBuilt
)
{
const
nameShort
=
`
${
this
.
_product
.
nameShort
}
Dev`
;
const
nameLong
=
`
${
this
.
_product
.
nameLong
}
Dev`
;
const
dataFolderName
=
`
${
this
.
_product
.
dataFolderName
}
-dev`
;
this
.
_product
=
assign
(
this
.
_product
,
{
nameShort
,
nameLong
,
dataFolderName
});
}
this
.
_userHome
=
path
.
join
(
app
.
getPath
(
'
home
'
),
this
.
_product
.
dataFolderName
);
// TODO move out of here!
if
(
!
fs
.
existsSync
(
this
.
_userHome
))
{
fs
.
mkdirSync
(
this
.
_userHome
);
}
this
.
_userExtensionsHome
=
this
.
cliArgs
.
extensionsHomePath
||
path
.
join
(
this
.
userHome
,
'
extensions
'
);
// TODO move out of here!
if
(
!
fs
.
existsSync
(
this
.
_userExtensionsHome
))
{
fs
.
mkdirSync
(
this
.
_userExtensionsHome
);
}
this
.
_mainIPCHandle
=
this
.
getMainIPCHandle
();
this
.
_sharedIPCHandle
=
this
.
getSharedIPCHandle
();
}
// Support to run VS Code multiple times as different user
// by making the socket unique over the logged in user
let
userId
=
uniqueUserId
();
if
(
userId
)
{
handleName
+=
(
'
-
'
+
userId
);
private
getMainIPCHandle
():
string
{
return
this
.
getIPCHandleName
()
+
(
process
.
platform
===
'
win32
'
?
'
-sock
'
:
'
.sock
'
);
}
if
(
process
.
platform
===
'
win32
'
)
{
return
'
\\\\
.
\\
pipe
\\
'
+
handleName
;
private
getSharedIPCHandle
():
string
{
return
this
.
getIPCHandleName
()
+
'
-shared
'
+
(
process
.
platform
===
'
win32
'
?
'
-sock
'
:
'
.sock
'
)
;
}
return
path
.
join
(
os
.
tmpdir
(),
handleName
);
}
private
getIPCHandleName
():
string
{
let
handleName
=
app
.
getName
();
function
getMainIPCHandle
():
string
{
return
getIPCHandleName
()
+
(
process
.
platform
===
'
win32
'
?
'
-sock
'
:
'
.sock
'
)
;
}
if
(
!
this
.
isBuilt
)
{
handleName
+=
'
-dev
'
;
}
function
getSharedIPCHandle
():
string
{
return
getIPCHandleName
()
+
'
-shared
'
+
(
process
.
platform
===
'
win32
'
?
'
-sock
'
:
'
.sock
'
);
}
// Support to run VS Code multiple times as different user
// by making the socket unique over the logged in user
let
userId
=
EnvService
.
getUniqueUserId
();
if
(
userId
)
{
handleName
+=
(
'
-
'
+
userId
);
}
function
uniqueUserId
():
string
{
let
username
:
string
;
if
(
platform
.
isWindows
)
{
username
=
process
.
env
.
USERNAME
;
}
else
{
username
=
process
.
env
.
USER
;
}
if
(
process
.
platform
===
'
win32
'
)
{
return
'
\\\\
.
\\
pipe
\\
'
+
handleName
;
}
if
(
!
username
)
{
return
''
;
// fail gracefully if there is no user name
return
path
.
join
(
os
.
tmpdir
(),
handleName
);
}
// use sha256 to ensure the userid value can be used in filenames and are unique
return
crypto
.
createHash
(
'
sha256
'
).
update
(
username
).
digest
(
'
hex
'
).
substr
(
0
,
6
);
private
static
getUniqueUserId
():
string
{
let
username
:
string
;
if
(
platform
.
isWindows
)
{
username
=
process
.
env
.
USERNAME
;
}
else
{
username
=
process
.
env
.
USER
;
}
if
(
!
username
)
{
return
''
;
// fail gracefully if there is no user name
}
// use sha256 to ensure the userid value can be used in filenames and are unique
return
crypto
.
createHash
(
'
sha256
'
).
update
(
username
).
digest
(
'
hex
'
).
substr
(
0
,
6
);
}
}
type
OptionBag
=
{
[
opt
:
string
]:
boolean
;
};
...
...
@@ -268,7 +312,7 @@ function parseOpts(argv: string[]): OptionBag {
.
reduce
((
r
,
a
)
=>
{
r
[
a
]
=
true
;
return
r
;
},
<
OptionBag
>
{});
}
function
parsePathArguments
(
argv
:
string
[],
gotoLineMode
?:
boolean
):
string
[]
{
function
parsePathArguments
(
cwd
:
string
,
argv
:
string
[],
gotoLineMode
?:
boolean
):
string
[]
{
return
arrays
.
coalesce
(
// no invalid paths
arrays
.
distinct
(
// no duplicates
argv
.
filter
(
a
=>
!
(
/^-/
.
test
(
a
)))
// arguments without leading "-"
...
...
@@ -282,7 +326,7 @@ function parsePathArguments(argv: string[], gotoLineMode?: boolean): string[] {
}
if
(
pathCandidate
)
{
pathCandidate
=
preparePath
(
pathCandidate
);
pathCandidate
=
preparePath
(
cwd
,
pathCandidate
);
}
let
realPath
:
string
;
...
...
@@ -291,7 +335,7 @@ function parsePathArguments(argv: string[], gotoLineMode?: boolean): string[] {
}
catch
(
error
)
{
// in case of an error, assume the user wants to create this file
// if the path is relative, we join it to the cwd
realPath
=
path
.
normalize
(
path
.
isAbsolute
(
pathCandidate
)
?
pathCandidate
:
path
.
join
(
c
urrentWorkingDirectory
,
pathCandidate
));
realPath
=
path
.
normalize
(
path
.
isAbsolute
(
pathCandidate
)
?
pathCandidate
:
path
.
join
(
c
wd
,
pathCandidate
));
}
if
(
!
paths
.
isValidBasename
(
path
.
basename
(
realPath
)))
{
...
...
@@ -312,7 +356,7 @@ function parsePathArguments(argv: string[], gotoLineMode?: boolean): string[] {
);
}
function
preparePath
(
p
:
string
):
string
{
function
preparePath
(
cwd
:
string
,
p
:
string
):
string
{
// Trim trailing quotes
if
(
platform
.
isWindows
)
{
...
...
@@ -325,7 +369,7 @@ function preparePath(p: string): string {
if
(
platform
.
isWindows
)
{
// Resolve the path against cwd if it is relative
p
=
path
.
resolve
(
c
urrentWorkingDirectory
,
p
);
p
=
path
.
resolve
(
c
wd
,
p
);
// Trim trailing '.' chars on Windows to prevent invalid file names
p
=
strings
.
rtrim
(
p
,
'
.
'
);
...
...
src/vs/workbench/electron-main/launch.ts
0 → 100644
浏览文件 @
f4321ecf
/*---------------------------------------------------------------------------------------------
* 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
{
ICommandLineArguments
,
IProcessEnvironment
}
from
'
vs/workbench/electron-main/env
'
;
import
{
IWindowsManager
}
from
'
vs/workbench/electron-main/windows
'
;
import
{
VSCodeWindow
}
from
'
vs/workbench/electron-main/window
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
IChannel
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
{
ILogService
}
from
'
./log
'
;
export
interface
ILaunchService
{
start
(
args
:
ICommandLineArguments
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
;
}
export
interface
ILaunchChannel
extends
IChannel
{
call
(
command
:
'
start
'
,
args
:
ICommandLineArguments
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
;
call
(
command
:
string
,
...
args
:
any
[]):
TPromise
<
any
>
;
}
export
class
LaunchChannel
implements
ILaunchChannel
{
constructor
(
private
service
:
ILaunchService
)
{
}
call
(
command
:
string
,
...
args
:
any
[]):
TPromise
<
any
>
{
switch
(
command
)
{
case
'
start
'
:
return
this
.
service
.
start
(
args
[
0
],
args
[
1
]);
}
}
}
export
class
LaunchChannelClient
implements
ILaunchService
{
constructor
(
private
channel
:
ILaunchChannel
)
{
}
start
(
args
:
ICommandLineArguments
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
{
return
this
.
channel
.
call
(
'
start
'
,
args
,
userEnv
);
}
}
export
class
LaunchService
implements
ILaunchService
{
constructor
(
@
ILogService
private
logService
:
ILogService
,
@
IWindowsManager
private
windowsManager
:
IWindowsManager
)
{}
start
(
args
:
ICommandLineArguments
,
userEnv
:
IProcessEnvironment
):
TPromise
<
void
>
{
this
.
logService
.
log
(
'
Received data from other instance
'
,
args
);
// Otherwise handle in windows manager
let
usedWindows
:
VSCodeWindow
[];
if
(
!!
args
.
extensionDevelopmentPath
)
{
this
.
windowsManager
.
openPluginDevelopmentHostWindow
({
cli
:
args
,
userEnv
:
userEnv
});
}
else
if
(
args
.
pathArguments
.
length
===
0
&&
args
.
openNewWindow
)
{
usedWindows
=
this
.
windowsManager
.
open
({
cli
:
args
,
userEnv
:
userEnv
,
forceNewWindow
:
true
,
forceEmpty
:
true
});
}
else
if
(
args
.
pathArguments
.
length
===
0
)
{
usedWindows
=
[
this
.
windowsManager
.
focusLastActive
(
args
)];
}
else
{
usedWindows
=
this
.
windowsManager
.
open
({
cli
:
args
,
userEnv
:
userEnv
,
forceNewWindow
:
args
.
waitForWindowClose
||
args
.
openNewWindow
,
preferNewWindow
:
!
args
.
openInSameWindow
,
diffMode
:
args
.
diffMode
});
}
// If the other instance is waiting to be killed, we hook up a window listener if one window
// is being used and only then resolve the startup promise which will kill this second instance
if
(
args
.
waitForWindowClose
&&
usedWindows
&&
usedWindows
.
length
===
1
&&
usedWindows
[
0
])
{
const
windowId
=
usedWindows
[
0
].
id
;
return
new
TPromise
<
void
>
((
c
,
e
)
=>
{
const
unbind
=
this
.
windowsManager
.
onClose
(
id
=>
{
if
(
id
===
windowId
)
{
unbind
();
c
(
null
);
}
});
});
}
return
TPromise
.
as
(
null
);
}
}
\ No newline at end of file
src/vs/workbench/electron-main/lifecycle.ts
浏览文件 @
f4321ecf
...
...
@@ -11,37 +11,55 @@ import {ipcMain as ipc, app} from 'electron';
import
{
TPromise
,
TValueCallback
}
from
'
vs/base/common/winjs.base
'
;
import
{
ReadyState
,
VSCodeWindow
}
from
'
vs/workbench/electron-main/window
'
;
import
env
=
require
(
'
vs/workbench/electron-main/env
'
);
const
eventEmitter
=
new
events
.
EventEmitter
()
;
import
{
ServiceIdentifier
,
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ILogService
}
from
'
./log
'
;
const
EventTypes
=
{
BEFORE_QUIT
:
'
before-quit
'
};
/**
* Due to the way we handle lifecycle with eventing, the general app.on('before-quit')
* event cannot be used because it can be called twice on shutdown. Instead the onBeforeQuit
* handler in this module can be used and it is only called once on a shutdown sequence.
*/
export
function
onBeforeQuit
(
clb
:
()
=>
void
):
()
=>
void
{
eventEmitter
.
addListener
(
EventTypes
.
BEFORE_QUIT
,
clb
);
export
const
ILifecycleService
=
createDecorator
<
ILifecycleService
>
(
'
lifecycleService
'
);
return
()
=>
eventEmitter
.
removeListener
(
EventTypes
.
BEFORE_QUIT
,
clb
);
export
interface
ILifecycleService
{
serviceId
:
ServiceIdentifier
<
any
>
;
onBeforeQuit
(
clb
:
()
=>
void
):
()
=>
void
;
ready
():
void
;
registerWindow
(
vscodeWindow
:
VSCodeWindow
):
void
;
unload
(
vscodeWindow
:
VSCodeWindow
):
TPromise
<
boolean
/* veto */
>
;
quit
():
TPromise
<
boolean
/* veto */
>
;
}
export
class
Lifecycle
{
export
class
LifecycleService
implements
ILifecycleService
{
serviceId
=
ILifecycleService
;
private
eventEmitter
=
new
events
.
EventEmitter
();
private
windowToCloseRequest
:
{
[
windowId
:
string
]:
boolean
};
private
quitRequested
:
boolean
;
private
pendingQuitPromise
:
TPromise
<
boolean
>
;
private
pendingQuitPromiseComplete
:
TValueCallback
<
boolean
>
;
private
oneTimeListenerTokenGenerator
:
number
;
constructor
()
{
constructor
(
@
env
.
IEnvService
private
envService
:
env
.
IEnvService
,
@
ILogService
private
logService
:
ILogService
)
{
this
.
windowToCloseRequest
=
Object
.
create
(
null
);
this
.
quitRequested
=
false
;
this
.
oneTimeListenerTokenGenerator
=
0
;
}
/**
* Due to the way we handle lifecycle with eventing, the general app.on('before-quit')
* event cannot be used because it can be called twice on shutdown. Instead the onBeforeQuit
* handler in this module can be used and it is only called once on a shutdown sequence.
*/
onBeforeQuit
(
clb
:
()
=>
void
):
()
=>
void
{
this
.
eventEmitter
.
addListener
(
EventTypes
.
BEFORE_QUIT
,
clb
);
return
()
=>
this
.
eventEmitter
.
removeListener
(
EventTypes
.
BEFORE_QUIT
,
clb
);
}
public
ready
():
void
{
this
.
registerListeners
();
}
...
...
@@ -50,10 +68,10 @@ export class Lifecycle {
// before-quit
app
.
on
(
'
before-quit
'
,
(
e
)
=>
{
env
.
log
(
'
Lifecycle#before-quit
'
);
this
.
logService
.
log
(
'
Lifecycle#before-quit
'
);
if
(
!
this
.
quitRequested
)
{
eventEmitter
.
emit
(
EventTypes
.
BEFORE_QUIT
);
// only send this if this is the first quit request we have
this
.
eventEmitter
.
emit
(
EventTypes
.
BEFORE_QUIT
);
// only send this if this is the first quit request we have
}
this
.
quitRequested
=
true
;
...
...
@@ -61,12 +79,12 @@ export class Lifecycle {
// window-all-closed
app
.
on
(
'
window-all-closed
'
,
()
=>
{
env
.
log
(
'
Lifecycle#window-all-closed
'
);
this
.
logService
.
log
(
'
Lifecycle#window-all-closed
'
);
// Windows/Linux: we quit when all windows have closed
// Mac: we only quit when quit was requested
// --wait: we quit when all windows are closed
if
(
this
.
quitRequested
||
process
.
platform
!==
'
darwin
'
||
env
.
cliArgs
.
waitForWindowClose
)
{
if
(
this
.
quitRequested
||
process
.
platform
!==
'
darwin
'
||
this
.
envService
.
cliArgs
.
waitForWindowClose
)
{
app
.
quit
();
}
});
...
...
@@ -77,11 +95,11 @@ export class Lifecycle {
// Window Before Closing: Main -> Renderer
vscodeWindow
.
win
.
on
(
'
close
'
,
(
e
)
=>
{
let
windowId
=
vscodeWindow
.
id
;
env
.
log
(
'
Lifecycle#window-before-close
'
,
windowId
);
this
.
logService
.
log
(
'
Lifecycle#window-before-close
'
,
windowId
);
// The window already acknowledged to be closed
if
(
this
.
windowToCloseRequest
[
windowId
])
{
env
.
log
(
'
Lifecycle#window-close
'
,
windowId
);
this
.
logService
.
log
(
'
Lifecycle#window-close
'
,
windowId
);
delete
this
.
windowToCloseRequest
[
windowId
];
...
...
@@ -108,8 +126,8 @@ export class Lifecycle {
if
(
vscodeWindow
.
readyState
!==
ReadyState
.
READY
)
{
return
TPromise
.
as
<
boolean
>
(
false
);
}
env
.
log
(
'
Lifecycle#unload()
'
,
vscodeWindow
.
id
);
this
.
logService
.
log
(
'
Lifecycle#unload()
'
,
vscodeWindow
.
id
);
return
new
TPromise
<
boolean
>
((
c
)
=>
{
let
oneTimeEventToken
=
this
.
oneTimeListenerTokenGenerator
++
;
...
...
@@ -141,7 +159,7 @@ export class Lifecycle {
* by the user or not.
*/
public
quit
():
TPromise
<
boolean
/* veto */
>
{
env
.
log
(
'
Lifecycle#quit()
'
);
this
.
logService
.
log
(
'
Lifecycle#quit()
'
);
if
(
!
this
.
pendingQuitPromise
)
{
this
.
pendingQuitPromise
=
new
TPromise
<
boolean
>
((
c
)
=>
{
...
...
@@ -163,6 +181,4 @@ export class Lifecycle {
return
this
.
pendingQuitPromise
;
}
}
export
const
manager
=
new
Lifecycle
();
\ No newline at end of file
}
\ No newline at end of file
src/vs/workbench/electron-main/log.ts
0 → 100644
浏览文件 @
f4321ecf
/*---------------------------------------------------------------------------------------------
* 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
{
ServiceIdentifier
,
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IEnvService
}
from
'
./env
'
;
export
const
ILogService
=
createDecorator
<
ILogService
>
(
'
logService
'
);
export
interface
ILogService
{
serviceId
:
ServiceIdentifier
<
any
>
;
log
(...
args
:
any
[]):
void
;
}
export
class
MainLogService
implements
ILogService
{
serviceId
=
ILogService
;
constructor
(@
IEnvService
private
envService
:
IEnvService
)
{
}
log
(...
args
:
any
[]):
void
{
const
{
verboseLogging
}
=
this
.
envService
.
cliArgs
;
if
(
verboseLogging
)
{
console
.
log
(
`(
${
new
Date
().
toLocaleTimeString
()}
)`
,
...
args
);
}
}
}
\ No newline at end of file
src/vs/workbench/electron-main/main.ts
浏览文件 @
f4321ecf
...
...
@@ -10,120 +10,35 @@ import fs = require('fs');
import
nls
=
require
(
'
vs/nls
'
);
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
platform
=
require
(
'
vs/base/common/platform
'
);
import
env
=
require
(
'
vs/workbench/electron-main/env
'
)
;
import
{
IProcessEnvironment
,
IEnvService
,
EnvService
}
from
'
vs/workbench/electron-main/env
'
;
import
windows
=
require
(
'
vs/workbench/electron-main/windows
'
);
import
window
=
require
(
'
vs/workbench/electron-main/window
'
);
import
lifecycle
=
require
(
'
vs/workbench/electron-main/lifecycle
'
);
import
menu
=
require
(
'
vs/workbench/electron-main/menus
'
);
import
settings
=
require
(
'
vs/workbench/electron-main/settings
'
);
import
{
Instance
as
UpdateManager
}
from
'
vs/workbench/electron-main/update-manager
'
;
import
{
ILifecycleService
,
LifecycleService
}
from
'
vs/workbench/electron-main/lifecycle
'
;
import
{
VSCodeMenu
}
from
'
vs/workbench/electron-main/menus
'
;
import
{
ISettingsManager
,
SettingsManager
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
IUpdateManager
,
UpdateManager
}
from
'
vs/workbench/electron-main/update-manager
'
;
import
{
Server
,
serve
,
connect
}
from
'
vs/base/parts/ipc/node/ipc.net
'
;
import
{
getUserEnvironment
}
from
'
vs/base/node/env
'
;
import
{
TPromise
}
from
'
vs/base/common/winjs.base
'
;
import
{
AskpassChannel
}
from
'
vs/workbench/parts/git/common/gitIpc
'
;
import
{
GitAskpassService
}
from
'
vs/workbench/parts/git/electron-main/askpassService
'
;
import
{
spawnSharedProcess
}
from
'
vs/workbench/electron-main/sharedProcess
'
;
import
{
IChannel
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
{
Mutex
}
from
'
windows-mutex
'
;
import
{
LaunchService
,
ILaunchChannel
,
LaunchChannel
,
LaunchChannelClient
}
from
'
./launch
'
;
import
{
ServicesAccessor
,
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
InstantiationService
}
from
'
vs/platform/instantiation/common/instantiationService
'
;
import
{
ServiceCollection
}
from
'
vs/platform/instantiation/common/serviceCollection
'
;
import
{
SyncDescriptor
}
from
'
vs/platform/instantiation/common/descriptors
'
;
import
{
ILogService
,
MainLogService
}
from
'
./log
'
;
import
{
IStorageService
,
StorageService
}
from
'
./storage
'
;
function
quit
(
accessor
:
ServicesAccessor
,
error
?:
Error
);
function
quit
(
accessor
:
ServicesAccessor
,
message
?:
string
);
function
quit
(
accessor
:
ServicesAccessor
,
arg
?:
any
)
{
const
logService
=
accessor
.
get
(
ILogService
);
interface
ILaunchService
{
start
(
args
:
env
.
ICommandLineArguments
,
userEnv
:
env
.
IProcessEnvironment
):
TPromise
<
void
>
;
}
export
interface
ILaunchChannel
extends
IChannel
{
call
(
command
:
'
start
'
,
args
:
env
.
ICommandLineArguments
,
userEnv
:
env
.
IProcessEnvironment
):
TPromise
<
void
>
;
call
(
command
:
string
,
...
args
:
any
[]):
TPromise
<
any
>
;
}
class
LaunchChannel
implements
ILaunchChannel
{
constructor
(
private
service
:
ILaunchService
)
{
}
call
(
command
:
string
,
...
args
:
any
[]):
TPromise
<
any
>
{
switch
(
command
)
{
case
'
start
'
:
return
this
.
service
.
start
(
args
[
0
],
args
[
1
]);
}
}
}
class
LaunchChannelClient
implements
ILaunchService
{
constructor
(
private
channel
:
ILaunchChannel
)
{
}
start
(
args
:
env
.
ICommandLineArguments
,
userEnv
:
env
.
IProcessEnvironment
):
TPromise
<
void
>
{
return
this
.
channel
.
call
(
'
start
'
,
args
,
userEnv
);
}
}
class
LaunchService
{
start
(
args
:
env
.
ICommandLineArguments
,
userEnv
:
env
.
IProcessEnvironment
):
TPromise
<
void
>
{
env
.
log
(
'
Received data from other instance
'
,
args
);
// Otherwise handle in windows manager
let
usedWindows
:
window
.
VSCodeWindow
[];
if
(
!!
args
.
extensionDevelopmentPath
)
{
windows
.
manager
.
openPluginDevelopmentHostWindow
({
cli
:
args
,
userEnv
:
userEnv
});
}
else
if
(
args
.
pathArguments
.
length
===
0
&&
args
.
openNewWindow
)
{
usedWindows
=
windows
.
manager
.
open
({
cli
:
args
,
userEnv
:
userEnv
,
forceNewWindow
:
true
,
forceEmpty
:
true
});
}
else
if
(
args
.
pathArguments
.
length
===
0
)
{
usedWindows
=
[
windows
.
manager
.
focusLastActive
(
args
)];
}
else
{
usedWindows
=
windows
.
manager
.
open
({
cli
:
args
,
userEnv
:
userEnv
,
forceNewWindow
:
args
.
waitForWindowClose
||
args
.
openNewWindow
,
preferNewWindow
:
!
args
.
openInSameWindow
,
diffMode
:
args
.
diffMode
});
}
// If the other instance is waiting to be killed, we hook up a window listener if one window
// is being used and only then resolve the startup promise which will kill this second instance
if
(
args
.
waitForWindowClose
&&
usedWindows
&&
usedWindows
.
length
===
1
&&
usedWindows
[
0
])
{
const
windowId
=
usedWindows
[
0
].
id
;
return
new
TPromise
<
void
>
((
c
,
e
)
=>
{
const
unbind
=
windows
.
onClose
(
id
=>
{
if
(
id
===
windowId
)
{
unbind
();
c
(
null
);
}
});
});
}
return
TPromise
.
as
(
null
);
}
}
// We handle uncaught exceptions here to prevent electron from opening a dialog to the user
process
.
on
(
'
uncaughtException
'
,
(
err
:
any
)
=>
{
if
(
err
)
{
// take only the message and stack property
let
friendlyError
=
{
message
:
err
.
message
,
stack
:
err
.
stack
};
// handle on client side
windows
.
manager
.
sendToFocused
(
'
vscode:reportError
'
,
JSON
.
stringify
(
friendlyError
));
}
console
.
error
(
'
[uncaught exception in main]:
'
+
err
);
if
(
err
.
stack
)
{
console
.
error
(
err
.
stack
);
}
});
function
quit
(
error
?:
Error
);
function
quit
(
message
?:
string
);
function
quit
(
arg
?:
any
)
{
let
exitCode
=
0
;
if
(
typeof
arg
===
'
string
'
)
{
env
.
log
(
arg
);
logService
.
log
(
arg
);
}
else
{
exitCode
=
1
;
// signal error to the outside
if
(
arg
.
stack
)
{
...
...
@@ -136,21 +51,49 @@ function quit(arg?: any) {
process
.
exit
(
exitCode
);
// in main, process.exit === app.exit
}
function
main
(
ipcServer
:
Server
,
userEnv
:
env
.
IProcessEnvironment
):
void
{
env
.
log
(
'
### VSCode main.js ###
'
);
env
.
log
(
env
.
appRoot
,
env
.
cliArgs
);
function
main
(
accessor
:
ServicesAccessor
,
ipcServer
:
Server
,
userEnv
:
IProcessEnvironment
):
void
{
const
instantiationService
=
accessor
.
get
(
IInstantiationService
);
const
logService
=
accessor
.
get
(
ILogService
);
const
envService
=
accessor
.
get
(
IEnvService
);
const
windowManager
=
accessor
.
get
(
windows
.
IWindowsManager
);
const
lifecycleService
=
accessor
.
get
(
ILifecycleService
);
const
updateManager
=
accessor
.
get
(
IUpdateManager
);
const
settingsManager
=
accessor
.
get
(
ISettingsManager
);
// We handle uncaught exceptions here to prevent electron from opening a dialog to the user
process
.
on
(
'
uncaughtException
'
,
(
err
:
any
)
=>
{
if
(
err
)
{
// take only the message and stack property
let
friendlyError
=
{
message
:
err
.
message
,
stack
:
err
.
stack
};
// handle on client side
windowManager
.
sendToFocused
(
'
vscode:reportError
'
,
JSON
.
stringify
(
friendlyError
));
}
console
.
error
(
'
[uncaught exception in main]:
'
+
err
);
if
(
err
.
stack
)
{
console
.
error
(
err
.
stack
);
}
});
logService
.
log
(
'
### VSCode main.js ###
'
);
logService
.
log
(
envService
.
appRoot
,
envService
.
cliArgs
);
// Setup Windows mutex
let
windowsMutex
:
Mutex
=
null
;
try
{
const
Mutex
=
(
<
any
>
require
.
__$__nodeRequire
(
'
windows-mutex
'
)).
Mutex
;
windowsMutex
=
new
Mutex
(
env
.
product
.
win32MutexName
);
windowsMutex
=
new
Mutex
(
env
Service
.
product
.
win32MutexName
);
}
catch
(
e
)
{
// noop
}
// Register IPC services
const
launchService
=
new
LaunchService
(
);
const
launchService
=
instantiationService
.
createInstance
(
LaunchService
);
const
launchChannel
=
new
LaunchChannel
(
launchService
);
ipcServer
.
registerChannel
(
'
launch
'
,
launchChannel
);
...
...
@@ -160,22 +103,22 @@ function main(ipcServer: Server, userEnv: env.IProcessEnvironment): void {
// Used by sub processes to communicate back to the main instance
process
.
env
[
'
VSCODE_PID
'
]
=
''
+
process
.
pid
;
process
.
env
[
'
VSCODE_IPC_HOOK
'
]
=
env
.
mainIPCHandle
;
process
.
env
[
'
VSCODE_SHARED_IPC_HOOK
'
]
=
env
.
sharedIPCHandle
;
process
.
env
[
'
VSCODE_IPC_HOOK
'
]
=
env
Service
.
mainIPCHandle
;
process
.
env
[
'
VSCODE_SHARED_IPC_HOOK
'
]
=
env
Service
.
sharedIPCHandle
;
// Spawn shared process
const
sharedProcess
=
spawnSharedProcess
(
);
const
sharedProcess
=
instantiationService
.
invokeFunction
(
spawnSharedProcess
);
// Make sure we associate the program with the app user model id
// This will help Windows to associate the running program with
// any shortcut that is pinned to the taskbar and prevent showing
// two icons in the taskbar for the same app.
if
(
platform
.
isWindows
&&
env
.
product
.
win32AppUserModelId
)
{
app
.
setAppUserModelId
(
env
.
product
.
win32AppUserModelId
);
if
(
platform
.
isWindows
&&
env
Service
.
product
.
win32AppUserModelId
)
{
app
.
setAppUserModelId
(
env
Service
.
product
.
win32AppUserModelId
);
}
// Set programStart in the global scope
global
.
programStart
=
env
.
cliArgs
.
programStart
;
global
.
programStart
=
env
Service
.
cliArgs
.
programStart
;
function
dispose
()
{
if
(
ipcServer
)
{
...
...
@@ -192,33 +135,34 @@ function main(ipcServer: Server, userEnv: env.IProcessEnvironment): void {
// Dispose on app quit
app
.
on
(
'
will-quit
'
,
()
=>
{
env
.
log
(
'
App#will-quit: disposing resources
'
);
logService
.
log
(
'
App#will-quit: disposing resources
'
);
dispose
();
});
// Dispose on vscode:exit
ipc
.
on
(
'
vscode:exit
'
,
(
event
,
code
:
number
)
=>
{
env
.
log
(
'
IPC#vscode:exit
'
,
code
);
logService
.
log
(
'
IPC#vscode:exit
'
,
code
);
dispose
();
process
.
exit
(
code
);
// in main, process.exit === app.exit
});
// Lifecycle
lifecycle
.
manager
.
ready
();
lifecycle
Service
.
ready
();
// Load settings
settings
.
m
anager
.
loadSync
();
settings
M
anager
.
loadSync
();
// Propagate to clients
window
s
.
m
anager
.
ready
(
userEnv
);
window
M
anager
.
ready
(
userEnv
);
// Install Menu
menu
.
manager
.
ready
();
const
menuManager
=
instantiationService
.
createInstance
(
VSCodeMenu
);
menuManager
.
ready
();
// Install Tasks
if
(
platform
.
isWindows
&&
env
.
isBuilt
)
{
if
(
platform
.
isWindows
&&
env
Service
.
isBuilt
)
{
app
.
setUserTasks
([
{
title
:
nls
.
localize
(
'
newWindow
'
,
"
New Window
"
),
...
...
@@ -231,21 +175,24 @@ function main(ipcServer: Server, userEnv: env.IProcessEnvironment): void {
}
// Setup auto update
U
pdateManager
.
initialize
();
u
pdateManager
.
initialize
();
// Open our first window
if
(
env
.
cliArgs
.
openNewWindow
&&
env
.
cliArgs
.
pathArguments
.
length
===
0
)
{
window
s
.
manager
.
open
({
cli
:
env
.
cliArgs
,
forceNewWindow
:
true
,
forceEmpty
:
true
});
// new window if "-n" was used without paths
}
else
if
(
global
.
macOpenFiles
&&
global
.
macOpenFiles
.
length
&&
(
!
env
.
cliArgs
.
pathArguments
||
!
env
.
cliArgs
.
pathArguments
.
length
))
{
window
s
.
manager
.
open
({
cli
:
env
.
cliArgs
,
pathsToOpen
:
global
.
macOpenFiles
});
// mac: open-file event received on startup
if
(
env
Service
.
cliArgs
.
openNewWindow
&&
envService
.
cliArgs
.
pathArguments
.
length
===
0
)
{
window
Manager
.
open
({
cli
:
envService
.
cliArgs
,
forceNewWindow
:
true
,
forceEmpty
:
true
});
// new window if "-n" was used without paths
}
else
if
(
global
.
macOpenFiles
&&
global
.
macOpenFiles
.
length
&&
(
!
env
Service
.
cliArgs
.
pathArguments
||
!
envService
.
cliArgs
.
pathArguments
.
length
))
{
window
Manager
.
open
({
cli
:
envService
.
cliArgs
,
pathsToOpen
:
global
.
macOpenFiles
});
// mac: open-file event received on startup
}
else
{
window
s
.
manager
.
open
({
cli
:
env
.
cliArgs
,
forceNewWindow
:
env
.
cliArgs
.
openNewWindow
,
diffMode
:
env
.
cliArgs
.
diffMode
});
// default: read paths from cli
window
Manager
.
open
({
cli
:
envService
.
cliArgs
,
forceNewWindow
:
envService
.
cliArgs
.
openNewWindow
,
diffMode
:
envService
.
cliArgs
.
diffMode
});
// default: read paths from cli
}
}
function
setupIPC
():
TPromise
<
Server
>
{
function
setupIPC
(
accessor
:
ServicesAccessor
):
TPromise
<
Server
>
{
const
logService
=
accessor
.
get
(
ILogService
);
const
envService
=
accessor
.
get
(
IEnvService
);
function
setup
(
retry
:
boolean
):
TPromise
<
Server
>
{
return
serve
(
env
.
mainIPCHandle
).
then
(
server
=>
{
return
serve
(
env
Service
.
mainIPCHandle
).
then
(
server
=>
{
if
(
platform
.
isMacintosh
)
{
app
.
dock
.
show
();
// dock might be hidden at this case due to a retry
}
...
...
@@ -262,23 +209,23 @@ function setupIPC(): TPromise<Server> {
}
// there's a running instance, let's connect to it
return
connect
(
env
.
mainIPCHandle
).
then
(
return
connect
(
env
Service
.
mainIPCHandle
).
then
(
client
=>
{
// Tests from CLI require to be the only instance currently (TODO@Ben support multiple instances and output)
if
(
env
.
isTestingFromCli
)
{
if
(
env
Service
.
isTestingFromCli
)
{
const
msg
=
'
Running extension tests from the command line is currently only supported if no other instance of Code is running.
'
;
console
.
error
(
msg
);
client
.
dispose
();
return
TPromise
.
wrapError
(
msg
);
}
env
.
log
(
'
Sending env to running instance...
'
);
logService
.
log
(
'
Sending env to running instance...
'
);
const
channel
=
client
.
getChannel
<
ILaunchChannel
>
(
'
launch
'
);
const
service
=
new
LaunchChannelClient
(
channel
);
return
service
.
start
(
env
.
cliArgs
,
process
.
env
)
return
service
.
start
(
env
Service
.
cliArgs
,
process
.
env
)
.
then
(()
=>
client
.
dispose
())
.
then
(()
=>
TPromise
.
wrapError
(
'
Sent env to running instance. Terminating...
'
));
},
...
...
@@ -291,9 +238,9 @@ function setupIPC(): TPromise<Server> {
// let's delete it, since we can't connect to it
// and the retry the whole thing
try
{
fs
.
unlinkSync
(
env
.
mainIPCHandle
);
fs
.
unlinkSync
(
env
Service
.
mainIPCHandle
);
}
catch
(
e
)
{
env
.
log
(
'
Fatal error deleting obsolete instance handle
'
,
e
);
logService
.
log
(
'
Fatal error deleting obsolete instance handle
'
,
e
);
return
TPromise
.
wrapError
(
e
);
}
...
...
@@ -306,6 +253,19 @@ function setupIPC(): TPromise<Server> {
return
setup
(
true
);
}
// TODO: isolate
const
services
=
new
ServiceCollection
();
services
.
set
(
IEnvService
,
new
SyncDescriptor
(
EnvService
));
services
.
set
(
ILogService
,
new
SyncDescriptor
(
MainLogService
));
services
.
set
(
windows
.
IWindowsManager
,
new
SyncDescriptor
(
windows
.
WindowsManager
));
services
.
set
(
ILifecycleService
,
new
SyncDescriptor
(
LifecycleService
));
services
.
set
(
IStorageService
,
new
SyncDescriptor
(
StorageService
));
services
.
set
(
IUpdateManager
,
new
SyncDescriptor
(
UpdateManager
));
services
.
set
(
ISettingsManager
,
new
SyncDescriptor
(
SettingsManager
));
const
instantiationService
=
new
InstantiationService
(
services
);
// On some platforms we need to manually read from the global environment variables
// and assign them to the process environment (e.g. when doubleclick app on Mac)
getUserEnvironment
()
...
...
@@ -314,7 +274,8 @@ getUserEnvironment()
// Make sure the NLS Config travels to the rendered process
// See also https://github.com/Microsoft/vscode/issues/4558
userEnv
[
'
VSCODE_NLS_CONFIG
'
]
=
process
.
env
[
'
VSCODE_NLS_CONFIG
'
];
return
setupIPC
()
.
then
(
ipcServer
=>
main
(
ipcServer
,
userEnv
));
return
instantiationService
.
invokeFunction
(
setupIPC
)
.
then
(
ipcServer
=>
instantiationService
.
invokeFunction
(
main
,
ipcServer
,
userEnv
));
})
.
done
(
null
,
quit
);
\ No newline at end of file
.
done
(
null
,
err
=>
instantiationService
.
invokeFunction
(
quit
,
err
));
\ No newline at end of file
src/vs/workbench/electron-main/menus.ts
浏览文件 @
f4321ecf
此差异已折叠。
点击以展开。
src/vs/workbench/electron-main/settings.ts
浏览文件 @
f4321ecf
...
...
@@ -6,21 +6,34 @@
'
use strict
'
;
import
{
app
}
from
'
electron
'
;
import
{
ServiceIdentifier
,
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
UserSettings
,
ISettings
}
from
'
vs/workbench/node/userSettings
'
;
import
{
IEnvService
}
from
'
vs/workbench/electron-main/env
'
;
import
Event
from
'
vs/base/common/event
'
;
export
const
ISettingsManager
=
createDecorator
<
ISettingsManager
>
(
'
settingsManager
'
);
export
interface
ISettingsManager
{
serviceId
:
ServiceIdentifier
<
any
>
;
globalSettings
:
ISettings
;
loadSync
():
boolean
;
getValue
(
key
:
string
,
fallback
?:
any
):
any
;
onChange
:
Event
<
ISettings
>
;
}
import
env
=
require
(
'
vs/workbench/electron-main/env
'
);
import
{
UserSettings
}
from
'
vs/workbench/node/userSettings
'
;
export
class
SettingsManager
extends
UserSettings
implements
ISettingsManager
{
export
class
SettingsManager
extends
UserSettings
{
serviceId
=
ISettingsManager
;
constructor
()
{
super
(
env
.
appSettingsPath
,
env
.
appKeybindingsPath
);
constructor
(
@
IEnvService
envService
:
IEnvService
)
{
super
(
env
Service
.
appSettingsPath
,
envService
.
appKeybindingsPath
);
app
.
on
(
'
will-quit
'
,
()
=>
{
this
.
dispose
();
});
}
public
loadSync
():
boolean
{
loadSync
():
boolean
{
const
settingsChanged
=
super
.
loadSync
();
// Store into global so that any renderer can access the value with remote.getGlobal()
...
...
@@ -30,6 +43,4 @@ export class SettingsManager extends UserSettings {
return
settingsChanged
;
}
}
export
const
manager
=
new
SettingsManager
();
\ No newline at end of file
}
\ No newline at end of file
src/vs/workbench/electron-main/sharedProcess.ts
浏览文件 @
f4321ecf
...
...
@@ -8,32 +8,33 @@ import URI from 'vs/base/common/uri';
import
{
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
assign
}
from
'
vs/base/common/objects
'
;
import
{
IEnvironment
}
from
'
vs/platform/workspace/common/workspace
'
;
import
env
=
require
(
'
vs/workbench/electron-main/env
'
);
import
{
manager
as
SettingsManager
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
Instance
as
UpdateManager
}
from
'
vs/workbench/electron-main/update-manager
'
;
import
{
IEnvService
}
from
'
vs/workbench/electron-main/env
'
;
import
{
ISettingsManager
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
IUpdateManager
}
from
'
vs/workbench/electron-main/update-manager
'
;
import
{
ServicesAccessor
}
from
'
vs/platform/instantiation/common/instantiation
'
;
const
boostrapPath
=
URI
.
parse
(
require
.
toUrl
(
'
bootstrap
'
)).
fsPath
;
function
getEnvironment
():
IEnvironment
{
let
configuration
:
IEnvironment
=
assign
({},
env
.
cliArgs
);
function
getEnvironment
(
envService
:
IEnvService
,
updateManager
:
IUpdateManager
):
IEnvironment
{
let
configuration
:
IEnvironment
=
assign
({},
env
Service
.
cliArgs
);
configuration
.
execPath
=
process
.
execPath
;
configuration
.
appName
=
env
.
product
.
nameLong
;
configuration
.
appRoot
=
env
.
appRoot
;
configuration
.
version
=
env
.
version
;
configuration
.
commitHash
=
env
.
product
.
commit
;
configuration
.
appSettingsHome
=
env
.
appSettingsHome
;
configuration
.
appSettingsPath
=
env
.
appSettingsPath
;
configuration
.
appKeybindingsPath
=
env
.
appKeybindingsPath
;
configuration
.
userExtensionsHome
=
env
.
userExtensionsHome
;
configuration
.
isBuilt
=
env
.
isBuilt
;
configuration
.
updateFeedUrl
=
U
pdateManager
.
feedUrl
;
configuration
.
updateChannel
=
U
pdateManager
.
channel
;
configuration
.
extensionsGallery
=
env
.
product
.
extensionsGallery
;
configuration
.
appName
=
env
Service
.
product
.
nameLong
;
configuration
.
appRoot
=
env
Service
.
appRoot
;
configuration
.
version
=
env
Service
.
version
;
configuration
.
commitHash
=
env
Service
.
product
.
commit
;
configuration
.
appSettingsHome
=
env
Service
.
appSettingsHome
;
configuration
.
appSettingsPath
=
env
Service
.
appSettingsPath
;
configuration
.
appKeybindingsPath
=
env
Service
.
appKeybindingsPath
;
configuration
.
userExtensionsHome
=
env
Service
.
userExtensionsHome
;
configuration
.
isBuilt
=
env
Service
.
isBuilt
;
configuration
.
updateFeedUrl
=
u
pdateManager
.
feedUrl
;
configuration
.
updateChannel
=
u
pdateManager
.
channel
;
configuration
.
extensionsGallery
=
env
Service
.
product
.
extensionsGallery
;
return
configuration
;
}
function
_spawnSharedProcess
():
cp
.
ChildProcess
{
function
_spawnSharedProcess
(
envService
:
IEnvService
,
updateManager
:
IUpdateManager
,
settingsManager
:
ISettingsManager
):
cp
.
ChildProcess
{
// Make sure the nls configuration travels to the shared process.
const
opts
=
{
env
:
assign
(
assign
({},
process
.
env
),
{
...
...
@@ -47,10 +48,10 @@ function _spawnSharedProcess(): cp.ChildProcess {
result
.
once
(
'
message
'
,
()
=>
{
result
.
send
({
configuration
:
{
env
:
getEnvironment
()
env
:
getEnvironment
(
envService
,
updateManager
)
},
contextServiceOptions
:
{
globalSettings
:
S
ettingsManager
.
globalSettings
globalSettings
:
s
ettingsManager
.
globalSettings
}
});
});
...
...
@@ -60,7 +61,11 @@ function _spawnSharedProcess(): cp.ChildProcess {
let
spawnCount
=
0
;
export
function
spawnSharedProcess
():
IDisposable
{
export
function
spawnSharedProcess
(
accessor
:
ServicesAccessor
):
IDisposable
{
const
envService
=
accessor
.
get
(
IEnvService
);
const
updateManager
=
accessor
.
get
(
IUpdateManager
);
const
settingsManager
=
accessor
.
get
(
ISettingsManager
);
let
child
:
cp
.
ChildProcess
;
const
spawn
=
()
=>
{
...
...
@@ -68,7 +73,7 @@ export function spawnSharedProcess(): IDisposable {
return
;
}
child
=
_spawnSharedProcess
();
child
=
_spawnSharedProcess
(
envService
,
updateManager
,
settingsManager
);
child
.
on
(
'
exit
'
,
spawn
);
};
...
...
src/vs/workbench/electron-main/storage.ts
浏览文件 @
f4321ecf
...
...
@@ -9,82 +9,100 @@
import
path
=
require
(
'
path
'
);
import
fs
=
require
(
'
fs
'
);
import
events
=
require
(
'
events
'
);
import
env
=
require
(
'
vs/workbench/electron-main/env
'
);
const
dbPath
=
path
.
join
(
env
.
appHome
,
'
storage.json
'
);
let
database
:
any
=
null
;
import
{
ServiceIdentifier
,
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
const
EventTypes
=
{
STORE
:
'
store
'
};
const
eventEmitter
=
new
events
.
EventEmitter
();
export
function
onStore
<
T
>
(
clb
:
(
key
:
string
,
oldValue
:
T
,
newValue
:
T
)
=>
void
):
()
=>
void
{
eventEmitter
.
addListener
(
EventTypes
.
STORE
,
clb
);
export
const
IStorageService
=
createDecorator
<
IStorageService
>
(
'
storageService
'
);
return
()
=>
eventEmitter
.
removeListener
(
EventTypes
.
STORE
,
clb
);
export
interface
IStorageService
{
serviceId
:
ServiceIdentifier
<
any
>
;
onStore
<
T
>
(
clb
:
(
key
:
string
,
oldValue
:
T
,
newValue
:
T
)
=>
void
):
()
=>
void
;
getItem
<
T
>
(
key
:
string
,
defaultValue
?:
T
):
T
;
setItem
(
key
:
string
,
data
:
any
):
void
;
removeItem
(
key
:
string
):
void
;
}
export
function
getItem
<
T
>
(
key
:
string
,
defaultValue
?:
T
):
T
{
if
(
!
database
)
{
database
=
load
();
}
export
class
StorageService
implements
IStorageService
{
serviceId
=
IStorageService
;
private
dbPath
:
string
;
private
database
:
any
=
null
;
private
eventEmitter
=
new
events
.
EventEmitter
();
const
res
=
database
[
key
];
if
(
typeof
res
===
'
undefined
'
)
{
return
defaultValue
;
constructor
(@
env
.
IEnvService
private
envService
:
env
.
IEnvService
)
{
this
.
dbPath
=
path
.
join
(
envService
.
appHome
,
'
storage.json
'
);
}
return
database
[
key
];
}
onStore
<
T
>
(
clb
:
(
key
:
string
,
oldValue
:
T
,
newValue
:
T
)
=>
void
):
()
=>
void
{
this
.
eventEmitter
.
addListener
(
EventTypes
.
STORE
,
clb
);
export
function
setItem
(
key
:
string
,
data
:
any
):
void
{
if
(
!
database
)
{
database
=
load
();
return
()
=>
this
.
eventEmitter
.
removeListener
(
EventTypes
.
STORE
,
clb
);
}
// Shortcut for primitives that did not change
if
(
typeof
data
===
'
string
'
||
typeof
data
===
'
number
'
||
typeof
data
===
'
boolean
'
)
{
if
(
database
[
key
]
===
data
)
{
return
;
getItem
<
T
>
(
key
:
string
,
defaultValue
?:
T
):
T
{
if
(
!
this
.
database
)
{
this
.
database
=
this
.
load
();
}
const
res
=
this
.
database
[
key
];
if
(
typeof
res
===
'
undefined
'
)
{
return
defaultValue
;
}
return
this
.
database
[
key
];
}
let
oldValue
=
database
[
key
];
database
[
key
]
=
data
;
save
();
setItem
(
key
:
string
,
data
:
any
):
void
{
if
(
!
this
.
database
)
{
this
.
database
=
this
.
load
();
}
eventEmitter
.
emit
(
EventTypes
.
STORE
,
key
,
oldValue
,
data
);
}
// Shortcut for primitives that did not change
if
(
typeof
data
===
'
string
'
||
typeof
data
===
'
number
'
||
typeof
data
===
'
boolean
'
)
{
if
(
this
.
database
[
key
]
===
data
)
{
return
;
}
}
let
oldValue
=
this
.
database
[
key
];
this
.
database
[
key
]
=
data
;
this
.
save
();
export
function
removeItem
(
key
:
string
):
void
{
if
(
!
database
)
{
database
=
load
();
this
.
eventEmitter
.
emit
(
EventTypes
.
STORE
,
key
,
oldValue
,
data
);
}
if
(
database
[
key
])
{
let
oldValue
=
database
[
key
];
delete
database
[
key
];
save
();
removeItem
(
key
:
string
):
void
{
if
(
!
this
.
database
)
{
this
.
database
=
this
.
load
();
}
if
(
this
.
database
[
key
])
{
let
oldValue
=
this
.
database
[
key
];
delete
this
.
database
[
key
];
this
.
save
();
eventEmitter
.
emit
(
EventTypes
.
STORE
,
key
,
oldValue
,
null
);
this
.
eventEmitter
.
emit
(
EventTypes
.
STORE
,
key
,
oldValue
,
null
);
}
}
}
function
load
():
any
{
try
{
return
JSON
.
parse
(
fs
.
readFileSync
(
dbPath
).
toString
());
}
catch
(
error
)
{
if
(
env
.
cliArgs
.
verboseLogging
)
{
console
.
error
(
error
);
private
load
():
any
{
try
{
return
JSON
.
parse
(
fs
.
readFileSync
(
this
.
dbPath
).
toString
());
}
catch
(
error
)
{
if
(
this
.
envService
.
cliArgs
.
verboseLogging
)
{
console
.
error
(
error
);
}
return
{};
}
}
return
{};
private
save
():
void
{
fs
.
writeFileSync
(
this
.
dbPath
,
JSON
.
stringify
(
this
.
database
,
null
,
4
));
}
}
function
save
():
void
{
fs
.
writeFileSync
(
dbPath
,
JSON
.
stringify
(
database
,
null
,
4
));
}
\ No newline at end of file
src/vs/workbench/electron-main/update-manager.ts
浏览文件 @
f4321ecf
...
...
@@ -8,14 +8,14 @@
import
fs
=
require
(
'
fs
'
);
import
path
=
require
(
'
path
'
);
import
events
=
require
(
'
events
'
);
import
electron
=
require
(
'
electron
'
);
import
platform
=
require
(
'
vs/base/common/platform
'
);
import
env
=
require
(
'
vs/workbench/electron-main/env
'
);
import
settings
=
require
(
'
vs/workbench/electron-main/settings
'
);
import
{
Win32AutoUpdaterImpl
}
from
'
vs/workbench/electron-main/auto-updater.win32
'
;
import
{
LinuxAutoUpdaterImpl
}
from
'
vs/workbench/electron-main/auto-updater.linux
'
;
import
{
manager
as
Lifecycle
}
from
'
vs/workbench/electron-main/lifecycle
'
;
import
{
IEnvService
,
getPlatformIdentifier
}
from
'
vs/workbench/electron-main/env
'
;
import
{
ISettingsManager
}
from
'
vs/workbench/electron-main/settings
'
;
import
{
Win32AutoUpdaterImpl
}
from
'
vs/workbench/electron-main/auto-updater.win32
'
;
import
{
LinuxAutoUpdaterImpl
}
from
'
vs/workbench/electron-main/auto-updater.linux
'
;
import
{
ILifecycleService
}
from
'
vs/workbench/electron-main/lifecycle
'
;
import
{
ServiceIdentifier
,
createDecorator
,
IInstantiationService
}
from
'
vs/platform/instantiation/common/instantiation
'
;
export
enum
State
{
Uninitialized
,
...
...
@@ -42,7 +42,23 @@ interface IAutoUpdater extends NodeJS.EventEmitter {
checkForUpdates
():
void
;
}
export
class
UpdateManager
extends
events
.
EventEmitter
{
export
const
IUpdateManager
=
createDecorator
<
IUpdateManager
>
(
'
updateManager
'
);
export
interface
IUpdateManager
{
serviceId
:
ServiceIdentifier
<
any
>
;
feedUrl
:
string
;
channel
:
string
;
initialize
():
void
;
state
:
State
;
availableUpdate
:
IUpdate
;
lastCheckDate
:
Date
;
checkForUpdates
(
explicit
:
boolean
):
void
;
on
(
event
:
string
,
listener
:
Function
):
this
;
}
export
class
UpdateManager
extends
events
.
EventEmitter
implements
IUpdateManager
{
serviceId
=
IUpdateManager
;
private
_state
:
State
;
private
explicitState
:
ExplicitState
;
...
...
@@ -52,7 +68,12 @@ export class UpdateManager extends events.EventEmitter {
private
_feedUrl
:
string
;
private
_channel
:
string
;
constructor
()
{
constructor
(
@
IInstantiationService
instantiationService
:
IInstantiationService
,
@
ILifecycleService
private
lifecycleService
:
ILifecycleService
,
@
IEnvService
private
envService
:
IEnvService
,
@
ISettingsManager
private
settingsManager
:
ISettingsManager
)
{
super
();
this
.
_state
=
State
.
Uninitialized
;
...
...
@@ -63,9 +84,9 @@ export class UpdateManager extends events.EventEmitter {
this
.
_channel
=
null
;
if
(
platform
.
isWindows
)
{
this
.
raw
=
new
Win32AutoUpdaterImpl
(
);
this
.
raw
=
instantiationService
.
createInstance
(
Win32AutoUpdaterImpl
);
}
else
if
(
platform
.
isLinux
)
{
this
.
raw
=
new
LinuxAutoUpdaterImpl
(
);
this
.
raw
=
instantiationService
.
createInstance
(
LinuxAutoUpdaterImpl
);
}
else
if
(
platform
.
isMacintosh
)
{
this
.
raw
=
electron
.
autoUpdater
;
}
...
...
@@ -122,7 +143,7 @@ export class UpdateManager extends events.EventEmitter {
}
private
quitAndUpdate
(
rawQuitAndUpdate
:
()
=>
void
):
void
{
Lifecycl
e
.
quit
().
done
(
vetod
=>
{
this
.
lifecycleServic
e
.
quit
().
done
(
vetod
=>
{
if
(
vetod
)
{
return
;
}
...
...
@@ -151,8 +172,8 @@ export class UpdateManager extends events.EventEmitter {
return
;
// already initialized
}
const
channel
=
UpdateManager
.
getUpdateChannel
();
const
feedUrl
=
UpdateManager
.
getUpdateFeedUrl
(
channel
);
const
channel
=
this
.
getUpdateChannel
();
const
feedUrl
=
this
.
getUpdateFeedUrl
(
channel
);
if
(
!
feedUrl
)
{
return
;
// updates not available
...
...
@@ -203,12 +224,12 @@ export class UpdateManager extends events.EventEmitter {
this
.
emit
(
'
change
'
);
}
private
static
getUpdateChannel
():
string
{
const
channel
=
settings
.
m
anager
.
getValue
(
'
update.channel
'
)
||
'
default
'
;
return
channel
===
'
none
'
?
null
:
env
.
quality
;
private
getUpdateChannel
():
string
{
const
channel
=
this
.
settingsM
anager
.
getValue
(
'
update.channel
'
)
||
'
default
'
;
return
channel
===
'
none
'
?
null
:
this
.
envService
.
quality
;
}
private
static
getUpdateFeedUrl
(
channel
:
string
):
string
{
private
getUpdateFeedUrl
(
channel
:
string
):
string
{
if
(
!
channel
)
{
return
null
;
}
...
...
@@ -217,12 +238,10 @@ export class UpdateManager extends events.EventEmitter {
return
null
;
}
if
(
!
env
.
updateUrl
||
!
env
.
product
.
commit
)
{
if
(
!
this
.
envService
.
updateUrl
||
!
this
.
envService
.
product
.
commit
)
{
return
null
;
}
return
`
${
env
.
updateUrl
}
/api/update/
${
env
.
getPlatformIdentifier
()
}
/
${
channel
}
/
${
env
.
product
.
commit
}
`
;
return
`
${
this
.
envService
.
updateUrl
}
/api/update/
${
getPlatformIdentifier
()
}
/
${
channel
}
/
${
this
.
envService
.
product
.
commit
}
`
;
}
}
export
const
Instance
=
new
UpdateManager
();
src/vs/workbench/electron-main/window.ts
浏览文件 @
f4321ecf
...
...
@@ -12,8 +12,9 @@ import {shell, screen, BrowserWindow} from 'electron';
import
{
TPromise
,
TValueCallback
}
from
'
vs/base/common/winjs.base
'
;
import
platform
=
require
(
'
vs/base/common/platform
'
);
import
objects
=
require
(
'
vs/base/common/objects
'
);
import
env
=
require
(
'
vs/workbench/electron-main/env
'
)
;
import
{
ICommandLineArguments
,
IEnvService
,
IProcessEnvironment
}
from
'
vs/workbench/electron-main/env
'
;
import
storage
=
require
(
'
vs/workbench/electron-main/storage
'
);
import
{
ILogService
}
from
'
./log
'
;
export
interface
IWindowState
{
width
?:
number
;
...
...
@@ -86,7 +87,7 @@ export interface IPath {
installExtensionPath
?:
boolean
;
}
export
interface
IWindowConfiguration
extends
env
.
ICommandLineArguments
{
export
interface
IWindowConfiguration
extends
ICommandLineArguments
{
execPath
:
string
;
version
:
string
;
appName
:
string
;
...
...
@@ -121,7 +122,7 @@ export interface IWindowConfiguration extends env.ICommandLineArguments {
licenseUrl
:
string
;
productDownloadUrl
:
string
;
enableTelemetry
:
boolean
;
userEnv
:
env
.
IProcessEnvironment
;
userEnv
:
IProcessEnvironment
;
aiConfig
:
{
key
:
string
;
asimovKey
:
string
;
...
...
@@ -154,7 +155,12 @@ export class VSCodeWindow {
private
currentConfig
:
IWindowConfiguration
;
private
pendingLoadConfig
:
IWindowConfiguration
;
constructor
(
config
:
IWindowCreationOptions
)
{
constructor
(
config
:
IWindowCreationOptions
,
@
ILogService
private
logService
:
ILogService
,
@
IEnvService
private
envService
:
IEnvService
,
@
storage
.
IStorageService
private
storageService
:
storage
.
IStorageService
)
{
this
.
_lastFocusTime
=
-
1
;
this
.
_readyState
=
ReadyState
.
NONE
;
this
.
_extensionDevelopmentPath
=
config
.
extensionDevelopmentPath
;
...
...
@@ -164,7 +170,7 @@ export class VSCodeWindow {
this
.
restoreWindowState
(
config
.
state
);
// For VS theme we can show directly because background is white
const
usesLightTheme
=
/vs
(
$|
)
/
.
test
(
storag
e
.
getItem
<
string
>
(
VSCodeWindow
.
themeStorageKey
));
const
usesLightTheme
=
/vs
(
$|
)
/
.
test
(
this
.
storageServic
e
.
getItem
<
string
>
(
VSCodeWindow
.
themeStorageKey
));
let
showDirectly
=
true
;
// set to false to prevent background color flash (flash should be fixed for Electron >= 0.37.x)
if
(
showDirectly
&&
!
global
.
windowShow
)
{
global
.
windowShow
=
new
Date
().
getTime
();
...
...
@@ -179,14 +185,14 @@ export class VSCodeWindow {
minWidth
:
VSCodeWindow
.
MIN_WIDTH
,
minHeight
:
VSCodeWindow
.
MIN_HEIGHT
,
show
:
showDirectly
&&
this
.
currentWindowMode
!==
WindowMode
.
Maximized
,
// in case we are maximized, only show later after the call to maximize (see below)
title
:
env
.
product
.
nameLong
,
title
:
this
.
envService
.
product
.
nameLong
,
webPreferences
:
{
'
backgroundThrottling
'
:
false
// by default if Code is in the background, intervals and timeouts get throttled
}
};
if
(
platform
.
isLinux
)
{
options
.
icon
=
path
.
join
(
env
.
appRoot
,
'
resources/linux/code.png
'
);
// Windows and Mac are better off using the embedded icon(s)
options
.
icon
=
path
.
join
(
this
.
envService
.
appRoot
,
'
resources/linux/code.png
'
);
// Windows and Mac are better off using the embedded icon(s)
}
// Create the browser window.
...
...
@@ -205,7 +211,7 @@ export class VSCodeWindow {
this
.
_lastFocusTime
=
new
Date
().
getTime
();
// since we show directly, we need to set the last focus time too
}
if
(
storag
e
.
getItem
<
boolean
>
(
VSCodeWindow
.
menuBarHiddenKey
,
false
))
{
if
(
this
.
storageServic
e
.
getItem
<
boolean
>
(
VSCodeWindow
.
menuBarHiddenKey
,
false
))
{
this
.
setMenuBarVisibility
(
false
);
// respect configured menu bar visibility
}
...
...
@@ -342,7 +348,7 @@ export class VSCodeWindow {
// Prevent any kind of navigation triggered by the user!
// But do not touch this in dev version because it will prevent "Reload" from dev tools
if
(
env
.
isBuilt
)
{
if
(
this
.
envService
.
isBuilt
)
{
this
.
_win
.
webContents
.
on
(
'
will-navigate
'
,
(
event
:
Event
)
=>
{
if
(
event
)
{
event
.
preventDefault
();
...
...
@@ -383,7 +389,7 @@ export class VSCodeWindow {
}
}
public
reload
(
cli
?:
env
.
ICommandLineArguments
):
void
{
public
reload
(
cli
?:
ICommandLineArguments
):
void
{
// Inherit current properties but overwrite some
let
configuration
:
IWindowConfiguration
=
objects
.
mixin
({},
this
.
currentConfig
);
...
...
@@ -458,7 +464,7 @@ export class VSCodeWindow {
try
{
state
=
this
.
validateWindowState
(
state
);
}
catch
(
err
)
{
env
.
log
(
`Unexpected error validating window state:
${
err
}
\n
${
err
.
stack
}
`
);
// somehow display API can be picky about the state to validate
this
.
logService
.
log
(
`Unexpected error validating window state:
${
err
}
\n
${
err
.
stack
}
`
);
// somehow display API can be picky about the state to validate
}
}
...
...
@@ -558,7 +564,7 @@ export class VSCodeWindow {
if
(
willBeFullScreen
)
{
this
.
setMenuBarVisibility
(
false
);
}
else
{
this
.
setMenuBarVisibility
(
!
storag
e
.
getItem
<
boolean
>
(
VSCodeWindow
.
menuBarHiddenKey
,
false
));
// restore as configured
this
.
setMenuBarVisibility
(
!
this
.
storageServic
e
.
getItem
<
boolean
>
(
VSCodeWindow
.
menuBarHiddenKey
,
false
));
// restore as configured
}
}
}
...
...
src/vs/workbench/electron-main/windows.ts
浏览文件 @
f4321ecf
此差异已折叠。
点击以展开。
src/vs/workbench/parts/git/electron-main/index.ts
已删除
100644 → 0
浏览文件 @
b717d96a
/*---------------------------------------------------------------------------------------------
* 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
env
=
require
(
'
vs/workbench/electron-main/env
'
);
import
events
=
require
(
'
vs/base/common/eventEmitter
'
);
import
platform
=
require
(
'
vs/base/common/platform
'
);
import
{
ipcMain
as
ipc
,
BrowserWindow
}
from
'
electron
'
;
interface
ICredentialsContext
{
id
:
number
;
host
:
string
;
command
:
string
;
}
interface
ICredentials
{
username
:
string
;
password
:
string
;
}
interface
ICredentialsResult
{
id
:
number
;
credentials
:
ICredentials
;
}
interface
IContext
{
credentials
:
ICredentials
;
window
:
Electron
.
BrowserWindow
;
}
export
function
configure
(
bus
:
events
.
EventEmitter
):
void
{
var
cache
:
{
[
id
:
string
]:
IContext
}
=
Object
.
create
(
null
);
ipc
.
on
(
'
git:askpass
'
,
(
event
,
result
:
ICredentialsResult
)
=>
{
cache
[
result
.
id
].
credentials
=
result
.
credentials
;
});
bus
.
addListener
(
'
git:askpass
'
,
(
context
:
ICredentialsContext
)
=>
{
var
cachedResult
=
cache
[
context
.
id
];
if
(
typeof
cachedResult
!==
'
undefined
'
)
{
bus
.
emit
(
'
git:askpass:
'
+
context
.
id
,
cachedResult
.
credentials
);
return
;
}
if
(
context
.
command
===
'
fetch
'
)
{
bus
.
emit
(
'
git:askpass:
'
+
context
.
id
,
{
id
:
context
.
id
,
credentials
:
{
username
:
''
,
password
:
''
}});
return
;
}
var
win
=
new
BrowserWindow
({
alwaysOnTop
:
true
,
skipTaskbar
:
true
,
resizable
:
false
,
width
:
450
,
height
:
platform
.
isWindows
?
280
:
260
,
show
:
true
,
title
:
env
.
product
.
nameLong
});
win
.
setMenuBarVisibility
(
false
);
cache
[
context
.
id
]
=
{
window
:
win
,
credentials
:
null
};
win
.
loadURL
(
require
.
toUrl
(
'
vs/workbench/parts/git/electron-main/index.html
'
));
win
.
webContents
.
executeJavaScript
(
'
init(
'
+
JSON
.
stringify
(
context
)
+
'
)
'
);
win
.
once
(
'
closed
'
,
()
=>
{
bus
.
emit
(
'
git:askpass:
'
+
context
.
id
,
cache
[
context
.
id
].
credentials
);
setTimeout
(
function
()
{
delete
cache
[
context
.
id
];
},
1000
*
10
);
});
});
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录