Merge branch 'master' into aeschli/html-extension

This commit is contained in:
Martin Aeschlimann 2016-09-14 20:12:26 +02:00
commit 8934bd2ba8
58 changed files with 979 additions and 305 deletions

View file

@ -38,7 +38,7 @@
}, },
{ {
"name": "chromium", "name": "chromium",
"version": "49.0.2623.75", "version": "52.0.2743.82",
"repositoryURL": "http://www.chromium.org/Home", "repositoryURL": "http://www.chromium.org/Home",
"licenseDetail": [ "licenseDetail": [
"BSD License", "BSD License",
@ -74,20 +74,20 @@
}, },
{ {
"name": "libchromiumcontent", "name": "libchromiumcontent",
"version": "49.0.2623.75", "version": "52.0.2743.82",
"license": "MIT", "license": "MIT",
"repositoryURL": "https://github.com/electron/libchromiumcontent", "repositoryURL": "https://github.com/electron/libchromiumcontent",
"isProd": true "isProd": true
}, },
{ {
"name": "nodejs", "name": "nodejs",
"version": "5.10.0", "version": "6.3.0",
"repositoryURL": "https://github.com/nodejs/node", "repositoryURL": "https://github.com/nodejs/node",
"isProd": true "isProd": true
}, },
{ {
"name": "electron", "name": "electron",
"version": "0.37.6", "version": "1.3.5",
"license": "MIT", "license": "MIT",
"repositoryURL": "https://github.com/electron/electron", "repositoryURL": "https://github.com/electron/electron",
"isProd": true "isProd": true

View file

@ -1,5 +1,5 @@
environment: environment:
ATOM_SHELL_INTERNAL_RUN_AS_NODE: 1 ELECTRON_RUN_AS_NODE: 1
VSCODE_BUILD_VERBOSE: true VSCODE_BUILD_VERBOSE: true
install: install:

View file

@ -230,6 +230,7 @@ function packageTask(platform, arch, opts) {
if (platform === 'win32') { if (platform === 'win32') {
result = es.merge(result, gulp.src('resources/win32/bin/code.js', { base: 'resources/win32' })); result = es.merge(result, gulp.src('resources/win32/bin/code.js', { base: 'resources/win32' }));
result = es.merge(result, gulp.src('resources/win32/bin/cat.exe', { base: 'resources/win32' }));
result = es.merge(result, gulp.src('resources/win32/bin/code.cmd', { base: 'resources/win32' }) result = es.merge(result, gulp.src('resources/win32/bin/code.cmd', { base: 'resources/win32' })
.pipe(replace('@@NAME@@', product.nameShort)) .pipe(replace('@@NAME@@', product.nameShort))

View file

@ -3,11 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
var es = require('event-stream'); const es = require('event-stream');
/** Ugly hack for gulp-tsb */ /** Ugly hack for gulp-tsb */
function handleDeletions() { function handleDeletions() {
return es.mapSync(function (f) { return es.mapSync(f => {
if (/\.ts$/.test(f.relative) && !f.contents) { if (/\.ts$/.test(f.relative) && !f.contents) {
f.contents = new Buffer(''); f.contents = new Buffer('');
f.stat = { mtime: new Date() }; f.stat = { mtime: new Date() };
@ -17,7 +17,9 @@ function handleDeletions() {
}); });
} }
var watch = process.platform === 'win32' ? require('./watch-win32') : require('gulp-watch'); const watch = process.platform === 'win32'
? require('./watch-win32')
: require('gulp-watch');
module.exports = function () { module.exports = function () {
return watch.apply(null, arguments) return watch.apply(null, arguments)

View file

@ -1,10 +1,10 @@
{ {
"name": "watch", "name": "watch",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"author": "Microsoft ", "author": "Microsoft ",
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"gulp-watch": "^4.3.5" "gulp-watch": "^4.3.9"
} }
} }

View file

@ -3,11 +3,32 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
var win = "Please run '.\\scripts\\npm.bat install' instead."; const path = require('path');
var nix = "Please run './scripts/npm.sh install' instead."; const cp = require('child_process');
if (process.env['npm_config_disturl'] !== 'https://atom.io/download/atom-shell') { if (process.env['npm_config_disturl'] !== 'https://atom.io/download/atom-shell') {
console.error("You can't use plain npm to install Code's dependencies."); console.error("You can't use plain npm to install Code's dependencies.");
console.error(/^win/.test(process.platform) ? win : nix); console.error(
/^win/.test(process.platform)
? "Please run '.\\scripts\\npm.bat install' instead."
: "Please run './scripts/npm.sh install' instead."
);
process.exit(1); process.exit(1);
} }
// make sure we install gulp watch for the system installed
// node, since that is the driver of gulp
if (process.platform !== 'win32') {
const env = Object.assign({}, process.env);
delete env['npm_config_disturl'];
delete env['npm_config_target'];
delete env['npm_config_runtime'];
cp.spawnSync('npm', ['install'], {
cwd: path.join(path.dirname(__dirname), 'lib', 'watch'),
stdio: 'inherit',
env
});
}

View file

@ -1,6 +1,6 @@
{ {
"account": "monacobuild", "account": "monacobuild",
"container": "debuggers", "container": "debuggers",
"zip": "d643199/node-debug.zip", "zip": "9263600/node-debug.zip",
"output": "" "output": ""
} }

View file

@ -48,7 +48,7 @@ function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string
newEnv['STDIN_PIPE_NAME'] = stdInPipeName; newEnv['STDIN_PIPE_NAME'] = stdInPipeName;
newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName; newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName;
newEnv['STDERR_PIPE_NAME'] = stdErrPipeName; newEnv['STDERR_PIPE_NAME'] = stdErrPipeName;
newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1'; newEnv['ELECTRON_RUN_AS_NODE'] = '1';
return newEnv; return newEnv;
} }

View file

@ -31,7 +31,7 @@ var stdErrPipeName = process.env['STDERR_PIPE_NAME'];
log('STDIN_PIPE_NAME: ' + stdInPipeName); log('STDIN_PIPE_NAME: ' + stdInPipeName);
log('STDOUT_PIPE_NAME: ' + stdOutPipeName); log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
log('STDERR_PIPE_NAME: ' + stdErrPipeName); log('STDERR_PIPE_NAME: ' + stdErrPipeName);
log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']); log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
// stdout redirection to named pipe // stdout redirection to named pipe
(function() { (function() {
@ -147,7 +147,7 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A
delete process.env['STDIN_PIPE_NAME']; delete process.env['STDIN_PIPE_NAME'];
delete process.env['STDOUT_PIPE_NAME']; delete process.env['STDOUT_PIPE_NAME'];
delete process.env['STDERR_PIPE_NAME']; delete process.env['STDERR_PIPE_NAME'];
delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; delete process.env['ELECTRON_RUN_AS_NODE'];
require(program); require(program);

2
npm-shrinkwrap.json generated
View file

@ -414,7 +414,7 @@
"from": "vscode-textmate@2.1.1", "from": "vscode-textmate@2.1.1",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-2.1.1.tgz" "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-2.1.1.tgz"
}, },
"windows-mutex": { "windows-mutex": {
"version": "0.2.0", "version": "0.2.0",
"from": "windows-mutex@>=0.2.0 <0.3.0", "from": "windows-mutex@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/windows-mutex/-/windows-mutex-0.2.0.tgz" "resolved": "https://registry.npmjs.org/windows-mutex/-/windows-mutex-0.2.0.tgz"

View file

@ -1,7 +1,7 @@
{ {
"name": "code-oss-dev", "name": "code-oss-dev",
"version": "1.6.0", "version": "1.6.0",
"electronVersion": "0.37.6", "electronVersion": "1.3.5",
"distro": "3d44b35db8d394d6d7b2bc224675735a0a8f2704", "distro": "3d44b35db8d394d6d7b2bc224675735a0a8f2704",
"author": { "author": {
"name": "Microsoft Corporation" "name": "Microsoft Corporation"
@ -69,7 +69,6 @@
"gulp-uglify": "^1.4.1", "gulp-uglify": "^1.4.1",
"gulp-util": "^3.0.6", "gulp-util": "^3.0.6",
"gulp-vinyl-zip": "^1.2.2", "gulp-vinyl-zip": "^1.2.2",
"gulp-watch": "4.3.6",
"innosetup-compiler": "^5.5.60", "innosetup-compiler": "^5.5.60",
"is": "^3.1.0", "is": "^3.1.0",
"istanbul": "^0.3.17", "istanbul": "^0.3.17",

View file

@ -7,5 +7,5 @@ function realpath() { /usr/bin/python -c "import os,sys; print os.path.realpath(
CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")" CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")"
ELECTRON="$CONTENTS/MacOS/Electron" ELECTRON="$CONTENTS/MacOS/Electron"
CLI="$CONTENTS/Resources/app/out/cli.js" CLI="$CONTENTS/Resources/app/out/cli.js"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $? exit $?

View file

@ -33,5 +33,5 @@ fi
ELECTRON="$VSCODE_PATH/@@NAME@@" ELECTRON="$VSCODE_PATH/@@NAME@@"
CLI="$VSCODE_PATH/resources/app/out/cli.js" CLI="$VSCODE_PATH/resources/app/out/cli.js"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $? exit $?

BIN
resources/win32/bin/cat.exe Normal file

Binary file not shown.

View file

@ -1,6 +1,6 @@
@echo off @echo off
setlocal setlocal
set VSCODE_DEV= set VSCODE_DEV=
set ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 set ELECTRON_RUN_AS_NODE=1
call "%~dp0..\@@NAME@@.exe" "%~dp0..\resources\\app\\out\\cli.js" %* call "%~dp0..\@@NAME@@.exe" "%~dp0..\resources\\app\\out\\cli.js" %* | cat
endlocal endlocal

View file

@ -11,5 +11,5 @@ if [ "$(expr substr $(uname -s) 1 9)" == "CYGWIN_NT" ]; then
else else
CLI="$VSCODE_PATH/resources/app/out/cli.js" CLI="$VSCODE_PATH/resources/app/out/cli.js"
fi fi
ELECTRON_NO_ATTACH_CONSOLE=1 ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" | cat
exit $? exit $?

View file

@ -30,7 +30,7 @@ function code() {
CLI="$ROOT/out/cli.js" CLI="$ROOT/out/cli.js"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \ ELECTRON_RUN_AS_NODE=1 \
NODE_ENV=development \ NODE_ENV=development \
VSCODE_DEV=1 \ VSCODE_DEV=1 \
ELECTRON_ENABLE_LOGGING=1 \ ELECTRON_ENABLE_LOGGING=1 \

View file

@ -1,10 +1,8 @@
@echo off @echo off
setlocal setlocal
rem APPVEYOR Builds
if not "%APPVEYOR%" == "" ( if not "%APPVEYOR%" == "" (
set ELECTRON_NO_ATTACH_CONSOLE=1 set ELECTRON_RUN_AS_NODE=
set ATOM_SHELL_INTERNAL_RUN_AS_NODE=
) )
:: Integration Tests :: Integration Tests

View file

@ -1,17 +1,7 @@
@echo off @echo off
setlocal setlocal
set ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 set ELECTRON_RUN_AS_NODE=1
rem TFS Builds
if not "%BUILD_BUILDID%" == "" (
set ELECTRON_NO_ATTACH_CONSOLE=1
)
rem APPVEYOR Builds
if not "%APPVEYOR%" == "" (
set ELECTRON_NO_ATTACH_CONSOLE=1
)
pushd %~dp0\.. pushd %~dp0\..
@ -20,7 +10,15 @@ set NAMESHORT=%NAMESHORT: "=%
set NAMESHORT=%NAMESHORT:"=%.exe set NAMESHORT=%NAMESHORT:"=%.exe
set CODE=".build\electron\%NAMESHORT%" set CODE=".build\electron\%NAMESHORT%"
%CODE% .\node_modules\mocha\bin\_mocha %* rem TFS Builds
if not "%BUILD_BUILDID%" == "" (
%CODE% .\node_modules\mocha\bin\_mocha %*
)
rem Otherwise
if "%BUILD_BUILDID%" == "" (
%CODE% .\node_modules\mocha\bin\_mocha %* | .\resources\win32\bin\cat
)
popd popd
endlocal endlocal

View file

@ -30,11 +30,11 @@ test -d out || ./node_modules/.bin/gulp compile
# Unit Tests # Unit Tests
export VSCODE_DEV=1 export VSCODE_DEV=1
if [[ "$OSTYPE" == "darwin"* ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then
cd $ROOT ; ulimit -n 4096 ; ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \ cd $ROOT ; ulimit -n 4096 ; ELECTRON_RUN_AS_NODE=1 \
"$CODE" \ "$CODE" \
node_modules/mocha/bin/_mocha "$@" node_modules/mocha/bin/_mocha "$@"
else else
cd $ROOT ; ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \ cd $ROOT ; ELECTRON_RUN_AS_NODE=1 \
"$CODE" \ "$CODE" \
node_modules/mocha/bin/_mocha "$@" node_modules/mocha/bin/_mocha "$@"
fi fi

File diff suppressed because it is too large Load diff

View file

@ -36,9 +36,13 @@ export class PathLabelProvider implements ILabelProvider {
} }
} }
export function getPathLabel(arg1: URI | string, arg2?: URI | string | IWorkspaceProvider): string { export function getPathLabel(resource: URI | string, basePathProvider?: URI | string | IWorkspaceProvider): string {
let basepath = arg2 && getPath(arg2); const absolutePath = getPath(resource);
let absolutePath = getPath(arg1); if (!absolutePath) {
return null;
}
const basepath = basePathProvider && getPath(basePathProvider);
if (basepath && paths.isEqualOrParent(absolutePath, basepath)) { if (basepath && paths.isEqualOrParent(absolutePath, basepath)) {
if (basepath === absolutePath) { if (basepath === absolutePath) {
@ -48,7 +52,7 @@ export function getPathLabel(arg1: URI | string, arg2?: URI | string | IWorkspac
return paths.normalize(strings.ltrim(absolutePath.substr(basepath.length), paths.nativeSep), true); return paths.normalize(strings.ltrim(absolutePath.substr(basepath.length), paths.nativeSep), true);
} }
if (platform.isWindows && absolutePath[1] === ':') { if (platform.isWindows && absolutePath && absolutePath[1] === ':') {
return paths.normalize(absolutePath.charAt(0).toUpperCase() + absolutePath.slice(1), true); return paths.normalize(absolutePath.charAt(0).toUpperCase() + absolutePath.slice(1), true);
} }
@ -65,7 +69,7 @@ function getPath(arg1: URI | string | IWorkspaceProvider): string {
} }
if (types.isFunction((<IWorkspaceProvider>arg1).getWorkspace)) { if (types.isFunction((<IWorkspaceProvider>arg1).getWorkspace)) {
let ws = (<IWorkspaceProvider>arg1).getWorkspace(); const ws = (<IWorkspaceProvider>arg1).getWorkspace();
return ws ? ws.resource.fsPath : void 0; return ws ? ws.resource.fsPath : void 0;
} }

View file

@ -49,7 +49,7 @@ function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string
newEnv['STDIN_PIPE_NAME'] = stdInPipeName; newEnv['STDIN_PIPE_NAME'] = stdInPipeName;
newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName; newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName;
newEnv['STDERR_PIPE_NAME'] = stdErrPipeName; newEnv['STDERR_PIPE_NAME'] = stdErrPipeName;
newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1'; newEnv['ELECTRON_RUN_AS_NODE'] = '1';
return newEnv; return newEnv;
} }

View file

@ -33,7 +33,7 @@ var stdErrPipeName = process.env['STDERR_PIPE_NAME'];
log('STDIN_PIPE_NAME: ' + stdInPipeName); log('STDIN_PIPE_NAME: ' + stdInPipeName);
log('STDOUT_PIPE_NAME: ' + stdOutPipeName); log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
log('STDERR_PIPE_NAME: ' + stdErrPipeName); log('STDERR_PIPE_NAME: ' + stdErrPipeName);
log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']); log('ELECTRON_RUN_AS_NODE: ' + process.env['ELECTRON_RUN_AS_NODE']);
// stdout redirection to named pipe // stdout redirection to named pipe
(function() { (function() {
@ -149,7 +149,7 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A
delete process.env['STDIN_PIPE_NAME']; delete process.env['STDIN_PIPE_NAME'];
delete process.env['STDOUT_PIPE_NAME']; delete process.env['STDOUT_PIPE_NAME'];
delete process.env['STDERR_PIPE_NAME']; delete process.env['STDERR_PIPE_NAME'];
delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; delete process.env['ELECTRON_RUN_AS_NODE'];
require(program); require(program);

View file

@ -273,13 +273,13 @@ interface IEnv {
function getUnixShellEnvironment(): TPromise<IEnv> { function getUnixShellEnvironment(): TPromise<IEnv> {
const promise = new TPromise((c, e) => { const promise = new TPromise((c, e) => {
const runAsNode = process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; const runAsNode = process.env['ELECTRON_RUN_AS_NODE'];
const noAttach = process.env['ELECTRON_NO_ATTACH_CONSOLE']; const noAttach = process.env['ELECTRON_NO_ATTACH_CONSOLE'];
const mark = generateUuid().replace(/-/g, '').substr(0, 12); const mark = generateUuid().replace(/-/g, '').substr(0, 12);
const regex = new RegExp(mark + '(.*)' + mark); const regex = new RegExp(mark + '(.*)' + mark);
const env = assign({}, process.env, { const env = assign({}, process.env, {
ATOM_SHELL_INTERNAL_RUN_AS_NODE: '1', ELECTRON_RUN_AS_NODE: '1',
ELECTRON_NO_ATTACH_CONSOLE: '1' ELECTRON_NO_ATTACH_CONSOLE: '1'
}); });
@ -307,9 +307,9 @@ function getUnixShellEnvironment(): TPromise<IEnv> {
const env = JSON.parse(rawStripped); const env = JSON.parse(rawStripped);
if (runAsNode) { if (runAsNode) {
env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = runAsNode; env['ELECTRON_RUN_AS_NODE'] = runAsNode;
} else { } else {
delete env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; delete env['ELECTRON_RUN_AS_NODE'];
} }
if (noAttach) { if (noAttach) {

View file

@ -568,7 +568,7 @@ export class VSCodeWindow {
return null; return null;
} }
public getBounds(): Electron.Bounds { public getBounds(): Electron.Rectangle {
const pos = this.win.getPosition(); const pos = this.win.getPosition();
const dimension = this.win.getSize(); const dimension = this.win.getSize();

View file

@ -31,7 +31,7 @@ export function main(argv: string[]): TPromise<void> {
if (args.help) { if (args.help) {
console.log(buildHelpMessage(product.nameLong, product.applicationName, pkg.version)); console.log(buildHelpMessage(product.nameLong, product.applicationName, pkg.version));
} else if (args.version) { } else if (args.version) {
console.log(`${ pkg.version } (${ product.commit })`); console.log(`${ pkg.version }\n${ product.commit }`);
} else if (shouldSpawnCliProcess(args)) { } else if (shouldSpawnCliProcess(args)) {
const mainCli = new TPromise<IMainCli>(c => require(['vs/code/node/cliProcessMain'], c)); const mainCli = new TPromise<IMainCli>(c => require(['vs/code/node/cliProcessMain'], c));
return mainCli.then(cli => cli.main(args)); return mainCli.then(cli => cli.main(args));
@ -41,7 +41,7 @@ export function main(argv: string[]): TPromise<void> {
'VSCODE_CLI': '1', 'VSCODE_CLI': '1',
'ELECTRON_NO_ATTACH_CONSOLE': '1' 'ELECTRON_NO_ATTACH_CONSOLE': '1'
}); });
delete env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; delete env['ELECTRON_RUN_AS_NODE'];
let options = { let options = {
detached: true, detached: true,

View file

@ -12,7 +12,8 @@
cursor: default; cursor: default;
} }
.monaco-workbench .monaco-editor .margin-view-overlays .line-numbers { /* disable until https://github.com/Microsoft/vscode/issues/8708 is fixed */
/*.monaco-workbench .monaco-editor .margin-view-overlays .line-numbers {
cursor: -webkit-image-set( cursor: -webkit-image-set(
url('flipped-cursor.svg') 1x, url('flipped-cursor.svg') 1x,
url('flipped-cursor-2x.svg') 2x url('flipped-cursor-2x.svg') 2x
@ -24,7 +25,7 @@
url('flipped-cursor-mac.svg') 1x, url('flipped-cursor-mac.svg') 1x,
url('flipped-cursor-mac-2x.svg') 2x url('flipped-cursor-mac-2x.svg') 2x
) 24 3, default; ) 24 3, default;
} }*/
.monaco-editor .margin-view-overlays .line-numbers.lh-odd { .monaco-editor .margin-view-overlays .line-numbers.lh-odd {
margin-top: 1px; margin-top: 1px;

View file

@ -25,7 +25,7 @@ class FindController extends CommonFindController implements IFindController {
) { ) {
super(editor, contextKeyService); super(editor, contextKeyService);
this._widget = this._register(new FindWidget(editor, this, this._state, contextViewService, keybindingService)); this._widget = this._register(new FindWidget(editor, this, this._state, contextViewService, keybindingService, contextKeyService));
} }
protected _start(opts:IFindStartOptions): void { protected _start(opts:IFindStartOptions): void {

View file

@ -22,6 +22,8 @@ import {ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositi
import {FIND_IDS, MATCHES_LIMIT} from 'vs/editor/contrib/find/common/findModel'; import {FIND_IDS, MATCHES_LIMIT} from 'vs/editor/contrib/find/common/findModel';
import {FindReplaceState, FindReplaceStateChangedEvent} from 'vs/editor/contrib/find/common/findState'; import {FindReplaceState, FindReplaceStateChangedEvent} from 'vs/editor/contrib/find/common/findState';
import {Range} from 'vs/editor/common/core/range'; import {Range} from 'vs/editor/common/core/range';
import {IContextKeyService, IContextKey} from 'vs/platform/contextkey/common/contextkey';
import {CONTEXT_FIND_INPUT_FOCUSSED} from 'vs/editor/contrib/find/common/findController';
export interface IFindController { export interface IFindController {
replace(): void; replace(): void;
@ -75,13 +77,15 @@ export class FindWidget extends Widget implements IOverlayWidget {
private _isReplaceVisible: boolean; private _isReplaceVisible: boolean;
private _focusTracker: dom.IFocusTracker; private _focusTracker: dom.IFocusTracker;
private _findInputFocussed: IContextKey<boolean>;
constructor( constructor(
codeEditor: ICodeEditor, codeEditor: ICodeEditor,
controller: IFindController, controller: IFindController,
state: FindReplaceState, state: FindReplaceState,
contextViewProvider: IContextViewProvider, contextViewProvider: IContextViewProvider,
keybindingService: IKeybindingService keybindingService: IKeybindingService,
contextKeyService: IContextKeyService
) { ) {
super(); super();
this._codeEditor = codeEditor; this._codeEditor = codeEditor;
@ -112,8 +116,10 @@ export class FindWidget extends Widget implements IOverlayWidget {
this._updateToggleSelectionFindButton(); this._updateToggleSelectionFindButton();
} }
})); }));
this._findInputFocussed = CONTEXT_FIND_INPUT_FOCUSSED.bindTo(contextKeyService);
this._focusTracker = this._register(dom.trackFocus(this._findInput.inputBox.inputElement)); this._focusTracker = this._register(dom.trackFocus(this._findInput.inputBox.inputElement));
this._focusTracker.addFocusListener(() => { this._focusTracker.addFocusListener(() => {
this._findInputFocussed.set(true);
let selection = this._codeEditor.getSelection(); let selection = this._codeEditor.getSelection();
let currentMatch = this._state.currentMatch; let currentMatch = this._state.currentMatch;
if (selection.startLineNumber !== selection.endLineNumber) { if (selection.startLineNumber !== selection.endLineNumber) {
@ -123,6 +129,9 @@ export class FindWidget extends Widget implements IOverlayWidget {
} }
} }
}); });
this._focusTracker.addBlurListener(() => {
this._findInputFocussed.set(false);
});
this._codeEditor.addOverlayWidget(this); this._codeEditor.addOverlayWidget(this);
} }

View file

@ -14,7 +14,7 @@ import {Selection} from 'vs/editor/common/core/selection';
import * as strings from 'vs/base/common/strings'; import * as strings from 'vs/base/common/strings';
import * as editorCommon from 'vs/editor/common/editorCommon'; import * as editorCommon from 'vs/editor/common/editorCommon';
import {editorAction, commonEditorContribution, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions'; import {editorAction, commonEditorContribution, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {FIND_IDS, FindModelBoundToEditorModel} from 'vs/editor/contrib/find/common/findModel'; import {FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding, ShowPreviousFindTermKeybinding, ShowNextFindTermKeybinding} from 'vs/editor/contrib/find/common/findModel';
import {FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState} from 'vs/editor/contrib/find/common/findState'; import {FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState} from 'vs/editor/contrib/find/common/findState';
import {DocumentHighlightProviderRegistry} from 'vs/editor/common/modes'; import {DocumentHighlightProviderRegistry} from 'vs/editor/common/modes';
import {RunOnceScheduler, Delayer} from 'vs/base/common/async'; import {RunOnceScheduler, Delayer} from 'vs/base/common/async';
@ -36,6 +36,7 @@ export interface IFindStartOptions {
export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('findWidgetVisible', false); export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('findWidgetVisible', false);
export const CONTEXT_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = CONTEXT_FIND_WIDGET_VISIBLE.toNegated(); export const CONTEXT_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = CONTEXT_FIND_WIDGET_VISIBLE.toNegated();
export const CONTEXT_FIND_INPUT_FOCUSSED = new RawContextKey<boolean>('findInputFocussed', false);
export class CommonFindController extends Disposable implements editorCommon.IEditorContribution { export class CommonFindController extends Disposable implements editorCommon.IEditorContribution {
@ -920,8 +921,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
kbOpts: { kbOpts: {
weight: CommonEditorRegistry.commandWeight(5), weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus, kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.KEY_C, primary: ToggleCaseSensitiveKeybinding.primary,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } mac: ToggleCaseSensitiveKeybinding.mac,
win: ToggleCaseSensitiveKeybinding.win,
linux: ToggleCaseSensitiveKeybinding.linux
} }
})); }));
@ -932,8 +935,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
kbOpts: { kbOpts: {
weight: CommonEditorRegistry.commandWeight(5), weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus, kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.KEY_W, primary: ToggleWholeWordKeybinding.primary,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } mac: ToggleWholeWordKeybinding.mac,
win: ToggleWholeWordKeybinding.win,
linux: ToggleWholeWordKeybinding.linux
} }
})); }));
@ -944,8 +949,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
kbOpts: { kbOpts: {
weight: CommonEditorRegistry.commandWeight(5), weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus, kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.KEY_R, primary: ToggleRegexKeybinding.primary,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } mac: ToggleRegexKeybinding.mac,
win: ToggleRegexKeybinding.win,
linux: ToggleRegexKeybinding.linux
} }
})); }));
@ -988,8 +995,11 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
handler: x => x.showPreviousFindTerm(), handler: x => x.showPreviousFindTerm(),
kbOpts: { kbOpts: {
weight: CommonEditorRegistry.commandWeight(5), weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus, kbExpr: ContextKeyExpr.and(CONTEXT_FIND_INPUT_FOCUSSED, EditorContextKeys.Focus),
primary: KeyMod.Alt | KeyCode.UpArrow primary: ShowPreviousFindTermKeybinding.primary,
mac: ShowPreviousFindTermKeybinding.mac,
win: ShowPreviousFindTermKeybinding.win,
linux: ShowPreviousFindTermKeybinding.linux
} }
})); }));
@ -999,7 +1009,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
handler: x => x.showNextFindTerm(), handler: x => x.showNextFindTerm(),
kbOpts: { kbOpts: {
weight: CommonEditorRegistry.commandWeight(5), weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus, kbExpr: ContextKeyExpr.and(CONTEXT_FIND_INPUT_FOCUSSED, EditorContextKeys.Focus),
primary: KeyMod.Alt | KeyCode.DownArrow primary: ShowNextFindTermKeybinding.primary,
mac: ShowNextFindTermKeybinding.mac,
win: ShowNextFindTermKeybinding.win,
linux: ShowNextFindTermKeybinding.linux
} }
})); }));

View file

@ -16,6 +16,27 @@ import {FindDecorations} from './findDecorations';
import {FindReplaceState, FindReplaceStateChangedEvent} from './findState'; import {FindReplaceState, FindReplaceStateChangedEvent} from './findState';
import {ReplaceAllCommand} from './replaceAllCommand'; import {ReplaceAllCommand} from './replaceAllCommand';
import {Selection} from 'vs/editor/common/core/selection'; import {Selection} from 'vs/editor/common/core/selection';
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import {IKeybindings} from 'vs/platform/keybinding/common/keybinding';
export const ToggleCaseSensitiveKeybinding: IKeybindings = {
primary: KeyMod.Alt | KeyCode.KEY_C,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C }
};
export const ToggleWholeWordKeybinding: IKeybindings = {
primary: KeyMod.Alt | KeyCode.KEY_W,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W }
};
export const ToggleRegexKeybinding: IKeybindings = {
primary: KeyMod.Alt | KeyCode.KEY_R,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R }
};
export const ShowPreviousFindTermKeybinding: IKeybindings = {
primary: KeyMod.Alt | KeyCode.UpArrow
};
export const ShowNextFindTermKeybinding: IKeybindings = {
primary: KeyMod.Alt | KeyCode.DownArrow
};
export const FIND_IDS = { export const FIND_IDS = {
StartFindAction: 'actions.find', StartFindAction: 'actions.find',
@ -43,16 +64,16 @@ export const MATCHES_LIMIT = 999;
export class FindModelBoundToEditorModel { export class FindModelBoundToEditorModel {
private _editor:editorCommon.ICommonCodeEditor; private _editor: editorCommon.ICommonCodeEditor;
private _state:FindReplaceState; private _state: FindReplaceState;
private _toDispose:IDisposable[]; private _toDispose: IDisposable[];
private _decorations: FindDecorations; private _decorations: FindDecorations;
private _ignoreModelContentChanged:boolean; private _ignoreModelContentChanged: boolean;
private _updateDecorationsScheduler:RunOnceScheduler; private _updateDecorationsScheduler: RunOnceScheduler;
private _isDisposed: boolean; private _isDisposed: boolean;
constructor(editor:editorCommon.ICommonCodeEditor, state:FindReplaceState) { constructor(editor: editorCommon.ICommonCodeEditor, state: FindReplaceState) {
this._editor = editor; this._editor = editor;
this._state = state; this._state = state;
this._toDispose = []; this._toDispose = [];
@ -64,7 +85,7 @@ export class FindModelBoundToEditorModel {
this._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100); this._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100);
this._toDispose.push(this._updateDecorationsScheduler); this._toDispose.push(this._updateDecorationsScheduler);
this._toDispose.push(this._editor.onDidChangeCursorPosition((e:editorCommon.ICursorPositionChangedEvent) => { this._toDispose.push(this._editor.onDidChangeCursorPosition((e: editorCommon.ICursorPositionChangedEvent) => {
if ( if (
e.reason === editorCommon.CursorChangeReason.Explicit e.reason === editorCommon.CursorChangeReason.Explicit
|| e.reason === editorCommon.CursorChangeReason.Undo || e.reason === editorCommon.CursorChangeReason.Undo
@ -75,7 +96,7 @@ export class FindModelBoundToEditorModel {
})); }));
this._ignoreModelContentChanged = false; this._ignoreModelContentChanged = false;
this._toDispose.push(this._editor.onDidChangeModelRawContent((e:editorCommon.IModelContentChangedEvent) => { this._toDispose.push(this._editor.onDidChangeModelRawContent((e: editorCommon.IModelContentChangedEvent) => {
if (this._ignoreModelContentChanged) { if (this._ignoreModelContentChanged) {
return; return;
} }
@ -97,7 +118,7 @@ export class FindModelBoundToEditorModel {
this._toDispose = dispose(this._toDispose); this._toDispose = dispose(this._toDispose);
} }
private _onStateChanged(e:FindReplaceStateChangedEvent): void { private _onStateChanged(e: FindReplaceStateChangedEvent): void {
if (this._isDisposed) { if (this._isDisposed) {
// The find model is disposed during a find state changed event // The find model is disposed during a find state changed event
return; return;
@ -111,8 +132,8 @@ export class FindModelBoundToEditorModel {
} }
} }
private static _getSearchRange(model:editorCommon.IModel, searchOnlyEditableRange:boolean, findScope:Range): Range { private static _getSearchRange(model: editorCommon.IModel, searchOnlyEditableRange: boolean, findScope: Range): Range {
let searchRange:Range; let searchRange: Range;
if (searchOnlyEditableRange) { if (searchOnlyEditableRange) {
searchRange = model.getEditableRange(); searchRange = model.getEditableRange();
@ -128,7 +149,7 @@ export class FindModelBoundToEditorModel {
return searchRange; return searchRange;
} }
private research(moveCursor:boolean, newFindScope?:Range): void { private research(moveCursor: boolean, newFindScope?: Range): void {
let findScope: Range = null; let findScope: Range = null;
if (typeof newFindScope !== 'undefined') { if (typeof newFindScope !== 'undefined') {
findScope = newFindScope; findScope = newFindScope;
@ -169,7 +190,7 @@ export class FindModelBoundToEditorModel {
return false; return false;
} }
private _setCurrentFindMatch(match:Range): void { private _setCurrentFindMatch(match: Range): void {
let matchesPosition = this._decorations.setCurrentFindMatch(match); let matchesPosition = this._decorations.setCurrentFindMatch(match);
this._state.changeMatchInfo( this._state.changeMatchInfo(
matchesPosition, matchesPosition,
@ -181,7 +202,7 @@ export class FindModelBoundToEditorModel {
this._editor.revealRangeInCenterIfOutsideViewport(match); this._editor.revealRangeInCenterIfOutsideViewport(match);
} }
private _moveToPrevMatch(before:Position, isRecursed:boolean = false): void { private _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {
if (this._cannotFind()) { if (this._cannotFind()) {
return; return;
} }
@ -199,7 +220,7 @@ export class FindModelBoundToEditorModel {
before = searchRange.getEndPosition(); before = searchRange.getEndPosition();
} }
let {lineNumber,column} = before; let {lineNumber, column} = before;
let model = this._editor.getModel(); let model = this._editor.getModel();
let position = new Position(lineNumber, column); let position = new Position(lineNumber, column);
@ -245,8 +266,8 @@ export class FindModelBoundToEditorModel {
this._moveToPrevMatch(this._editor.getSelection().getStartPosition()); this._moveToPrevMatch(this._editor.getSelection().getStartPosition());
} }
private _moveToNextMatch(nextMatch:Range): void private _moveToNextMatch(nextMatch: Range): void
private _moveToNextMatch(after:Position): void private _moveToNextMatch(after: Position): void
private _moveToNextMatch(arg: any): void { private _moveToNextMatch(arg: any): void {
let nextMatch = Range.isIRange(arg) ? arg : Position.isIPosition(arg) ? this._getNextMatch(arg) : null; let nextMatch = Range.isIRange(arg) ? arg : Position.isIPosition(arg) ? this._getNextMatch(arg) : null;
if (nextMatch) { if (nextMatch) {
@ -254,7 +275,7 @@ export class FindModelBoundToEditorModel {
} }
} }
private _getNextMatch(after:Position, isRecursed:boolean = false): Range { private _getNextMatch(after: Position, isRecursed: boolean = false): Range {
if (this._cannotFind()) { if (this._cannotFind()) {
return null; return null;
} }
@ -272,7 +293,7 @@ export class FindModelBoundToEditorModel {
after = searchRange.getStartPosition(); after = searchRange.getStartPosition();
} }
let {lineNumber,column} = after; let {lineNumber, column} = after;
let model = this._editor.getModel(); let model = this._editor.getModel();
let position = new Position(lineNumber, column); let position = new Position(lineNumber, column);
@ -370,7 +391,7 @@ export class FindModelBoundToEditorModel {
} }
} }
private _findMatches(findScope: Range, limitResultCount:number): Range[] { private _findMatches(findScope: Range, limitResultCount: number): Range[] {
let searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), this._state.isReplaceRevealed, findScope); let searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), this._state.isReplaceRevealed, findScope);
return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord, limitResultCount); return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord, limitResultCount);
} }
@ -385,7 +406,7 @@ export class FindModelBoundToEditorModel {
// Get all the ranges (even more than the highlighted ones) // Get all the ranges (even more than the highlighted ones)
let ranges = this._findMatches(findScope, Number.MAX_VALUE); let ranges = this._findMatches(findScope, Number.MAX_VALUE);
let replaceStrings:string[] = []; let replaceStrings: string[] = [];
for (let i = 0, len = ranges.length; i < len; i++) { for (let i = 0, len = ranges.length; i < len; i++) {
replaceStrings.push(this.getReplaceString(ranges[i])); replaceStrings.push(this.getReplaceString(ranges[i]));
} }
@ -409,7 +430,7 @@ export class FindModelBoundToEditorModel {
this._editor.setSelections(ranges.map(r => new Selection(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn))); this._editor.setSelections(ranges.map(r => new Selection(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn)));
} }
private _executeEditorCommand(source:string, command:editorCommon.ICommand): void { private _executeEditorCommand(source: string, command: editorCommon.ICommand): void {
try { try {
this._ignoreModelContentChanged = true; this._ignoreModelContentChanged = true;
this._editor.executeCommand(source, command); this._editor.executeCommand(source, command);

3
src/vs/vscode.d.ts vendored
View file

@ -3498,9 +3498,10 @@ declare namespace vscode {
* *
* @param name Optional human-readable string which will be used to represent the terminal in the UI. * @param name Optional human-readable string which will be used to represent the terminal in the UI.
* @param shellPath Optional path to a custom shell executable to be used in the terminal. * @param shellPath Optional path to a custom shell executable to be used in the terminal.
* @param shellArgs Optional args for the custom shell executable, this does not work on Windows (see #8429)
* @return A new Terminal. * @return A new Terminal.
*/ */
export function createTerminal(name?: string, shellPath?: string): Terminal; export function createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): Terminal;
} }
/** /**

View file

@ -260,8 +260,8 @@ export class ExtHostAPIImplementation {
createOutputChannel(name: string): vscode.OutputChannel { createOutputChannel(name: string): vscode.OutputChannel {
return extHostOutputService.createOutputChannel(name); return extHostOutputService.createOutputChannel(name);
}, },
createTerminal(name?: string, shellPath?: string): vscode.Terminal { createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
return extHostTerminalService.createTerminal(name, shellPath); return extHostTerminalService.createTerminal(name, shellPath, shellArgs);
} }
}; };

View file

@ -153,7 +153,7 @@ export abstract class MainThreadOutputServiceShape {
} }
export abstract class MainThreadTerminalServiceShape { export abstract class MainThreadTerminalServiceShape {
$createTerminal(name?: string, shellPath?: string): number { throw ni(); } $createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): TPromise<number> { throw ni(); }
$dispose(terminalId: number): void { throw ni(); } $dispose(terminalId: number): void { throw ni(); }
$hide(terminalId: number): void { throw ni(); } $hide(terminalId: number): void { throw ni(); }
$sendText(terminalId: number, text: string, addNewLine: boolean): void { throw ni(); } $sendText(terminalId: number, text: string, addNewLine: boolean): void { throw ni(); }

View file

@ -10,18 +10,21 @@ import {MainContext, MainThreadTerminalServiceShape} from './extHost.protocol';
export class ExtHostTerminal implements vscode.Terminal { export class ExtHostTerminal implements vscode.Terminal {
public _name: string; private _name: string;
public _shellPath: string;
private _id: number; private _id: number;
private _proxy: MainThreadTerminalServiceShape; private _proxy: MainThreadTerminalServiceShape;
private _disposed: boolean; private _disposed: boolean;
private _queuedRequests: ApiRequest[] = [];
constructor(proxy: MainThreadTerminalServiceShape, id: number, name?: string, shellPath?: string) { constructor(proxy: MainThreadTerminalServiceShape, name?: string, shellPath?: string, shellArgs?: string[]) {
this._name = name; this._name = name;
this._shellPath = shellPath;
this._proxy = proxy; this._proxy = proxy;
this._id = this._proxy.$createTerminal(name, shellPath); this._proxy.$createTerminal(name, shellPath, shellArgs).then((id) => {
this._id = id;
this._queuedRequests.forEach((r) => {
r.run(this._proxy, this._id);
});
});
} }
public get name(): string { public get name(): string {
@ -31,26 +34,35 @@ export class ExtHostTerminal implements vscode.Terminal {
public sendText(text: string, addNewLine: boolean = true): void { public sendText(text: string, addNewLine: boolean = true): void {
this._checkDisposed(); this._checkDisposed();
this._proxy.$sendText(this._id, text, addNewLine); this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]);
} }
public show(preserveFocus: boolean): void { public show(preserveFocus: boolean): void {
this._checkDisposed(); this._checkDisposed();
this._proxy.$show(this._id, preserveFocus); this._queueApiRequest(this._proxy.$show, [preserveFocus]);
} }
public hide(): void { public hide(): void {
this._checkDisposed(); this._checkDisposed();
this._proxy.$hide(this._id); this._queueApiRequest(this._proxy.$hide, []);
} }
public dispose(): void { public dispose(): void {
if (!this._disposed) { if (!this._disposed) {
this._disposed = true; this._disposed = true;
this._proxy.$dispose(this._id); this._queueApiRequest(this._proxy.$dispose, []);
} }
} }
private _queueApiRequest(callback: (...args: any[]) => void, args: any[]) {
let request: ApiRequest = new ApiRequest(callback, args);
if (!this._id) {
this._queuedRequests.push(request);
return;
}
request.run(this._proxy, this._id);
}
private _checkDisposed() { private _checkDisposed() {
if (this._disposed) { if (this._disposed) {
throw new Error('Terminal has already been disposed'); throw new Error('Terminal has already been disposed');
@ -66,7 +78,21 @@ export class ExtHostTerminalService {
this._proxy = threadService.get(MainContext.MainThreadTerminalService); this._proxy = threadService.get(MainContext.MainThreadTerminalService);
} }
public createTerminal(name?: string, shellPath?: string): vscode.Terminal { public createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
return new ExtHostTerminal(this._proxy, -1, name, shellPath); return new ExtHostTerminal(this._proxy, name, shellPath, shellArgs);
} }
} }
class ApiRequest {
private _callback: (...args: any[]) => void;
private _args: any[];
constructor(callback: (...args: any[]) => void, args: any[]) {
this._callback = callback;
this._args = args;
}
public run(proxy: MainThreadTerminalServiceShape, id: number) {
this._callback.apply(proxy, [id].concat(this._args));
}
}

View file

@ -8,6 +8,7 @@ import {ITerminalService} from 'vs/workbench/parts/terminal/electron-browser/ter
import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; import {IPanelService} from 'vs/workbench/services/panel/common/panelService';
import {IPartService} from 'vs/workbench/services/part/common/partService'; import {IPartService} from 'vs/workbench/services/part/common/partService';
import {MainThreadTerminalServiceShape} from './extHost.protocol'; import {MainThreadTerminalServiceShape} from './extHost.protocol';
import {TPromise} from 'vs/base/common/winjs.base';
export class MainThreadTerminalService extends MainThreadTerminalServiceShape { export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
@ -19,8 +20,8 @@ export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
super(); super();
} }
public $createTerminal(name?: string, shellPath?: string): number { public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): TPromise<number> {
return this.terminalService.createInstance(name, shellPath).id; return TPromise.as(this.terminalService.createInstance(name, shellPath, shellArgs).id);
} }
public $show(terminalId: number, preserveFocus: boolean): void { public $show(terminalId: number, preserveFocus: boolean): void {

View file

@ -662,9 +662,12 @@ export class ChangeModeAction extends Action {
// All languages are valid picks // All languages are valid picks
const picks: IPickOpenEntry[] = languages.sort().map((lang, index) => { const picks: IPickOpenEntry[] = languages.sort().map((lang, index) => {
return { const languageModeId = this.modeService.getModeIdForLanguageName(lang.toLowerCase());
const configureLabel = nls.localize('configuredLanguage', "Configured Language");
return <IPickOpenEntry>{
label: lang, label: lang,
description: currentModeId === lang ? nls.localize('configuredLanguage', "Configured Language") : void 0 description: currentModeId === lang ? `${languageModeId} (${configureLabel})` : languageModeId
}; };
}); });
picks[0].separator = { border: true, label: nls.localize('languagesPicks', "languages") }; picks[0].separator = { border: true, label: nls.localize('languagesPicks', "languages") };

View file

@ -607,7 +607,7 @@ export class DebugService implements debug.IDebugService {
timeout: 1000 * 60 * 5, timeout: 1000 * 60 * 5,
args: [`${ publisher }.${ type }`, JSON.stringify(data), aiKey], args: [`${ publisher }.${ type }`, JSON.stringify(data), aiKey],
env: { env: {
ATOM_SHELL_INTERNAL_RUN_AS_NODE: 1, ELECTRON_RUN_AS_NODE: 1,
PIPE_LOGGING: 'true', PIPE_LOGGING: 'true',
AMD_ENTRYPOINT: 'vs/workbench/parts/debug/node/telemetryApp' AMD_ENTRYPOINT: 'vs/workbench/parts/debug/node/telemetryApp'
} }

View file

@ -25,6 +25,7 @@ import v8 = require('vs/workbench/parts/debug/node/v8Protocol');
import {IOutputService} from 'vs/workbench/parts/output/common/output'; import {IOutputService} from 'vs/workbench/parts/output/common/output';
import {ExtensionsChannelId} from 'vs/platform/extensionManagement/common/extensionManagement'; import {ExtensionsChannelId} from 'vs/platform/extensionManagement/common/extensionManagement';
import {TerminalSupport} from 'vs/workbench/parts/debug/electron-browser/terminalSupport'; import {TerminalSupport} from 'vs/workbench/parts/debug/electron-browser/terminalSupport';
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
import {shell} from 'electron'; import {shell} from 'electron';
@ -75,7 +76,8 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
@ITelemetryService private telemetryService: ITelemetryService, @ITelemetryService private telemetryService: ITelemetryService,
@IOutputService private outputService: IOutputService, @IOutputService private outputService: IOutputService,
@ITerminalService private terminalService: ITerminalService, @ITerminalService private terminalService: ITerminalService,
@IExternalTerminalService private nativeTerminalService: IExternalTerminalService @IExternalTerminalService private nativeTerminalService: IExternalTerminalService,
@IConfigurationService private configurationService: IConfigurationService
) { ) {
super(); super();
this.emittedStopped = false; this.emittedStopped = false;
@ -348,7 +350,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
if (request.command === 'runInTerminal') { if (request.command === 'runInTerminal') {
TerminalSupport.runInTerminal(this.terminalService, this.nativeTerminalService, <DebugProtocol.RunInTerminalRequestArguments>request.arguments, <DebugProtocol.RunInTerminalResponse>response).then(() => { TerminalSupport.runInTerminal(this.terminalService, this.nativeTerminalService, this.configurationService, <DebugProtocol.RunInTerminalRequestArguments>request.arguments, <DebugProtocol.RunInTerminalResponse>response).then(() => {
this.sendResponse(response); this.sendResponse(response);
}, e => { }, e => {
response.success = false; response.success = false;

View file

@ -8,33 +8,40 @@ import platform = require('vs/base/common/platform');
import {TPromise} from 'vs/base/common/winjs.base'; import {TPromise} from 'vs/base/common/winjs.base';
import {ITerminalService, ITerminalInstance} from 'vs/workbench/parts/terminal/electron-browser/terminal'; import {ITerminalService, ITerminalInstance} from 'vs/workbench/parts/terminal/electron-browser/terminal';
import {ITerminalService as IExternalTerminalService} from 'vs/workbench/parts/execution/common/execution'; import {ITerminalService as IExternalTerminalService} from 'vs/workbench/parts/execution/common/execution';
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
export interface IIntegratedTerminalConfiguration {
terminal: {
integrated: {
shell: {
windows: string
}
}
};
}
export class TerminalSupport { export class TerminalSupport {
private static integratedTerminalInstance: ITerminalInstance; private static integratedTerminalInstance: ITerminalInstance;
public static runInTerminal(terminalService: ITerminalService, nativeTerminalService: IExternalTerminalService, args: DebugProtocol.RunInTerminalRequestArguments, response: DebugProtocol.RunInTerminalResponse): TPromise<void> { public static runInTerminal(terminalService: ITerminalService, nativeTerminalService: IExternalTerminalService, configurationService: IConfigurationService, args: DebugProtocol.RunInTerminalRequestArguments, response: DebugProtocol.RunInTerminalResponse): TPromise<void> {
if (args.kind === 'external') { if (args.kind === 'external') {
return nativeTerminalService.runInTerminal(args.title, args.cwd, args.args, args.env); return nativeTerminalService.runInTerminal(args.title, args.cwd, args.args, args.env);
} }
return this.runInIntegratedTerminal(terminalService, args);
}
private static runInIntegratedTerminal(terminalService: ITerminalService, args: DebugProtocol.RunInTerminalRequestArguments): TPromise<void> {
if (!TerminalSupport.integratedTerminalInstance) { if (!TerminalSupport.integratedTerminalInstance) {
TerminalSupport.integratedTerminalInstance = terminalService.createInstance(args.title || nls.localize('debuggee', "debuggee")); TerminalSupport.integratedTerminalInstance = terminalService.createInstance(args.title || nls.localize('debuggee', "debuggee"));
} }
terminalService.setActiveInstance(TerminalSupport.integratedTerminalInstance); terminalService.setActiveInstance(TerminalSupport.integratedTerminalInstance);
terminalService.showPanel(true); terminalService.showPanel(true);
const command = this.prepareCommand(args); const command = this.prepareCommand(args, configurationService);
TerminalSupport.integratedTerminalInstance.sendText(command, true); TerminalSupport.integratedTerminalInstance.sendText(command, true);
return TPromise.as(void 0); return TPromise.as(void 0);
} }
private static prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments): string { private static prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, configurationService: IConfigurationService): string {
let command = ''; let command = '';
if (platform.isWindows) { if (platform.isWindows) {
@ -44,21 +51,41 @@ export class TerminalSupport {
return (s.indexOf(' ') >= 0 || s.indexOf('"') >= 0) ? `"${s}"` : s; return (s.indexOf(' ') >= 0 || s.indexOf('"') >= 0) ? `"${s}"` : s;
}; };
if (args.cwd) { const conf = configurationService.getConfiguration<IIntegratedTerminalConfiguration>();
command += `cd ${quote(args.cwd)} && `;
let isPowerShell = false;
if (conf.terminal && conf.terminal.integrated && conf.terminal.integrated.shell && conf.terminal.integrated.shell.windows) {
isPowerShell = conf.terminal.integrated.shell.windows.indexOf('PowerShell') >= 0;
} }
if (args.env) {
command += 'cmd /C "'; if (isPowerShell) {
for (let key in args.env) {
command += `set "${key}=${args.env[key]}" && `; if (args.cwd) {
command += `cd ${quote(args.cwd)}; `;
}
for (let a of args.args) {
command += `${quote(a)} `;
}
} else {
if (args.cwd) {
command += `cd ${quote(args.cwd)} && `;
}
if (args.env) {
command += 'cmd /C "';
for (let key in args.env) {
command += `set "${key}=${args.env[key]}" && `;
}
}
for (let a of args.args) {
command += `${quote(a)} `;
}
if (args.env) {
command += '"';
} }
} }
for (let a of args.args) {
command += `${quote(a)} `;
}
if (args.env) {
command += '"';
}
} else { } else {
const quote = (s: string) => { const quote = (s: string) => {
s = s.replace(/\"/g, '\\"'); s = s.replace(/\"/g, '\\"');

View file

@ -42,6 +42,7 @@ import { Keybinding } from 'vs/base/common/keyCodes';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IMessageService } from 'vs/platform/message/common/message'; import { IMessageService } from 'vs/platform/message/common/message';
import { IOpenerService } from 'vs/platform/opener/common/opener';
function renderBody(body: string): string { function renderBody(body: string): string {
return `<!DOCTYPE html> return `<!DOCTYPE html>
@ -140,7 +141,8 @@ export class ExtensionEditor extends BaseEditor {
@IThemeService private themeService: IThemeService, @IThemeService private themeService: IThemeService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IKeybindingService private keybindingService: IKeybindingService, @IKeybindingService private keybindingService: IKeybindingService,
@IMessageService private messageService: IMessageService @IMessageService private messageService: IMessageService,
@IOpenerService private openerService: IOpenerService
) { ) {
super(ExtensionEditor.ID, telemetryService); super(ExtensionEditor.ID, telemetryService);
this._highlight = null; this._highlight = null;
@ -276,9 +278,9 @@ export class ExtensionEditor extends BaseEditor {
webview.style(this.themeService.getColorTheme()); webview.style(this.themeService.getColorTheme());
webview.contents = [body]; webview.contents = [body];
const linkListener = webview.onDidClickLink(link => shell.openExternal(link.toString(true))); webview.onDidClickLink(link => this.openerService.open(link), null, this.contentDisposables);
const themeListener = this.themeService.onDidColorThemeChange(themeId => webview.style(themeId)); this.themeService.onDidColorThemeChange(themeId => webview.style(themeId), null, this.contentDisposables);
this.contentDisposables.push(webview, linkListener, themeListener); this.contentDisposables.push(webview);
}) })
.then(null, () => { .then(null, () => {
const p = append(this.content, $('p')); const p = append(this.content, $('p'));

View file

@ -15,6 +15,11 @@
line-height: 22px; line-height: 22px;
} }
.explorer-viewlet .explorer-item {
display: flex; /* this helps showing the overflow ellipsis (...) even though we use display:inline-block for the labels */
flex-wrap: nowrap;
}
.explorer-viewlet .explorer-item-label, .explorer-viewlet .explorer-item-label,
.explorer-viewlet .open-editor, .explorer-viewlet .open-editor,
.explorer-viewlet .editor-group { .explorer-viewlet .editor-group {
@ -25,6 +30,7 @@
.explorer-viewlet .explorer-item-label, .explorer-viewlet .explorer-item-label,
.explorer-viewlet .explorer-item .monaco-inputbox { .explorer-viewlet .explorer-item .monaco-inputbox {
display: inline-block; /* required for icons support :before rule */ display: inline-block; /* required for icons support :before rule */
flex: 1;
} }
.explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row > .content { .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row > .content {

View file

@ -398,19 +398,19 @@ export class FileRenderer extends ActionsRenderer implements IRenderer {
const name = dotSegments[0]; // file.txt => "file", .dockerfile => "", file.some.txt => "file" const name = dotSegments[0]; // file.txt => "file", .dockerfile => "", file.some.txt => "file"
if (name) { if (name) {
classes.push(`${name.toLowerCase()}-name-file-icon`); classes.push(`${this.cssEscape(name.toLowerCase())}-name-file-icon`);
} }
const extensions = dotSegments.splice(1); const extensions = dotSegments.splice(1);
if (extensions.length > 0) { if (extensions.length > 0) {
for (let i = 0; i < extensions.length; i++) { for (let i = 0; i < extensions.length; i++) {
classes.push(`${extensions.slice(i).join('.').toLowerCase()}-ext-file-icon`); // add each combination of all found extensions if more than one classes.push(`${this.cssEscape(extensions.slice(i).join('.').toLowerCase())}-ext-file-icon`); // add each combination of all found extensions if more than one
} }
} }
const langId = this.modeService.getModeIdByFilenameOrFirstLine(fsPath); const langId = this.modeService.getModeIdByFilenameOrFirstLine(fsPath);
if (langId) { if (langId) {
classes.push(`${langId}-lang-file-icon`); classes.push(`${this.cssEscape(langId)}-lang-file-icon`);
} }
return classes; return classes;
@ -422,11 +422,15 @@ export class FileRenderer extends ActionsRenderer implements IRenderer {
const classes = ['folder-icon']; const classes = ['folder-icon'];
if (basename) { if (basename) {
classes.push(`${basename.toLowerCase()}-name-folder-icon`); classes.push(`${this.cssEscape(basename.toLowerCase())}-name-folder-icon`);
} }
return classes; return classes;
} }
private cssEscape(val: string): string {
return val.replace(/\s/g, '\\$&'); // make sure to not introduce CSS classes from files that contain whitespace
}
} }
// Explorer Accessibility Provider // Explorer Accessibility Provider

View file

@ -158,7 +158,7 @@ function createRemoteRawGitService(gitPath: string, execPath: string, workspaceR
timeout: 1000 * 60, timeout: 1000 * 60,
args: [path, workspaceRoot, encoding, execPath, version], args: [path, workspaceRoot, encoding, execPath, version],
env: { env: {
ATOM_SHELL_INTERNAL_RUN_AS_NODE: 1, ELECTRON_RUN_AS_NODE: 1,
PIPE_LOGGING: 'true', PIPE_LOGGING: 'true',
AMD_ENTRYPOINT: 'vs/workbench/parts/git/node/gitApp', AMD_ENTRYPOINT: 'vs/workbench/parts/git/node/gitApp',
VERBOSE_LOGGING: String(verbose) VERBOSE_LOGGING: String(verbose)

View file

@ -25,11 +25,12 @@ import {IKeybindings} from 'vs/platform/keybinding/common/keybinding';
import {IQuickOpenService} from 'vs/workbench/services/quickopen/common/quickOpenService'; import {IQuickOpenService} from 'vs/workbench/services/quickopen/common/quickOpenService';
import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService'; import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
import {OpenSearchViewletAction, ReplaceInFilesAction, ShowNextSearchTermAction, ShowPreviousSearchTermAction, FocusNextInputAction, FocusPreviousInputAction} from 'vs/workbench/parts/search/browser/searchActions'; import * as searchActions from 'vs/workbench/parts/search/browser/searchActions';
import * as Constants from 'vs/workbench/parts/search/common/constants'; import * as Constants from 'vs/workbench/parts/search/common/constants';
import { registerContributions as replaceContributions } from 'vs/workbench/parts/search/browser/replaceContributions'; import { registerContributions as replaceContributions } from 'vs/workbench/parts/search/browser/replaceContributions';
import { registerContributions as searchWidgetContributions } from 'vs/workbench/parts/search/browser/searchWidget'; import { registerContributions as searchWidgetContributions } from 'vs/workbench/parts/search/browser/searchWidget';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding, ShowPreviousFindTermKeybinding, ShowNextFindTermKeybinding } from 'vs/editor/contrib/find/common/findModel';
replaceContributions(); replaceContributions();
searchWidgetContributions(); searchWidgetContributions();
@ -118,13 +119,13 @@ const openSearchViewletKb: IKeybindings = {
}; };
(<IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions)).registerWorkbenchAction( (<IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions)).registerWorkbenchAction(
new SyncActionDescriptor(OpenSearchViewletAction, OpenSearchViewletAction.ID, OpenSearchViewletAction.LABEL, openSearchViewletKb), new SyncActionDescriptor(searchActions.OpenSearchViewletAction, searchActions.OpenSearchViewletAction.ID, searchActions.OpenSearchViewletAction.LABEL, openSearchViewletKb),
'View: Show Search', 'View: Show Search',
nls.localize('view', "View") nls.localize('view', "View")
); );
(<IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions)).registerWorkbenchAction( (<IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions)).registerWorkbenchAction(
new SyncActionDescriptor(ReplaceInFilesAction, ReplaceInFilesAction.ID, ReplaceInFilesAction.LABEL, { new SyncActionDescriptor(searchActions.ReplaceInFilesAction, searchActions.ReplaceInFilesAction.ID, searchActions.ReplaceInFilesAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H
}), }),
'Replace in Files' 'Replace in Files'
@ -165,22 +166,22 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction,
primary: KeyMod.CtrlCmd | KeyCode.KEY_T primary: KeyMod.CtrlCmd | KeyCode.KEY_T
}), 'Show All Symbols'); }), 'Show All Symbols');
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextSearchTermAction, ShowNextSearchTermAction.ID, ShowNextSearchTermAction.LABEL, { registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchTermAction, searchActions.ShowNextSearchTermAction.ID, searchActions.ShowNextSearchTermAction.LABEL, ShowNextFindTermKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
primary: KeyMod.Alt | KeyCode.DownArrow
}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousSearchTermAction, ShowPreviousSearchTermAction.ID, ShowPreviousSearchTermAction.LABEL, { registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchTermAction, searchActions.ShowPreviousSearchTermAction.ID, searchActions.ShowPreviousSearchTermAction.LABEL, ShowPreviousFindTermKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
primary: KeyMod.Alt | KeyCode.UpArrow
}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextInputAction, FocusNextInputAction.ID, FocusNextInputAction.LABEL, { registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusNextInputAction, searchActions.FocusNextInputAction.ID, searchActions.FocusNextInputAction.LABEL, {
primary: KeyCode.DownArrow primary: KeyCode.DownArrow
}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey)), ''); }, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousInputAction, FocusPreviousInputAction.ID, FocusPreviousInputAction.LABEL, { registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusPreviousInputAction, searchActions.FocusPreviousInputAction.ID, searchActions.FocusPreviousInputAction.LABEL, {
primary: KeyCode.UpArrow primary: KeyCode.UpArrow
}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey, Constants.SearchInputBoxFocussedKey.toNegated())), ''); }, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey, Constants.SearchInputBoxFocussedKey.toNegated())), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleCaseSensitiveAction, Constants.ToggleCaseSensitiveActionId, '', ToggleCaseSensitiveKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleWholeWordAction, Constants.ToggleWholeWordActionId, '', ToggleWholeWordKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleRegexAction, Constants.ToggleRegexActionId, '', ToggleRegexKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
// Configuration // Configuration
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration); const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({ configurationRegistry.registerConfiguration({

View file

@ -39,6 +39,45 @@ export function appendKeyBindingLabel(label: string, keyBinding: any, keyBinding
return label + ' (' + keyBindingService2.getLabelFor(keyBinding) + ')'; return label + ' (' + keyBindingService2.getLabelFor(keyBinding) + ')';
} }
export class ToggleCaseSensitiveAction extends Action {
constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) {
super(id, label);
}
public run(): TPromise<any> {
let searchViewlet = <SearchViewlet>this.viewletService.getActiveViewlet();
searchViewlet.toggleCaseSensitive();
return TPromise.as(null);
}
}
export class ToggleWholeWordAction extends Action {
constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) {
super(id, label);
}
public run(): TPromise<any> {
let searchViewlet = <SearchViewlet>this.viewletService.getActiveViewlet();
searchViewlet.toggleWholeWords();
return TPromise.as(null);
}
}
export class ToggleRegexAction extends Action {
constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) {
super(id, label);
}
public run(): TPromise<any> {
let searchViewlet = <SearchViewlet>this.viewletService.getActiveViewlet();
searchViewlet.toggleRegex();
return TPromise.as(null);
}
}
export class ShowNextSearchTermAction extends Action { export class ShowNextSearchTermAction extends Action {
public static ID = 'search.history.showNext'; public static ID = 'search.history.showNext';

View file

@ -617,6 +617,21 @@ export class SearchViewlet extends Viewlet {
return dom.hasClass(this.queryDetails, 'more'); return dom.hasClass(this.queryDetails, 'more');
} }
public toggleCaseSensitive(): void {
this.searchWidget.searchInput.setCaseSensitive(!this.searchWidget.searchInput.getCaseSensitive());
this.onQueryChanged(true, true);
}
public toggleWholeWords(): void {
this.searchWidget.searchInput.setWholeWords(!this.searchWidget.searchInput.getWholeWords());
this.onQueryChanged(true, true);
}
public toggleRegex(): void {
this.searchWidget.searchInput.setRegex(!this.searchWidget.searchInput.getRegex());
this.onQueryChanged(true, true);
}
public toggleFileTypes(moveFocus?: boolean, show?: boolean, skipLayout?: boolean, reverse?: boolean): void { public toggleFileTypes(moveFocus?: boolean, show?: boolean, skipLayout?: boolean, reverse?: boolean): void {
let cls = 'more'; let cls = 'more';
show = typeof show === 'undefined' ? !dom.hasClass(this.queryDetails, cls) : Boolean(show); show = typeof show === 'undefined' ? !dom.hasClass(this.queryDetails, cls) : Boolean(show);

View file

@ -201,7 +201,10 @@ export class SearchWidget extends Widget {
let inputOptions: IFindInputOptions = { let inputOptions: IFindInputOptions = {
label: nls.localize('label.Search', 'Search: Type Search Term and press Enter to search or Escape to cancel'), label: nls.localize('label.Search', 'Search: Type Search Term and press Enter to search or Escape to cancel'),
validation: (value: string) => this.validatSearchInput(value), validation: (value: string) => this.validatSearchInput(value),
placeholder: nls.localize('search.placeHolder', "Search") placeholder: nls.localize('search.placeHolder', "Search"),
appendCaseSensitiveLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybindings(Constants.ToggleCaseSensitiveActionId)[0], this.keyBindingService2),
appendWholeWordsLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybindings(Constants.ToggleWholeWordActionId)[0], this.keyBindingService2),
appendRegexLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybindings(Constants.ToggleRegexActionId)[0], this.keyBindingService2)
}; };
let searchInputContainer= dom.append(parent, dom.$('.search-container.input-box')); let searchInputContainer= dom.append(parent, dom.$('.search-container.input-box'));
@ -350,7 +353,7 @@ export class SearchWidget extends Widget {
export function registerContributions() { export function registerContributions() {
KeybindingsRegistry.registerCommandAndKeybindingRule({id: ReplaceAllAction.ID, KeybindingsRegistry.registerCommandAndKeybindingRule({id: ReplaceAllAction.ID,
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
when: ContextKeyExpr.and(ContextKeyExpr.has('searchViewletVisible'), Constants.ReplaceActiveKey, CONTEXT_FIND_WIDGET_NOT_VISIBLE), when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.ReplaceActiveKey, CONTEXT_FIND_WIDGET_NOT_VISIBLE),
primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.Enter, primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.Enter,
handler: accessor => { handler: accessor => {
if (isSearchViewletFocussed(accessor.get(IViewletService))) { if (isSearchViewletFocussed(accessor.get(IViewletService))) {

View file

@ -7,6 +7,11 @@ import {RawContextKey} from 'vs/platform/contextkey/common/contextkey';
export const VIEWLET_ID = 'workbench.view.search'; export const VIEWLET_ID = 'workbench.view.search';
export const ToggleCaseSensitiveActionId = 'toggleSearchCaseSensitive';
export const ToggleWholeWordActionId = 'toggleSearchWholeWord';
export const ToggleRegexActionId = 'toggleSearchRegex';
export const SearchViewletVisibleKey = new RawContextKey<boolean>('searchViewletVisible', true); export const SearchViewletVisibleKey = new RawContextKey<boolean>('searchViewletVisible', true);
export const InputBoxFocussedKey = new RawContextKey<boolean>('inputBoxFocus', false); export const InputBoxFocussedKey = new RawContextKey<boolean>('inputBoxFocus', false);
export const SearchInputBoxFocussedKey = new RawContextKey<boolean>('searchInputBoxFocus', false); export const SearchInputBoxFocussedKey = new RawContextKey<boolean>('searchInputBoxFocus', false);

View file

@ -22,6 +22,7 @@
display: flex; display: flex;
padding: 0 20px; padding: 0 20px;
flex-grow: 1; flex-grow: 1;
width: 100%;
} }
.monaco-workbench .panel.integrated-terminal .terminal-wrapper { .monaco-workbench .panel.integrated-terminal .terminal-wrapper {

View file

@ -62,7 +62,7 @@ export interface ITerminalService {
onInstanceTitleChanged: Event<string>; onInstanceTitleChanged: Event<string>;
terminalInstances: ITerminalInstance[]; terminalInstances: ITerminalInstance[];
createInstance(name?: string, shellPath?: string): ITerminalInstance; createInstance(name?: string, shellPath?: string, shellArgs?: string[]): ITerminalInstance;
getInstanceFromId(terminalId: number): ITerminalInstance; getInstanceFromId(terminalId: number): ITerminalInstance;
getInstanceLabels(): string[]; getInstanceLabels(): string[];
getActiveInstance(): ITerminalInstance; getActiveInstance(): ITerminalInstance;

View file

@ -47,6 +47,9 @@ export class KillTerminalAction extends Action {
let terminalInstance = this.terminalService.getActiveInstance(); let terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance) { if (terminalInstance) {
this.terminalService.getActiveInstance().dispose(); this.terminalService.getActiveInstance().dispose();
if (this.terminalService.terminalInstances.length > 0) {
this.terminalService.showPanel(true);
}
} }
return TPromise.as(void 0); return TPromise.as(void 0);
} }

View file

@ -38,6 +38,7 @@ export class TerminalInstance implements ITerminalInstance {
public get onTitleChanged(): Event<string> { return this._onTitleChanged.event; } public get onTitleChanged(): Event<string> { return this._onTitleChanged.event; }
private isExiting: boolean = false; private isExiting: boolean = false;
private isVisible: boolean = false;
private toDispose: lifecycle.IDisposable[] = []; private toDispose: lifecycle.IDisposable[] = [];
private skipTerminalKeybindings: Keybinding[] = []; private skipTerminalKeybindings: Keybinding[] = [];
private process: cp.ChildProcess; private process: cp.ChildProcess;
@ -52,13 +53,13 @@ export class TerminalInstance implements ITerminalInstance {
private container: HTMLElement, private container: HTMLElement,
private workspace: IWorkspace, private workspace: IWorkspace,
name: string, name: string,
shellPath: string, shell: IShell,
@IKeybindingService private keybindingService: IKeybindingService, @IKeybindingService private keybindingService: IKeybindingService,
@IMessageService private messageService: IMessageService @IMessageService private messageService: IMessageService
) { ) {
this._id = TerminalInstance.ID_COUNTER++; this._id = TerminalInstance.ID_COUNTER++;
this._onTitleChanged = new Emitter<string>(); this._onTitleChanged = new Emitter<string>();
this.createProcess(workspace, name, shellPath); this.createProcess(workspace, name, shell);
if (container) { if (container) {
this.attachToElement(container); this.attachToElement(container);
@ -74,6 +75,7 @@ export class TerminalInstance implements ITerminalInstance {
throw new Error('The terminal instance has already been attached to a container'); throw new Error('The terminal instance has already been attached to a container');
} }
this.container = container;
this.wrapperElement = document.createElement('div'); this.wrapperElement = document.createElement('div');
DOM.addClass(this.wrapperElement, 'terminal-wrapper'); DOM.addClass(this.wrapperElement, 'terminal-wrapper');
this.xtermElement = document.createElement('div'); this.xtermElement = document.createElement('div');
@ -139,6 +141,7 @@ export class TerminalInstance implements ITerminalInstance {
this.container.appendChild(this.wrapperElement); this.container.appendChild(this.wrapperElement);
this.layout(new Dimension(this.container.offsetWidth, this.container.offsetHeight)); this.layout(new Dimension(this.container.offsetWidth, this.container.offsetHeight));
this.setVisible(this.isVisible);
} }
public copySelection(): void { public copySelection(): void {
@ -195,7 +198,10 @@ export class TerminalInstance implements ITerminalInstance {
} }
public setVisible(visible: boolean): void { public setVisible(visible: boolean): void {
DOM.toggleClass(this.wrapperElement, 'active', visible); this.isVisible = visible;
if (this.wrapperElement) {
DOM.toggleClass(this.wrapperElement, 'active', visible);
}
} }
public scrollDown(): void { public scrollDown(): void {
@ -210,9 +216,11 @@ export class TerminalInstance implements ITerminalInstance {
return typeof data === 'string' ? data.replace(TerminalInstance.EOL_REGEX, os.EOL) : data; return typeof data === 'string' ? data.replace(TerminalInstance.EOL_REGEX, os.EOL) : data;
} }
private createProcess(workspace: IWorkspace, name?: string, shellPath?: string) { private createProcess(workspace: IWorkspace, name: string, shell: IShell) {
let locale = this.configHelper.isSetLocaleVariables() ? platform.locale : undefined; let locale = this.configHelper.isSetLocaleVariables() ? platform.locale : undefined;
let shell = shellPath ? { executable: shellPath, args: [] } : this.configHelper.getShell(); if (!shell.executable) {
shell = this.configHelper.getShell();
}
let env = TerminalInstance.createTerminalEnv(process.env, shell, workspace, locale); let env = TerminalInstance.createTerminalEnv(process.env, shell, workspace, locale);
this._title = name ? name : ''; this._title = name ? name : '';
this.process = cp.fork('./terminalProcess', [], { this.process = cp.fork('./terminalProcess', [], {
@ -244,9 +252,11 @@ export class TerminalInstance implements ITerminalInstance {
let env = TerminalInstance.cloneEnv(parentEnv); let env = TerminalInstance.cloneEnv(parentEnv);
env['PTYPID'] = process.pid.toString(); env['PTYPID'] = process.pid.toString();
env['PTYSHELL'] = shell.executable; env['PTYSHELL'] = shell.executable;
shell.args.forEach((arg, i) => { if (shell.args) {
env[`PTYSHELLARG${i}`] = arg; shell.args.forEach((arg, i) => {
}); env[`PTYSHELLARG${i}`] = arg;
});
}
env['PTYCWD'] = TerminalInstance.sanitizeCwd(workspace ? workspace.resource.fsPath : os.homedir()); env['PTYCWD'] = TerminalInstance.sanitizeCwd(workspace ? workspace.resource.fsPath : os.homedir());
if (locale) { if (locale) {
env['LANG'] = TerminalInstance.getLangEnvVariable(locale); env['LANG'] = TerminalInstance.getLangEnvVariable(locale);

View file

@ -72,6 +72,8 @@ export class TerminalPanel extends Panel {
this.updateTheme(); this.updateTheme();
this.updateConfig(); this.updateConfig();
// Force another layout (first is setContainers) since config has changed
this.layout(new Dimension(this.terminalContainer.offsetWidth, this.terminalContainer.offsetHeight));
return TPromise.as(void 0); return TPromise.as(void 0);
} }

View file

@ -65,7 +65,7 @@ function getArgs() {
function cleanEnv() { function cleanEnv() {
var keys = [ var keys = [
'ATOM_SHELL_INTERNAL_RUN_AS_NODE', 'ELECTRON_RUN_AS_NODE',
'PTYCWD', 'PTYCWD',
'PTYPID', 'PTYPID',
'PTYSHELL' 'PTYSHELL'

View file

@ -14,7 +14,7 @@ import { IPartService } from 'vs/workbench/services/part/common/partService';
import { ITerminalInstance, ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/electron-browser/terminal'; import { ITerminalInstance, ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/electron-browser/terminal';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { TerminalConfigHelper, IShell } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance'; import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance';
export class TerminalService implements ITerminalService { export class TerminalService implements ITerminalService {
@ -51,7 +51,11 @@ export class TerminalService implements ITerminalService {
this._configHelper = <TerminalConfigHelper>this.instantiationService.createInstance(TerminalConfigHelper, platform.platform); this._configHelper = <TerminalConfigHelper>this.instantiationService.createInstance(TerminalConfigHelper, platform.platform);
} }
public createInstance(name?: string, shellPath?: string): ITerminalInstance { public createInstance(name?: string, shellPath?: string, shellArgs?: string[]): ITerminalInstance {
let shell: IShell = {
executable: shellPath,
args: shellArgs
};
let terminalInstance = <TerminalInstance>this.instantiationService.createInstance(TerminalInstance, let terminalInstance = <TerminalInstance>this.instantiationService.createInstance(TerminalInstance,
this.terminalFocusContextKey, this.terminalFocusContextKey,
this.onTerminalInstanceDispose.bind(this), this.onTerminalInstanceDispose.bind(this),
@ -59,7 +63,7 @@ export class TerminalService implements ITerminalService {
this.terminalContainer, this.terminalContainer,
this.workspaceContextService.getWorkspace(), this.workspaceContextService.getWorkspace(),
name, name,
shellPath); shell);
terminalInstance.addDisposable(terminalInstance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged)); terminalInstance.addDisposable(terminalInstance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged));
this.terminalInstances.push(terminalInstance); this.terminalInstances.push(terminalInstance);
if (this.terminalInstances.length === 1) { if (this.terminalInstances.length === 1) {
@ -139,11 +143,11 @@ export class TerminalService implements ITerminalService {
} }
public setContainers(panelContainer: Builder, terminalContainer: HTMLElement): void { public setContainers(panelContainer: Builder, terminalContainer: HTMLElement): void {
this._configHelper.panelContainer = panelContainer;
this.terminalContainer = terminalContainer; this.terminalContainer = terminalContainer;
this._terminalInstances.forEach(terminalInstance => { this._terminalInstances.forEach(terminalInstance => {
terminalInstance.attachToElement(this.terminalContainer); terminalInstance.attachToElement(this.terminalContainer);
}); });
this._configHelper.panelContainer = panelContainer;
} }
public showPanel(focus?: boolean): TPromise<void> { public showPanel(focus?: boolean): TPromise<void> {
@ -151,7 +155,6 @@ export class TerminalService implements ITerminalService {
let panel = this.panelService.getActivePanel(); let panel = this.panelService.getActivePanel();
if (!panel || panel.getId() !== TERMINAL_PANEL_ID) { if (!panel || panel.getId() !== TERMINAL_PANEL_ID) {
return this.panelService.openPanel(TERMINAL_PANEL_ID, focus).then(() => { return this.panelService.openPanel(TERMINAL_PANEL_ID, focus).then(() => {
panel = this.panelService.getActivePanel();
if (focus) { if (focus) {
this.getActiveInstance().focus(true); this.getActiveInstance().focus(true);
} }

View file

@ -54,7 +54,7 @@ export class ContextMenuService implements IContextMenuService {
x *= zoom; x *= zoom;
y *= zoom; y *= zoom;
menu.popup(remote.getCurrentWindow(), Math.floor(x), Math.floor(y), -1 /* no item selected by default */); menu.popup(remote.getCurrentWindow(), Math.floor(x), Math.floor(y));
if (delegate.onHide) { if (delegate.onHide) {
delegate.onHide(undefined); delegate.onHide(undefined);
} }