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

View file

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

View file

@ -230,6 +230,7 @@ function packageTask(platform, arch, opts) {
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/cat.exe', { base: 'resources/win32' }));
result = es.merge(result, gulp.src('resources/win32/bin/code.cmd', { base: 'resources/win32' })
.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.
*--------------------------------------------------------------------------------------------*/
var es = require('event-stream');
const es = require('event-stream');
/** Ugly hack for gulp-tsb */
function handleDeletions() {
return es.mapSync(function (f) {
return es.mapSync(f => {
if (/\.ts$/.test(f.relative) && !f.contents) {
f.contents = new Buffer('');
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 () {
return watch.apply(null, arguments)

View file

@ -1,10 +1,10 @@
{
"name": "watch",
"version": "1.0.0",
"description": "",
"author": "Microsoft ",
"private": true,
"devDependencies": {
"gulp-watch": "^4.3.5"
}
"name": "watch",
"version": "1.0.0",
"description": "",
"author": "Microsoft ",
"private": true,
"devDependencies": {
"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.
*--------------------------------------------------------------------------------------------*/
var win = "Please run '.\\scripts\\npm.bat install' instead.";
var nix = "Please run './scripts/npm.sh install' instead.";
const path = require('path');
const cp = require('child_process');
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(/^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);
}
// 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",
"container": "debuggers",
"zip": "d643199/node-debug.zip",
"zip": "9263600/node-debug.zip",
"output": ""
}

View file

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

View file

@ -31,7 +31,7 @@ var stdErrPipeName = process.env['STDERR_PIPE_NAME'];
log('STDIN_PIPE_NAME: ' + stdInPipeName);
log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
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
(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['STDOUT_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);

2
npm-shrinkwrap.json generated
View file

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

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.6.0",
"electronVersion": "0.37.6",
"electronVersion": "1.3.5",
"distro": "3d44b35db8d394d6d7b2bc224675735a0a8f2704",
"author": {
"name": "Microsoft Corporation"
@ -69,7 +69,6 @@
"gulp-uglify": "^1.4.1",
"gulp-util": "^3.0.6",
"gulp-vinyl-zip": "^1.2.2",
"gulp-watch": "4.3.6",
"innosetup-compiler": "^5.5.60",
"is": "^3.1.0",
"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")")")")")"
ELECTRON="$CONTENTS/MacOS/Electron"
CLI="$CONTENTS/Resources/app/out/cli.js"
ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
exit $?

View file

@ -33,5 +33,5 @@ fi
ELECTRON="$VSCODE_PATH/@@NAME@@"
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 $?

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

Binary file not shown.

View file

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

View file

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

View file

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

View file

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

View file

@ -1,17 +1,7 @@
@echo off
setlocal
set ATOM_SHELL_INTERNAL_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
)
set ELECTRON_RUN_AS_NODE=1
pushd %~dp0\..
@ -20,7 +10,15 @@ set NAMESHORT=%NAMESHORT: "=%
set NAMESHORT=%NAMESHORT:"=%.exe
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
endlocal

View file

@ -30,11 +30,11 @@ test -d out || ./node_modules/.bin/gulp compile
# Unit Tests
export VSCODE_DEV=1
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" \
node_modules/mocha/bin/_mocha "$@"
else
cd $ROOT ; ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 \
cd $ROOT ; ELECTRON_RUN_AS_NODE=1 \
"$CODE" \
node_modules/mocha/bin/_mocha "$@"
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 {
let basepath = arg2 && getPath(arg2);
let absolutePath = getPath(arg1);
export function getPathLabel(resource: URI | string, basePathProvider?: URI | string | IWorkspaceProvider): string {
const absolutePath = getPath(resource);
if (!absolutePath) {
return null;
}
const basepath = basePathProvider && getPath(basePathProvider);
if (basepath && paths.isEqualOrParent(absolutePath, basepath)) {
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);
}
if (platform.isWindows && absolutePath[1] === ':') {
if (platform.isWindows && absolutePath && absolutePath[1] === ':') {
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)) {
let ws = (<IWorkspaceProvider>arg1).getWorkspace();
const ws = (<IWorkspaceProvider>arg1).getWorkspace();
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['STDOUT_PIPE_NAME'] = stdOutPipeName;
newEnv['STDERR_PIPE_NAME'] = stdErrPipeName;
newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1';
newEnv['ELECTRON_RUN_AS_NODE'] = '1';
return newEnv;
}

View file

@ -33,7 +33,7 @@ var stdErrPipeName = process.env['STDERR_PIPE_NAME'];
log('STDIN_PIPE_NAME: ' + stdInPipeName);
log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
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
(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['STDOUT_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);

View file

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

View file

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

View file

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

View file

@ -12,7 +12,8 @@
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(
url('flipped-cursor.svg') 1x,
url('flipped-cursor-2x.svg') 2x
@ -24,7 +25,7 @@
url('flipped-cursor-mac.svg') 1x,
url('flipped-cursor-mac-2x.svg') 2x
) 24 3, default;
}
}*/
.monaco-editor .margin-view-overlays .line-numbers.lh-odd {
margin-top: 1px;

View file

@ -25,7 +25,7 @@ class FindController extends CommonFindController implements IFindController {
) {
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 {

View file

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

View file

@ -14,7 +14,7 @@ import {Selection} from 'vs/editor/common/core/selection';
import * as strings from 'vs/base/common/strings';
import * as editorCommon from 'vs/editor/common/editorCommon';
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 {DocumentHighlightProviderRegistry} from 'vs/editor/common/modes';
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_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 {
@ -920,8 +921,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
kbOpts: {
weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.KEY_C,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C }
primary: ToggleCaseSensitiveKeybinding.primary,
mac: ToggleCaseSensitiveKeybinding.mac,
win: ToggleCaseSensitiveKeybinding.win,
linux: ToggleCaseSensitiveKeybinding.linux
}
}));
@ -932,8 +935,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
kbOpts: {
weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.KEY_W,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W }
primary: ToggleWholeWordKeybinding.primary,
mac: ToggleWholeWordKeybinding.mac,
win: ToggleWholeWordKeybinding.win,
linux: ToggleWholeWordKeybinding.linux
}
}));
@ -944,8 +949,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
kbOpts: {
weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.KEY_R,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R }
primary: ToggleRegexKeybinding.primary,
mac: ToggleRegexKeybinding.mac,
win: ToggleRegexKeybinding.win,
linux: ToggleRegexKeybinding.linux
}
}));
@ -988,8 +995,11 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
handler: x => x.showPreviousFindTerm(),
kbOpts: {
weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.UpArrow
kbExpr: ContextKeyExpr.and(CONTEXT_FIND_INPUT_FOCUSSED, EditorContextKeys.Focus),
primary: ShowPreviousFindTermKeybinding.primary,
mac: ShowPreviousFindTermKeybinding.mac,
win: ShowPreviousFindTermKeybinding.win,
linux: ShowPreviousFindTermKeybinding.linux
}
}));
@ -999,7 +1009,10 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({
handler: x => x.showNextFindTerm(),
kbOpts: {
weight: CommonEditorRegistry.commandWeight(5),
kbExpr: EditorContextKeys.Focus,
primary: KeyMod.Alt | KeyCode.DownArrow
kbExpr: ContextKeyExpr.and(CONTEXT_FIND_INPUT_FOCUSSED, EditorContextKeys.Focus),
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 {ReplaceAllCommand} from './replaceAllCommand';
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 = {
StartFindAction: 'actions.find',
@ -43,16 +64,16 @@ export const MATCHES_LIMIT = 999;
export class FindModelBoundToEditorModel {
private _editor:editorCommon.ICommonCodeEditor;
private _state:FindReplaceState;
private _toDispose:IDisposable[];
private _editor: editorCommon.ICommonCodeEditor;
private _state: FindReplaceState;
private _toDispose: IDisposable[];
private _decorations: FindDecorations;
private _ignoreModelContentChanged:boolean;
private _ignoreModelContentChanged: boolean;
private _updateDecorationsScheduler:RunOnceScheduler;
private _updateDecorationsScheduler: RunOnceScheduler;
private _isDisposed: boolean;
constructor(editor:editorCommon.ICommonCodeEditor, state:FindReplaceState) {
constructor(editor: editorCommon.ICommonCodeEditor, state: FindReplaceState) {
this._editor = editor;
this._state = state;
this._toDispose = [];
@ -64,7 +85,7 @@ export class FindModelBoundToEditorModel {
this._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100);
this._toDispose.push(this._updateDecorationsScheduler);
this._toDispose.push(this._editor.onDidChangeCursorPosition((e:editorCommon.ICursorPositionChangedEvent) => {
this._toDispose.push(this._editor.onDidChangeCursorPosition((e: editorCommon.ICursorPositionChangedEvent) => {
if (
e.reason === editorCommon.CursorChangeReason.Explicit
|| e.reason === editorCommon.CursorChangeReason.Undo
@ -75,7 +96,7 @@ export class FindModelBoundToEditorModel {
}));
this._ignoreModelContentChanged = false;
this._toDispose.push(this._editor.onDidChangeModelRawContent((e:editorCommon.IModelContentChangedEvent) => {
this._toDispose.push(this._editor.onDidChangeModelRawContent((e: editorCommon.IModelContentChangedEvent) => {
if (this._ignoreModelContentChanged) {
return;
}
@ -97,7 +118,7 @@ export class FindModelBoundToEditorModel {
this._toDispose = dispose(this._toDispose);
}
private _onStateChanged(e:FindReplaceStateChangedEvent): void {
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
if (this._isDisposed) {
// The find model is disposed during a find state changed event
return;
@ -111,8 +132,8 @@ export class FindModelBoundToEditorModel {
}
}
private static _getSearchRange(model:editorCommon.IModel, searchOnlyEditableRange:boolean, findScope:Range): Range {
let searchRange:Range;
private static _getSearchRange(model: editorCommon.IModel, searchOnlyEditableRange: boolean, findScope: Range): Range {
let searchRange: Range;
if (searchOnlyEditableRange) {
searchRange = model.getEditableRange();
@ -128,7 +149,7 @@ export class FindModelBoundToEditorModel {
return searchRange;
}
private research(moveCursor:boolean, newFindScope?:Range): void {
private research(moveCursor: boolean, newFindScope?: Range): void {
let findScope: Range = null;
if (typeof newFindScope !== 'undefined') {
findScope = newFindScope;
@ -169,7 +190,7 @@ export class FindModelBoundToEditorModel {
return false;
}
private _setCurrentFindMatch(match:Range): void {
private _setCurrentFindMatch(match: Range): void {
let matchesPosition = this._decorations.setCurrentFindMatch(match);
this._state.changeMatchInfo(
matchesPosition,
@ -181,7 +202,7 @@ export class FindModelBoundToEditorModel {
this._editor.revealRangeInCenterIfOutsideViewport(match);
}
private _moveToPrevMatch(before:Position, isRecursed:boolean = false): void {
private _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {
if (this._cannotFind()) {
return;
}
@ -199,7 +220,7 @@ export class FindModelBoundToEditorModel {
before = searchRange.getEndPosition();
}
let {lineNumber,column} = before;
let {lineNumber, column} = before;
let model = this._editor.getModel();
let position = new Position(lineNumber, column);
@ -245,8 +266,8 @@ export class FindModelBoundToEditorModel {
this._moveToPrevMatch(this._editor.getSelection().getStartPosition());
}
private _moveToNextMatch(nextMatch:Range): void
private _moveToNextMatch(after:Position): void
private _moveToNextMatch(nextMatch: Range): void
private _moveToNextMatch(after: Position): void
private _moveToNextMatch(arg: any): void {
let nextMatch = Range.isIRange(arg) ? arg : Position.isIPosition(arg) ? this._getNextMatch(arg) : null;
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()) {
return null;
}
@ -272,7 +293,7 @@ export class FindModelBoundToEditorModel {
after = searchRange.getStartPosition();
}
let {lineNumber,column} = after;
let {lineNumber, column} = after;
let model = this._editor.getModel();
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);
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)
let ranges = this._findMatches(findScope, Number.MAX_VALUE);
let replaceStrings:string[] = [];
let replaceStrings: string[] = [];
for (let i = 0, len = ranges.length; i < len; 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)));
}
private _executeEditorCommand(source:string, command:editorCommon.ICommand): void {
private _executeEditorCommand(source: string, command: editorCommon.ICommand): void {
try {
this._ignoreModelContentChanged = true;
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 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.
*/
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 {
return extHostOutputService.createOutputChannel(name);
},
createTerminal(name?: string, shellPath?: string): vscode.Terminal {
return extHostTerminalService.createTerminal(name, shellPath);
createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
return extHostTerminalService.createTerminal(name, shellPath, shellArgs);
}
};

View file

@ -153,7 +153,7 @@ export abstract class MainThreadOutputServiceShape {
}
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(); }
$hide(terminalId: number): 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 {
public _name: string;
public _shellPath: string;
private _name: string;
private _id: number;
private _proxy: MainThreadTerminalServiceShape;
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._shellPath = shellPath;
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 {
@ -31,26 +34,35 @@ export class ExtHostTerminal implements vscode.Terminal {
public sendText(text: string, addNewLine: boolean = true): void {
this._checkDisposed();
this._proxy.$sendText(this._id, text, addNewLine);
this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]);
}
public show(preserveFocus: boolean): void {
this._checkDisposed();
this._proxy.$show(this._id, preserveFocus);
this._queueApiRequest(this._proxy.$show, [preserveFocus]);
}
public hide(): void {
this._checkDisposed();
this._proxy.$hide(this._id);
this._queueApiRequest(this._proxy.$hide, []);
}
public dispose(): void {
if (!this._disposed) {
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() {
if (this._disposed) {
throw new Error('Terminal has already been disposed');
@ -66,7 +78,21 @@ export class ExtHostTerminalService {
this._proxy = threadService.get(MainContext.MainThreadTerminalService);
}
public createTerminal(name?: string, shellPath?: string): vscode.Terminal {
return new ExtHostTerminal(this._proxy, -1, name, shellPath);
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
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 {IPartService} from 'vs/workbench/services/part/common/partService';
import {MainThreadTerminalServiceShape} from './extHost.protocol';
import {TPromise} from 'vs/base/common/winjs.base';
export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
@ -19,8 +20,8 @@ export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
super();
}
public $createTerminal(name?: string, shellPath?: string): number {
return this.terminalService.createInstance(name, shellPath).id;
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): TPromise<number> {
return TPromise.as(this.terminalService.createInstance(name, shellPath, shellArgs).id);
}
public $show(terminalId: number, preserveFocus: boolean): void {

View file

@ -662,9 +662,12 @@ export class ChangeModeAction extends Action {
// All languages are valid picks
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,
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") };

View file

@ -607,7 +607,7 @@ export class DebugService implements debug.IDebugService {
timeout: 1000 * 60 * 5,
args: [`${ publisher }.${ type }`, JSON.stringify(data), aiKey],
env: {
ATOM_SHELL_INTERNAL_RUN_AS_NODE: 1,
ELECTRON_RUN_AS_NODE: 1,
PIPE_LOGGING: 'true',
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 {ExtensionsChannelId} from 'vs/platform/extensionManagement/common/extensionManagement';
import {TerminalSupport} from 'vs/workbench/parts/debug/electron-browser/terminalSupport';
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
import {shell} from 'electron';
@ -75,7 +76,8 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
@ITelemetryService private telemetryService: ITelemetryService,
@IOutputService private outputService: IOutputService,
@ITerminalService private terminalService: ITerminalService,
@IExternalTerminalService private nativeTerminalService: IExternalTerminalService
@IExternalTerminalService private nativeTerminalService: IExternalTerminalService,
@IConfigurationService private configurationService: IConfigurationService
) {
super();
this.emittedStopped = false;
@ -348,7 +350,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.IRawDebugSes
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);
}, e => {
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 {ITerminalService, ITerminalInstance} from 'vs/workbench/parts/terminal/electron-browser/terminal';
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 {
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') {
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) {
TerminalSupport.integratedTerminalInstance = terminalService.createInstance(args.title || nls.localize('debuggee', "debuggee"));
}
terminalService.setActiveInstance(TerminalSupport.integratedTerminalInstance);
terminalService.showPanel(true);
const command = this.prepareCommand(args);
const command = this.prepareCommand(args, configurationService);
TerminalSupport.integratedTerminalInstance.sendText(command, true);
return TPromise.as(void 0);
}
private static prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments): string {
private static prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, configurationService: IConfigurationService): string {
let command = '';
if (platform.isWindows) {
@ -44,21 +51,41 @@ export class TerminalSupport {
return (s.indexOf(' ') >= 0 || s.indexOf('"') >= 0) ? `"${s}"` : s;
};
if (args.cwd) {
command += `cd ${quote(args.cwd)} && `;
const conf = configurationService.getConfiguration<IIntegratedTerminalConfiguration>();
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 "';
for (let key in args.env) {
command += `set "${key}=${args.env[key]}" && `;
if (isPowerShell) {
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 {
const quote = (s: string) => {
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 { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IMessageService } from 'vs/platform/message/common/message';
import { IOpenerService } from 'vs/platform/opener/common/opener';
function renderBody(body: string): string {
return `<!DOCTYPE html>
@ -140,7 +141,8 @@ export class ExtensionEditor extends BaseEditor {
@IThemeService private themeService: IThemeService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IKeybindingService private keybindingService: IKeybindingService,
@IMessageService private messageService: IMessageService
@IMessageService private messageService: IMessageService,
@IOpenerService private openerService: IOpenerService
) {
super(ExtensionEditor.ID, telemetryService);
this._highlight = null;
@ -276,9 +278,9 @@ export class ExtensionEditor extends BaseEditor {
webview.style(this.themeService.getColorTheme());
webview.contents = [body];
const linkListener = webview.onDidClickLink(link => shell.openExternal(link.toString(true)));
const themeListener = this.themeService.onDidColorThemeChange(themeId => webview.style(themeId));
this.contentDisposables.push(webview, linkListener, themeListener);
webview.onDidClickLink(link => this.openerService.open(link), null, this.contentDisposables);
this.themeService.onDidColorThemeChange(themeId => webview.style(themeId), null, this.contentDisposables);
this.contentDisposables.push(webview);
})
.then(null, () => {
const p = append(this.content, $('p'));

View file

@ -15,6 +15,11 @@
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 .open-editor,
.explorer-viewlet .editor-group {
@ -25,6 +30,7 @@
.explorer-viewlet .explorer-item-label,
.explorer-viewlet .explorer-item .monaco-inputbox {
display: inline-block; /* required for icons support :before rule */
flex: 1;
}
.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"
if (name) {
classes.push(`${name.toLowerCase()}-name-file-icon`);
classes.push(`${this.cssEscape(name.toLowerCase())}-name-file-icon`);
}
const extensions = dotSegments.splice(1);
if (extensions.length > 0) {
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);
if (langId) {
classes.push(`${langId}-lang-file-icon`);
classes.push(`${this.cssEscape(langId)}-lang-file-icon`);
}
return classes;
@ -422,11 +422,15 @@ export class FileRenderer extends ActionsRenderer implements IRenderer {
const classes = ['folder-icon'];
if (basename) {
classes.push(`${basename.toLowerCase()}-name-folder-icon`);
classes.push(`${this.cssEscape(basename.toLowerCase())}-name-folder-icon`);
}
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

View file

@ -158,7 +158,7 @@ function createRemoteRawGitService(gitPath: string, execPath: string, workspaceR
timeout: 1000 * 60,
args: [path, workspaceRoot, encoding, execPath, version],
env: {
ATOM_SHELL_INTERNAL_RUN_AS_NODE: 1,
ELECTRON_RUN_AS_NODE: 1,
PIPE_LOGGING: 'true',
AMD_ENTRYPOINT: 'vs/workbench/parts/git/node/gitApp',
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 {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService';
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 { registerContributions as replaceContributions } from 'vs/workbench/parts/search/browser/replaceContributions';
import { registerContributions as searchWidgetContributions } from 'vs/workbench/parts/search/browser/searchWidget';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding, ShowPreviousFindTermKeybinding, ShowNextFindTermKeybinding } from 'vs/editor/contrib/find/common/findModel';
replaceContributions();
searchWidgetContributions();
@ -118,13 +119,13 @@ const openSearchViewletKb: IKeybindings = {
};
(<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',
nls.localize('view', "View")
);
(<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
}),
'Replace in Files'
@ -165,22 +166,22 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction,
primary: KeyMod.CtrlCmd | KeyCode.KEY_T
}), 'Show All Symbols');
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextSearchTermAction, ShowNextSearchTermAction.ID, ShowNextSearchTermAction.LABEL, {
primary: KeyMod.Alt | KeyCode.DownArrow
}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchTermAction, searchActions.ShowNextSearchTermAction.ID, searchActions.ShowNextSearchTermAction.LABEL, ShowNextFindTermKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousSearchTermAction, ShowPreviousSearchTermAction.ID, ShowPreviousSearchTermAction.LABEL, {
primary: KeyMod.Alt | KeyCode.UpArrow
}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), '');
registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchTermAction, searchActions.ShowPreviousSearchTermAction.ID, searchActions.ShowPreviousSearchTermAction.LABEL, ShowPreviousFindTermKeybinding, 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
}, 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
}, 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
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({

View file

@ -39,6 +39,45 @@ export function appendKeyBindingLabel(label: string, keyBinding: any, 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 {
public static ID = 'search.history.showNext';

View file

@ -617,6 +617,21 @@ export class SearchViewlet extends Viewlet {
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 {
let cls = 'more';
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 = {
label: nls.localize('label.Search', 'Search: Type Search Term and press Enter to search or Escape to cancel'),
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'));
@ -350,7 +353,7 @@ export class SearchWidget extends Widget {
export function registerContributions() {
KeybindingsRegistry.registerCommandAndKeybindingRule({id: ReplaceAllAction.ID,
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,
handler: accessor => {
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 ToggleCaseSensitiveActionId = 'toggleSearchCaseSensitive';
export const ToggleWholeWordActionId = 'toggleSearchWholeWord';
export const ToggleRegexActionId = 'toggleSearchRegex';
export const SearchViewletVisibleKey = new RawContextKey<boolean>('searchViewletVisible', true);
export const InputBoxFocussedKey = new RawContextKey<boolean>('inputBoxFocus', false);
export const SearchInputBoxFocussedKey = new RawContextKey<boolean>('searchInputBoxFocus', false);

View file

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

View file

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

View file

@ -47,6 +47,9 @@ export class KillTerminalAction extends Action {
let terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance) {
this.terminalService.getActiveInstance().dispose();
if (this.terminalService.terminalInstances.length > 0) {
this.terminalService.showPanel(true);
}
}
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; }
private isExiting: boolean = false;
private isVisible: boolean = false;
private toDispose: lifecycle.IDisposable[] = [];
private skipTerminalKeybindings: Keybinding[] = [];
private process: cp.ChildProcess;
@ -52,13 +53,13 @@ export class TerminalInstance implements ITerminalInstance {
private container: HTMLElement,
private workspace: IWorkspace,
name: string,
shellPath: string,
shell: IShell,
@IKeybindingService private keybindingService: IKeybindingService,
@IMessageService private messageService: IMessageService
) {
this._id = TerminalInstance.ID_COUNTER++;
this._onTitleChanged = new Emitter<string>();
this.createProcess(workspace, name, shellPath);
this.createProcess(workspace, name, shell);
if (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');
}
this.container = container;
this.wrapperElement = document.createElement('div');
DOM.addClass(this.wrapperElement, 'terminal-wrapper');
this.xtermElement = document.createElement('div');
@ -139,6 +141,7 @@ export class TerminalInstance implements ITerminalInstance {
this.container.appendChild(this.wrapperElement);
this.layout(new Dimension(this.container.offsetWidth, this.container.offsetHeight));
this.setVisible(this.isVisible);
}
public copySelection(): void {
@ -195,7 +198,10 @@ export class TerminalInstance implements ITerminalInstance {
}
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 {
@ -210,9 +216,11 @@ export class TerminalInstance implements ITerminalInstance {
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 shell = shellPath ? { executable: shellPath, args: [] } : this.configHelper.getShell();
if (!shell.executable) {
shell = this.configHelper.getShell();
}
let env = TerminalInstance.createTerminalEnv(process.env, shell, workspace, locale);
this._title = name ? name : '';
this.process = cp.fork('./terminalProcess', [], {
@ -244,9 +252,11 @@ export class TerminalInstance implements ITerminalInstance {
let env = TerminalInstance.cloneEnv(parentEnv);
env['PTYPID'] = process.pid.toString();
env['PTYSHELL'] = shell.executable;
shell.args.forEach((arg, i) => {
env[`PTYSHELLARG${i}`] = arg;
});
if (shell.args) {
shell.args.forEach((arg, i) => {
env[`PTYSHELLARG${i}`] = arg;
});
}
env['PTYCWD'] = TerminalInstance.sanitizeCwd(workspace ? workspace.resource.fsPath : os.homedir());
if (locale) {
env['LANG'] = TerminalInstance.getLangEnvVariable(locale);

View file

@ -72,6 +72,8 @@ export class TerminalPanel extends Panel {
this.updateTheme();
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);
}

View file

@ -65,7 +65,7 @@ function getArgs() {
function cleanEnv() {
var keys = [
'ATOM_SHELL_INTERNAL_RUN_AS_NODE',
'ELECTRON_RUN_AS_NODE',
'PTYCWD',
'PTYPID',
'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 { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
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';
export class TerminalService implements ITerminalService {
@ -51,7 +51,11 @@ export class TerminalService implements ITerminalService {
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,
this.terminalFocusContextKey,
this.onTerminalInstanceDispose.bind(this),
@ -59,7 +63,7 @@ export class TerminalService implements ITerminalService {
this.terminalContainer,
this.workspaceContextService.getWorkspace(),
name,
shellPath);
shell);
terminalInstance.addDisposable(terminalInstance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged));
this.terminalInstances.push(terminalInstance);
if (this.terminalInstances.length === 1) {
@ -139,11 +143,11 @@ export class TerminalService implements ITerminalService {
}
public setContainers(panelContainer: Builder, terminalContainer: HTMLElement): void {
this._configHelper.panelContainer = panelContainer;
this.terminalContainer = terminalContainer;
this._terminalInstances.forEach(terminalInstance => {
terminalInstance.attachToElement(this.terminalContainer);
});
this._configHelper.panelContainer = panelContainer;
}
public showPanel(focus?: boolean): TPromise<void> {
@ -151,7 +155,6 @@ export class TerminalService implements ITerminalService {
let panel = this.panelService.getActivePanel();
if (!panel || panel.getId() !== TERMINAL_PANEL_ID) {
return this.panelService.openPanel(TERMINAL_PANEL_ID, focus).then(() => {
panel = this.panelService.getActivePanel();
if (focus) {
this.getActiveInstance().focus(true);
}

View file

@ -54,7 +54,7 @@ export class ContextMenuService implements IContextMenuService {
x *= 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) {
delegate.onHide(undefined);
}