未验证 提交 5fa6084d 编写于 作者: J Johannes Rieken 提交者: GitHub

Merge branch 'master' into joh/extHostInject

......@@ -140,6 +140,7 @@ jobs:
- template: sync-mooncake.yml
trigger: none
pr: none
schedules:
- cron: "0 5 * * Mon-Fri"
......
......@@ -365,7 +365,12 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
.pipe(electron(_.extend({}, config, { platform, arch, ffmpegChromium: true })))
.pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'], { dot: true }));
// result = es.merge(result, gulp.src('resources/completions/**', { base: '.' }));
result = es.merge(result, gulp.src('resources/completions/bash/code', { base: '.' })
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename(function (f) { f.basename = product.applicationName; })));
result = es.merge(result, gulp.src('resources/completions/zsh/_code', { base: '.' })
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename(function (f) { f.basename = '_' + product.applicationName; })));
if (platform === 'win32') {
result = es.merge(result, gulp.src('resources/win32/bin/code.js', { base: 'resources/win32', allowEmpty: true }));
......
......@@ -54,11 +54,13 @@ function prepareDebPackage(arch) {
const icon = gulp.src('resources/linux/code.png', { base: '.' })
.pipe(rename('usr/share/pixmaps/' + product.linuxIconName + '.png'));
// const bash_completion = gulp.src('resources/completions/bash/code')
// .pipe(rename('usr/share/bash-completion/completions/code'));
const bash_completion = gulp.src('resources/completions/bash/code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('usr/share/bash-completion/completions/' + product.applicationName));
// const zsh_completion = gulp.src('resources/completions/zsh/_code')
// .pipe(rename('usr/share/zsh/vendor-completions/_code'));
const zsh_completion = gulp.src('resources/completions/zsh/_code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('usr/share/zsh/vendor-completions/_' + product.applicationName));
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
.pipe(rename(function (p) { p.dirname = 'usr/share/' + product.applicationName + '/' + p.dirname; }));
......@@ -94,7 +96,7 @@ function prepareDebPackage(arch) {
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
.pipe(rename('DEBIAN/postinst'));
const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, icon, /* bash_completion, zsh_completion, */ code);
const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, icon, bash_completion, zsh_completion, code);
return all.pipe(vfs.dest(destination));
};
......@@ -144,11 +146,13 @@ function prepareRpmPackage(arch) {
const icon = gulp.src('resources/linux/code.png', { base: '.' })
.pipe(rename('BUILD/usr/share/pixmaps/' + product.linuxIconName + '.png'));
// const bash_completion = gulp.src('resources/completions/bash/code')
// .pipe(rename('BUILD/usr/share/bash-completion/completions/code'));
const bash_completion = gulp.src('resources/completions/bash/code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('BUILD/usr/share/bash-completion/completions/' + product.applicationName));
// const zsh_completion = gulp.src('resources/completions/zsh/_code')
// .pipe(rename('BUILD/usr/share/zsh/site-functions/_code'));
const zsh_completion = gulp.src('resources/completions/zsh/_code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('BUILD/usr/share/zsh/site-functions/_' + product.applicationName));
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
.pipe(rename(function (p) { p.dirname = 'BUILD/usr/share/' + product.applicationName + '/' + p.dirname; }));
......@@ -171,7 +175,7 @@ function prepareRpmPackage(arch) {
const specIcon = gulp.src('resources/linux/rpm/code.xpm', { base: '.' })
.pipe(rename('SOURCES/' + product.applicationName + '.xpm'));
const all = es.merge(code, desktops, appdata, icon, /* bash_completion, zsh_completion, */ spec, specIcon);
const all = es.merge(code, desktops, appdata, icon, bash_completion, zsh_completion, spec, specIcon);
return all.pipe(vfs.dest(getRpmBuildPath(rpmArch)));
};
......
......@@ -1361,19 +1361,6 @@ export class CommandCenter {
await this.commitWithAnyInput(repository);
}
@command('git.commitWithInput', { repository: true })
async commitWithInput(repository: Repository): Promise<void> {
if (!repository.inputBox.value) {
return;
}
const didCommit = await this.smartCommit(repository, async () => repository.inputBox.value);
if (didCommit) {
repository.inputBox.value = await repository.getCommitTemplate();
}
}
@command('git.commitStaged', { repository: true })
async commitStaged(repository: Repository): Promise<void> {
await this.commitWithAnyInput(repository, { all: false });
......@@ -1498,12 +1485,12 @@ export class CommandCenter {
await this._branch(repository, undefined, true);
}
private async _branch(repository: Repository, defaultName?: string, from = false): Promise<void> {
private async promptForBranchName(defaultName?: string): Promise<string> {
const config = workspace.getConfiguration('git');
const branchWhitespaceChar = config.get<string>('branchWhitespaceChar')!;
const branchValidationRegex = config.get<string>('branchValidationRegex')!;
const sanitize = (name: string) => name ?
name.trim().replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, branchWhitespaceChar)
name.trim().replace(/^-+/, '').replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, branchWhitespaceChar)
: name;
const rawBranchName = defaultName || await window.showInputBox({
......@@ -1520,7 +1507,11 @@ export class CommandCenter {
}
});
const branchName = sanitize(rawBranchName || '');
return sanitize(rawBranchName || '');
}
private async _branch(repository: Repository, defaultName?: string, from = false): Promise<void> {
const branchName = await this.promptForBranchName(defaultName);
if (!branchName) {
return;
......@@ -1582,25 +1573,21 @@ export class CommandCenter {
@command('git.renameBranch', { repository: true })
async renameBranch(repository: Repository): Promise<void> {
const name = await window.showInputBox({
placeHolder: localize('branch name', "Branch name"),
prompt: localize('provide branch name', "Please provide a branch name"),
value: repository.HEAD && repository.HEAD.name
});
const branchName = await this.promptForBranchName();
if (!name || name.trim().length === 0) {
if (!branchName) {
return;
}
try {
await repository.renameBranch(name);
await repository.renameBranch(branchName);
} catch (err) {
switch (err.gitErrorCode) {
case GitErrorCodes.InvalidBranchName:
window.showErrorMessage(localize('invalid branch name', 'Invalid branch name'));
return;
case GitErrorCodes.BranchAlreadyExists:
window.showErrorMessage(localize('branch already exists', "A branch named '{0}' already exists", name));
window.showErrorMessage(localize('branch already exists', "A branch named '{0}' already exists", branchName));
return;
default:
throw err;
......
......@@ -1680,13 +1680,16 @@ export class Repository {
async getBranch(name: string): Promise<Branch> {
if (name === 'HEAD') {
return this.getHEAD();
} else if (/^@/.test(name)) {
const symbolicFullNameResult = await this.run(['rev-parse', '--symbolic-full-name', name]);
const symbolicFullName = symbolicFullNameResult.stdout.trim();
name = symbolicFullName || name;
}
const result = await this.run(['rev-parse', name]);
let result = await this.run(['rev-parse', name]);
if (!result.stdout && /^@/.test(name)) {
const symbolicFullNameResult = await this.run(['rev-parse', '--symbolic-full-name', name]);
name = symbolicFullNameResult.stdout.trim();
result = await this.run(['rev-parse', name]);
}
if (!result.stdout) {
return Promise.reject<Branch>(new Error('No such branch'));
......
......@@ -680,7 +680,7 @@ export class Repository implements Disposable {
const root = Uri.file(repository.root);
this._sourceControl = scm.createSourceControl('git', 'Git', root);
this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message (press {0} to commit)");
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
this._sourceControl.acceptInputCommand = { command: 'git.commit', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
this._sourceControl.quickDiffProvider = this;
this._sourceControl.inputBox.validateInput = this.validateInput.bind(this);
this.disposables.push(this._sourceControl);
......
......@@ -274,52 +274,52 @@ suite('window namespace tests', () => {
const terminal = window.createTerminal({ name: 'foo', pty });
});
test('should not provide dimensions on start as the terminal has not been shown yet', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term);
reg1.dispose();
});
const pty: Pseudoterminal = {
onDidWrite: new EventEmitter<string>().event,
open: (dimensions) => {
equal(dimensions, undefined);
const reg3 = window.onDidCloseTerminal(() => {
reg3.dispose();
done();
});
// Show a terminal and wait a brief period before dispose, this will cause
// the panel to init it's dimenisons and be provided to following terminals.
// The following test depends on this.
terminal.show();
setTimeout(() => terminal.dispose(), 200);
},
close: () => {}
};
const terminal = window.createTerminal({ name: 'foo', pty });
});
test('should provide dimensions on start as the terminal has been shown', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term);
reg1.dispose();
});
const pty: Pseudoterminal = {
onDidWrite: new EventEmitter<string>().event,
open: (dimensions) => {
// This test depends on Terminal.show being called some time before such
// that the panel dimensions are initialized and cached.
ok(dimensions!.columns > 0);
ok(dimensions!.rows > 0);
const reg3 = window.onDidCloseTerminal(() => {
reg3.dispose();
done();
});
terminal.dispose();
},
close: () => {}
};
const terminal = window.createTerminal({ name: 'foo', pty });
});
// The below tests depend on global UI state and each other
// test('should not provide dimensions on start as the terminal has not been shown yet', (done) => {
// const reg1 = window.onDidOpenTerminal(term => {
// equal(terminal, term);
// reg1.dispose();
// });
// const pty: Pseudoterminal = {
// onDidWrite: new EventEmitter<string>().event,
// open: (dimensions) => {
// equal(dimensions, undefined);
// const reg3 = window.onDidCloseTerminal(() => {
// reg3.dispose();
// done();
// });
// // Show a terminal and wait a brief period before dispose, this will cause
// // the panel to init it's dimenisons and be provided to following terminals.
// // The following test depends on this.
// terminal.show();
// setTimeout(() => terminal.dispose(), 200);
// },
// close: () => {}
// };
// const terminal = window.createTerminal({ name: 'foo', pty });
// });
// test('should provide dimensions on start as the terminal has been shown', (done) => {
// const reg1 = window.onDidOpenTerminal(term => {
// equal(terminal, term);
// reg1.dispose();
// });
// const pty: Pseudoterminal = {
// onDidWrite: new EventEmitter<string>().event,
// open: (dimensions) => {
// // This test depends on Terminal.show being called some time before such
// // that the panel dimensions are initialized and cached.
// ok(dimensions!.columns > 0);
// ok(dimensions!.rows > 0);
// const reg3 = window.onDidCloseTerminal(() => {
// reg3.dispose();
// done();
// });
// terminal.dispose();
// },
// close: () => {}
// };
// const terminal = window.createTerminal({ name: 'foo', pty });
// });
test('should respect dimension overrides', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
......
{
"name": "code-oss-dev",
"version": "1.38.0",
"distro": "f123663d79c57c07e3f70b2d0938f1a58ff4d1da",
"distro": "1413fa0e8982b468bc452d742bbd60c36b0cb45e",
"author": {
"name": "Microsoft Corporation"
},
......@@ -35,7 +35,6 @@
"iconv-lite": "0.5.0",
"jschardet": "1.6.0",
"keytar": "^4.11.0",
"minimist": "1.2.0",
"native-is-elevated": "0.3.0",
"native-keymap": "2.0.0",
"native-watchdog": "1.0.0",
......@@ -47,6 +46,7 @@
"sudo-prompt": "9.0.0",
"v8-inspect-profiler": "^0.0.20",
"vscode-chokidar": "2.1.7",
"vscode-minimist": "^1.2.1",
"vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.5",
"vscode-sqlite3": "4.0.8",
......@@ -60,7 +60,6 @@
"devDependencies": {
"7zip": "0.0.6",
"@types/keytar": "^4.4.0",
"@types/minimist": "^1.2.0",
"@types/mocha": "2.2.39",
"@types/node": "^10.12.12",
"@types/semver": "^5.5.0",
......
......@@ -9,7 +9,6 @@
"https-proxy-agent": "^2.2.1",
"iconv-lite": "0.5.0",
"jschardet": "1.6.0",
"minimist": "1.2.0",
"native-watchdog": "1.0.0",
"node-pty": "0.9.0-beta19",
"nsfw": "1.2.5",
......@@ -17,6 +16,7 @@
"semver-umd": "^5.5.3",
"spdlog": "^0.9.0",
"vscode-chokidar": "2.1.7",
"vscode-minimist": "^1.2.1",
"vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.5",
"vscode-textmate": "^4.2.2",
......
......@@ -660,11 +660,6 @@ minimist@0.0.8:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
minimist@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
mixin-deep@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
......@@ -1113,6 +1108,11 @@ vscode-fsevents@1.2.12:
dependencies:
nan "^2.14.0"
vscode-minimist@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a"
integrity sha512-cmB72+qDoiCFJ1UKnGUBdGYfXzdpJ3bQM/D/+XhkVk5v7uZgLbYiCz5JcwVyk7NC7hSi5VGtQ4wihzmi12NeXw==
vscode-proxy-agent@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.4.0.tgz#574833e65405c6333f350f1b9fef9909deccb6b5"
......
_code()
_@@APPNAME@@()
{
local cur prev words cword split
_init_completion -s || return
......@@ -58,4 +58,4 @@ _code()
_filedir
} &&
complete -F _code code
complete -F _@@APPNAME@@ @@APPNAME@@
#compdef code
#compdef @@APPNAME@@
local arguments
......@@ -14,7 +14,7 @@ arguments=(
'--user-data-dir[specify the directory that user data is kept in]:directory:_directories'
'(- *)'{-v,--version}'[print version]'
'(- *)'{-h,--help}'[print usage]'
'(- *)'{--telemetry}'[Shows all telemetry events which VS code collects.]'
'--telemetry[show all telemetry events which VS code collects]'
'--extensions-dir[set the root path for extensions]:root path:_directories'
'--list-extensions[list the installed extensions]'
'--category[filters instaled extension list by category, when using --list-extension]'
......
......@@ -18,14 +18,14 @@ Visual Studio Code is a new choice of tool that combines the simplicity of a cod
mkdir -p %{buildroot}/usr/share/@@NAME@@
mkdir -p %{buildroot}/usr/share/applications
mkdir -p %{buildroot}/usr/share/pixmaps
#mkdir -p %{buildroot}/usr/share/bash-completion/completions
#mkdir -p %{buildroot}/usr/share/zsh/site-functions
mkdir -p %{buildroot}/usr/share/bash-completion/completions
mkdir -p %{buildroot}/usr/share/zsh/site-functions
cp -r usr/share/@@NAME@@/* %{buildroot}/usr/share/@@NAME@@
cp -r usr/share/applications/@@NAME@@.desktop %{buildroot}/usr/share/applications
cp -r usr/share/applications/@@NAME@@-url-handler.desktop %{buildroot}/usr/share/applications
cp -r usr/share/pixmaps/@@ICON@@.png %{buildroot}/usr/share/pixmaps
#cp usr/share/bash-completion/completions/code %{buildroot}/usr/share/bash-completion/completions/code
#cp usr/share/zsh/site-functions/_code %{buildroot}/usr/share/zsh/site-functions/_code
cp usr/share/bash-completion/completions/@@NAME@@ %{buildroot}/usr/share/bash-completion/completions/@@NAME@@
cp usr/share/zsh/site-functions/_@@NAME@@ %{buildroot}/usr/share/zsh/site-functions/_@@NAME@@
%post
# Remove the legacy bin command if this is the stable build
......@@ -58,5 +58,5 @@ fi
/usr/share/applications/@@NAME@@.desktop
/usr/share/applications/@@NAME@@-url-handler.desktop
/usr/share/pixmaps/@@ICON@@.png
#/usr/share/bash-completion/completions/code
#/usr/share/zsh/site-functions/_code
/usr/share/bash-completion/completions/@@NAME@@
/usr/share/zsh/site-functions/_@@NAME@@
// Type definitions for minimist 1.2.0
// Project: https://github.com/substack/minimist
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>, Necroskillz <https://github.com/Necroskillz>, kamranayub <https://github.com/kamranayub>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/**
* Return an argument object populated with the array arguments from args
*
* @param args An optional argument array (typically `process.argv.slice(2)`)
* @param opts An optional options object to customize the parsing
*/
declare function minimist(args?: string[], opts?: minimist.Opts): minimist.ParsedArgs;
/**
* Return an argument object populated with the array arguments from args. Strongly-typed
* to be the intersect of type T with minimist.ParsedArgs.
*
* @type T The type that will be intersected with minimist.ParsedArgs to represent the argument object
* @param args An optional argument array (typically `process.argv.slice(2)`)
* @param opts An optional options object to customize the parsing
*/
declare function minimist<T>(args?: string[], opts?: minimist.Opts): T & minimist.ParsedArgs;
/**
* Return an argument object populated with the array arguments from args. Strongly-typed
* to be the the type T which should extend minimist.ParsedArgs
*
* @type T The type that extends minimist.ParsedArgs and represents the argument object
* @param args An optional argument array (typically `process.argv.slice(2)`)
* @param opts An optional options object to customize the parsing
*/
declare function minimist<T extends minimist.ParsedArgs>(args?: string[], opts?: minimist.Opts): T;
declare namespace minimist {
export interface Opts {
/**
* A string or array of strings argument names to always treat as strings
*/
string?: string | string[];
/**
* A boolean, string or array of strings to always treat as booleans. If true will treat
* all double hyphenated arguments without equals signs as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`)
*/
boolean?: boolean | string | string[];
/**
* An object mapping string names to strings or arrays of string argument names to use as aliases
*/
alias?: { [key: string]: string | string[] };
/**
* An object mapping string argument names to default values
*/
default?: { [key: string]: any };
/**
* When true, populate argv._ with everything after the first non-option
*/
stopEarly?: boolean;
/**
* A function which is invoked with a command line parameter not defined in the opts
* configuration object. If the function returns false, the unknown option is not added to argv
*/
unknown?: (arg: string) => boolean;
/**
* When true, populate argv._ with everything before the -- and argv['--'] with everything after the --.
* Note that with -- set, parsing for arguments still stops after the `--`.
*/
'--'?: boolean;
}
export interface ParsedArgs {
[arg: string]: any;
/**
* If opts['--'] is true, populated with everything after the --
*/
'--'?: string[];
/**
* Contains all the arguments that didn't have an option associated with them
*/
_: string[];
}
}
declare module "vscode-minimist" {
export = minimist;
}
......@@ -58,6 +58,8 @@ class ErrorInvalidArgType extends Error {
msg += `. Received type ${typeof actual}`;
super(msg);
this.code = 'ERR_INVALID_ARG_TYPE';
}
}
......
......@@ -47,8 +47,8 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
return new Promise<IDecodeStreamResult>((resolve, reject) => {
const writer = new class extends Writable {
private decodeStream: NodeJS.ReadWriteStream;
private decodeStreamPromise: Promise<void>;
private decodeStream: NodeJS.ReadWriteStream | undefined;
private decodeStreamPromise: Promise<void> | undefined;
private bufferedChunks: Buffer[] = [];
private bytesBuffered = 0;
......@@ -122,7 +122,7 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
// detection. thus, wrap up starting the stream even
// without all the data to get things going
else {
this._startDecodeStream(() => this.decodeStream.end(callback));
this._startDecodeStream(() => this.decodeStream!.end(callback));
}
}
};
......
......@@ -31,7 +31,7 @@ class QueueProtocol implements IMessagePassingProtocol {
});
readonly onMessage = this._onMessage.event;
other: QueueProtocol;
other!: QueueProtocol;
send(buffer: VSBuffer): void {
this.other.receive(buffer);
......
......@@ -57,7 +57,7 @@ export class QuickOpenEntry {
private labelHighlights: IHighlight[];
private descriptionHighlights?: IHighlight[];
private detailHighlights?: IHighlight[];
private hidden: boolean;
private hidden: boolean | undefined;
constructor(highlights: IHighlight[] = []) {
this.id = (IDS++).toString();
......@@ -148,7 +148,7 @@ export class QuickOpenEntry {
* Allows to reuse the same model while filtering. Hidden entries will not show up in the viewer.
*/
isHidden(): boolean {
return this.hidden;
return !!this.hidden;
}
/**
......
......@@ -18,7 +18,7 @@ export class SharedProcess implements ISharedProcess {
private barrier = new Barrier();
private window: Electron.BrowserWindow | null;
private window: Electron.BrowserWindow | null = null;
constructor(
private readonly machineId: string,
......
......@@ -446,14 +446,8 @@ export class TextAreaHandler extends ViewPart {
private _primaryCursorVisibleRange: HorizontalRange | null = null;
public prepareRender(ctx: RenderingContext): void {
if (this._accessibilitySupport === AccessibilitySupport.Enabled) {
// Do not move the textarea with the cursor, as this generates accessibility events that might confuse screen readers
// See https://github.com/Microsoft/vscode/issues/26730
this._primaryCursorVisibleRange = null;
} else {
const primaryCursorPosition = new Position(this._selections[0].positionLineNumber, this._selections[0].positionColumn);
this._primaryCursorVisibleRange = ctx.visibleRangeForPosition(primaryCursorPosition);
}
const primaryCursorPosition = new Position(this._selections[0].positionLineNumber, this._selections[0].positionColumn);
this._primaryCursorVisibleRange = ctx.visibleRangeForPosition(primaryCursorPosition);
}
public render(ctx: RestrictedRenderingContext): void {
......
......@@ -21,6 +21,7 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
private _renderResult: string[] | null;
private _enabled: boolean;
private _activeIndentEnabled: boolean;
private _maxIndentLeft: number;
constructor(context: ViewContext) {
super();
......@@ -30,6 +31,9 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
this._spaceWidth = this._context.configuration.editor.fontInfo.spaceWidth;
this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides;
this._activeIndentEnabled = this._context.configuration.editor.viewInfo.highlightActiveIndentGuide;
const wrappingColumn = this._context.configuration.editor.wrappingInfo.wrappingColumn;
this._maxIndentLeft = wrappingColumn === -1 ? -1 : (wrappingColumn * this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth);
this._renderResult = null;
this._context.addEventHandler(this);
......@@ -54,6 +58,10 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides;
this._activeIndentEnabled = this._context.configuration.editor.viewInfo.highlightActiveIndentGuide;
}
if (e.wrappingInfo || e.fontInfo) {
const wrappingColumn = this._context.configuration.editor.wrappingInfo.wrappingColumn;
this._maxIndentLeft = wrappingColumn === -1 ? -1 : (wrappingColumn * this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth);
}
return true;
}
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
......@@ -133,7 +141,7 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
const className = (containsActiveIndentGuide && i === activeIndentLevel ? 'cigra' : 'cigr');
result += `<div class="${className}" style="left:${left}px;height:${lineHeight}px;width:${indentWidth}px"></div>`;
left += indentWidth;
if (left > scrollWidth) {
if (left > scrollWidth || (this._maxIndentLeft > 0 && left > this._maxIndentLeft)) {
break;
}
}
......
......@@ -31,9 +31,9 @@ export class QuickOpenController implements editorCommon.IEditorContribution, ID
}
private readonly editor: ICodeEditor;
private widget: QuickOpenEditorWidget | null;
private rangeHighlightDecorationId: string | null;
private lastKnownEditorSelection: Selection | null;
private widget: QuickOpenEditorWidget | null = null;
private rangeHighlightDecorationId: string | null = null;
private lastKnownEditorSelection: Selection | null = null;
constructor(editor: ICodeEditor, @IThemeService private readonly themeService: IThemeService) {
this.editor = editor;
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as minimist from 'minimist';
import * as minimist from 'vscode-minimist';
import * as os from 'os';
import { localize } from 'vs/nls';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
......
......@@ -52,4 +52,15 @@ suite('EnvironmentService', () => {
assert.equal(parse(['--user-data-dir', './dir'], { cwd: () => '/foo', env: { 'VSCODE_CWD': '/bar' } }), path.resolve('/bar/dir'),
'should use VSCODE_CWD as the cwd when --user-data-dir is specified');
});
// https://github.com/microsoft/vscode/issues/78440
test('careful with boolean file names', function () {
let actual = parseArgs(['-r', 'arg.txt']);
assert(actual['reuse-window']);
assert.deepEqual(actual._, ['arg.txt']);
actual = parseArgs(['-r', 'true.txt']);
assert(actual['reuse-window']);
assert.deepEqual(actual._, ['true.txt']);
});
});
......@@ -18,7 +18,7 @@ export class OutOfProcessWin32FolderWatcher {
private ignored: glob.ParsedPattern[];
private handle: cp.ChildProcess;
private handle: cp.ChildProcess | undefined;
private restartCounter: number;
constructor(
......
......@@ -62,9 +62,9 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider {
totalBytesRead: number = 0;
private invalidStatSize: boolean;
private invalidStatSize: boolean = false;
private _testCapabilities: FileSystemProviderCapabilities;
private _testCapabilities!: FileSystemProviderCapabilities;
get capabilities(): FileSystemProviderCapabilities {
if (!this._testCapabilities) {
this._testCapabilities =
......
......@@ -11,7 +11,7 @@ import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiatio
export class LocalizationsService implements ILocalizationsService {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private channel: IChannel;
......@@ -24,4 +24,4 @@ export class LocalizationsService implements ILocalizationsService {
getLanguageIds(type?: LanguageType): Promise<string[]> {
return this.channel.call('getLanguageIds', type);
}
}
\ No newline at end of file
}
......@@ -93,7 +93,7 @@ class LanguagePacksCache extends Disposable {
private languagePacks: { [language: string]: ILanguagePack } = {};
private languagePacksFilePath: string;
private languagePacksFileLimiter: Queue<any>;
private initializedCache: boolean;
private initializedCache: boolean | undefined;
constructor(
@IEnvironmentService environmentService: IEnvironmentService,
......@@ -184,4 +184,4 @@ class LanguagePacksCache extends Disposable {
.then(() => result, error => this.logService.error(error));
});
}
}
\ No newline at end of file
}
......@@ -120,7 +120,7 @@ export interface IOperation {
export class LongRunningOperation extends Disposable {
private currentOperationId = 0;
private readonly currentOperationDisposables = this._register(new DisposableStore());
private currentProgressRunner: IProgressRunner;
private currentProgressRunner: IProgressRunner | undefined;
private currentProgressTimeout: any;
constructor(
......
......@@ -38,7 +38,7 @@ export class RequestService extends Disposable implements IRequestService {
_serviceBrand: any;
private proxyUrl?: string;
private strictSSL: boolean;
private strictSSL: boolean | undefined;
private authorization?: string;
constructor(
......@@ -143,4 +143,4 @@ export class RequestService extends Disposable implements IRequestService {
}
}
\ No newline at end of file
}
......@@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/screencast';
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/platform/windows/common/windows';
import * as nls from 'vs/nls';
......@@ -110,19 +112,7 @@ export class ToggleScreencastModeAction extends Action {
const container = this.layoutService.getWorkbenchElement();
const mouseMarker = append(container, $('div'));
mouseMarker.style.position = 'absolute';
mouseMarker.style.border = '2px solid red';
mouseMarker.style.borderRadius = '20px';
mouseMarker.style.width = '20px';
mouseMarker.style.height = '20px';
mouseMarker.style.top = '0';
mouseMarker.style.left = '0';
mouseMarker.style.zIndex = '100000';
mouseMarker.style.content = ' ';
mouseMarker.style.pointerEvents = 'none';
mouseMarker.style.display = 'none';
const mouseMarker = append(container, $('.screencast-mouse'));
const onMouseDown = domEvent(container, 'mousedown', true);
const onMouseUp = domEvent(container, 'mouseup', true);
const onMouseMove = domEvent(container, 'mousemove', true);
......@@ -143,23 +133,10 @@ export class ToggleScreencastModeAction extends Action {
});
});
const keyboardMarker = append(container, $('div'));
keyboardMarker.style.position = 'absolute';
keyboardMarker.style.backgroundColor = 'rgba(0, 0, 0 ,0.5)';
keyboardMarker.style.width = '100%';
keyboardMarker.style.height = '100px';
keyboardMarker.style.bottom = '20%';
keyboardMarker.style.left = '0';
keyboardMarker.style.zIndex = '100000';
keyboardMarker.style.pointerEvents = 'none';
keyboardMarker.style.color = 'white';
keyboardMarker.style.lineHeight = '100px';
keyboardMarker.style.textAlign = 'center';
keyboardMarker.style.fontSize = '56px';
keyboardMarker.style.display = 'none';
const keyboardMarker = append(container, $('.screencast-keyboard'));
const onKeyDown = domEvent(container, 'keydown', true);
let keyboardTimeout: IDisposable = Disposable.None;
let length = 0;
const keyboardListener = onKeyDown(e => {
keyboardTimeout.dispose();
......@@ -168,20 +145,21 @@ export class ToggleScreencastModeAction extends Action {
const keybinding = this.keybindingService.resolveKeyboardEvent(event);
const label = keybinding.getLabel();
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && this.keybindingService.mightProducePrintableCharacter(event) && label) {
keyboardMarker.textContent += ' ' + label;
} else {
keyboardMarker.textContent = label;
if (event.ctrlKey || event.altKey || event.metaKey || event.shiftKey || length > 20) {
keyboardMarker.innerHTML = '';
length = 0;
}
keyboardMarker.style.display = 'block';
const key = $('span.key', {}, label || '');
length++;
append(keyboardMarker, key);
const promise = timeout(800);
keyboardTimeout = toDisposable(() => promise.cancel());
promise.then(() => {
keyboardMarker.textContent = '';
keyboardMarker.style.display = 'none';
length = 0;
});
});
......@@ -219,4 +197,4 @@ const developerCategory = nls.localize('developer', "Developer");
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Screencast Mode', developerCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory);
\ No newline at end of file
registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .screencast-mouse {
position: absolute;
border: 2px solid red;
border-radius: 20px;
width: 20px;
height: 20px;
top: 0;
left: 0;
z-index: 100000;
content: ' ';
pointer-events: none;
display: none;
}
.monaco-workbench .screencast-keyboard {
position: absolute;
background-color: rgba(0, 0, 0 ,0.5);
width: 100%;
height: 100px;
bottom: 20%;
left: 0;
z-index: 100000;
pointer-events: none;
color: #eee;
line-height: 100px;
text-align: center;
font-size: 56px;
transition: opacity 0.3s ease-out;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
direction: rtl;
}
.monaco-workbench .screencast-keyboard:empty {
opacity: 0;
}
.monaco-workbench .screencast-keyboard > .key {
padding: 0 8px;
box-shadow: inset 0 -3px 0 hsla(0,0%,73%,.4);
margin-right: 6px;
border: 1px solid hsla(0,0%,80%,.4);
border-radius: 5px;
background-color: rgba(255, 255, 255, 0.05);
}
......@@ -34,6 +34,7 @@ import { Part } from 'vs/workbench/browser/part';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { IFileService } from 'vs/platform/files/common/files';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
enum Settings {
MENUBAR_VISIBLE = 'window.menuBarVisibility',
......@@ -578,7 +579,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.zenMode.active = !this.state.zenMode.active;
this.state.zenMode.transitionDisposables.clear();
const setLineNumbers = (lineNumbers: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => editor.updateOptions({ lineNumbers }));
const setLineNumbers = (lineNumbers?: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => {
// To properly reset line numbers we need to read the configuration for each editor respecting it's uri.
if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) {
const model = editor.getModel();
this.configurationService.getValue('editor.lineNumbers', { resource: model.uri });
} else {
editor.updateOptions({ lineNumbers });
}
});
// Check if zen mode transitioned to full screen and if now we are out of zen mode
// -> we need to go out of full screen (same goes for the centered editor layout)
......@@ -641,7 +650,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.centerEditorLayout(false, true);
}
setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
setLineNumbers();
// Status bar and activity bar visibility come from settings -> update their visibility.
this.doUpdateLayoutConfiguration(true);
......
......@@ -285,4 +285,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
if (notificationBorderColor) {
collector.addRule(`.monaco-workbench > .notifications-center .notifications-list-container .monaco-list-row[data-last-element="false"] > .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`);
}
});
\ No newline at end of file
});
......@@ -11,12 +11,12 @@ import { localize } from 'vs/nls';
export class NotificationsStatus extends Disposable {
private notificationsCenterStatusItem: IStatusbarEntryAccessor;
private notificationsCenterStatusItem: IStatusbarEntryAccessor | undefined;
private currentNotifications = new Set<INotificationViewItem>();
private currentStatusMessage: [IStatusMessageViewItem, IDisposable] | undefined;
private isNotificationsCenterVisible: boolean;
private isNotificationsCenterVisible: boolean | undefined;
constructor(
private model: INotificationsModel,
......@@ -172,4 +172,4 @@ export class NotificationsStatus extends Disposable {
// Remember as current status message
this.currentStatusMessage = [item, statusMessageDispose];
}
}
\ No newline at end of file
}
......@@ -62,7 +62,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
}
// Last row: source and buttons if we have any
if (notification.source || isNonEmptyArray(notification.actions.primary)) {
if (notification.source || isNonEmptyArray(notification.actions && notification.actions.primary)) {
expandedHeight += NotificationsListDelegate.ROW_HEIGHT;
}
......@@ -82,7 +82,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
if (notification.canCollapse) {
actions++; // expand/collapse
}
if (isNonEmptyArray(notification.actions.secondary)) {
if (isNonEmptyArray(notification.actions && notification.actions.secondary)) {
actions++; // secondary actions
}
this.offsetHelper.style.width = `calc(100% - ${10 /* padding */ + 24 /* severity icon */ + (actions * 24) /* 24px per action */}px)`;
......@@ -392,8 +392,9 @@ export class NotificationTemplateRenderer extends Disposable {
const actions: IAction[] = [];
// Secondary Actions
if (isNonEmptyArray(notification.actions.secondary)) {
const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, notification.actions.secondary);
const secondaryActions = notification.actions ? notification.actions.secondary : undefined;
if (isNonEmptyArray(secondaryActions)) {
const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, secondaryActions);
actions.push(configureNotificationAction);
this.inputDisposables.add(configureNotificationAction);
}
......@@ -435,10 +436,11 @@ export class NotificationTemplateRenderer extends Disposable {
private renderButtons(notification: INotificationViewItem): void {
clearNode(this.template.buttonsContainer);
if (notification.expanded && notification.actions.primary) {
const buttonGroup = new ButtonGroup(this.template.buttonsContainer, notification.actions.primary.length, { title: true /* assign titles to buttons in case they overflow */ });
const primaryActions = notification.actions ? notification.actions.primary : undefined;
if (notification.expanded && isNonEmptyArray(primaryActions)) {
const buttonGroup = new ButtonGroup(this.template.buttonsContainer, primaryActions.length, { title: true /* assign titles to buttons in case they overflow */ });
buttonGroup.buttons.forEach((button, index) => {
const action = notification.actions.primary![index];
const action = primaryActions[index];
button.label = action.label;
this.inputDisposables.add(button.onDidClick(e => {
......
......@@ -728,7 +728,9 @@ export class SimpleWindowsService implements IWindowsService {
}
// add connection token
newAddress += `${this.workbenchEnvironmentService.configuration.connectionToken ? `tkn=${this.workbenchEnvironmentService.configuration.connectionToken}` : ''}`;
if (this.workbenchEnvironmentService.configuration.connectionToken) {
newAddress += `&tkn=${this.workbenchEnvironmentService.configuration.connectionToken}`;
}
window.open(newAddress);
......
......@@ -38,8 +38,8 @@ export interface IWorkbenchContributionsRegistry {
}
class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry {
private instantiationService: IInstantiationService;
private lifecycleService: ILifecycleService;
private instantiationService: IInstantiationService | undefined;
private lifecycleService: ILifecycleService | undefined;
private readonly toBeInstantiated: Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]> = new Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]>();
......@@ -67,7 +67,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry
this.lifecycleService = accessor.get(ILifecycleService);
[LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually].forEach(phase => {
this.instantiateByPhase(this.instantiationService, this.lifecycleService, phase);
this.instantiateByPhase(this.instantiationService!, this.lifecycleService!, phase);
});
}
......
......@@ -17,8 +17,8 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
* The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated.
*/
export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport {
protected textEditorModelHandle: URI | null;
private createdEditorModel: boolean;
protected textEditorModelHandle: URI | null = null;
private createdEditorModel: boolean | undefined;
private readonly modelDisposeListener = this._register(new MutableDisposable());
......
......@@ -243,7 +243,7 @@ export interface INotificationViewItem {
readonly silent: boolean;
readonly message: INotificationMessage;
readonly source: string | undefined;
readonly actions: INotificationActions;
readonly actions: INotificationActions | undefined;
readonly progress: INotificationViewItemProgress;
readonly expanded: boolean;
......@@ -391,10 +391,10 @@ export class NotificationViewItem extends Disposable implements INotificationVie
// RegEx: [, anything not ], ], (, http://|https://|command:, no whitespace)
private static LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: "([^"]+)")?\)/gi;
private _expanded: boolean;
private _expanded: boolean | undefined;
private _actions: INotificationActions;
private _progress: NotificationViewItemProgress;
private _actions: INotificationActions | undefined;
private _progress: NotificationViewItemProgress | undefined;
private readonly _onDidExpansionChange: Emitter<void> = this._register(new Emitter<void>());
readonly onDidExpansionChange: Event<void> = this._onDidExpansionChange.event;
......@@ -505,7 +505,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
}
get expanded(): boolean {
return this._expanded;
return !!this._expanded;
}
get severity(): Severity {
......@@ -534,6 +534,10 @@ export class NotificationViewItem extends Disposable implements INotificationVie
}
hasPrompt(): boolean {
if (!this._actions) {
return false;
}
if (!this._actions.primary) {
return false;
}
......@@ -562,7 +566,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return this._source;
}
get actions(): INotificationActions {
get actions(): INotificationActions | undefined {
return this._actions;
}
......@@ -635,8 +639,8 @@ export class NotificationViewItem extends Disposable implements INotificationVie
return false;
}
const primaryActions = this._actions.primary || [];
const otherPrimaryActions = other.actions.primary || [];
const primaryActions = (this._actions && this._actions.primary) || [];
const otherPrimaryActions = (other.actions && other.actions.primary) || [];
if (primaryActions.length !== otherPrimaryActions.length) {
return false;
}
......@@ -704,4 +708,4 @@ class StatusMessageViewItem {
return { message, options };
}
}
\ No newline at end of file
}
......@@ -46,13 +46,13 @@ export class FeedbackDropdown extends Dropdown {
private readonly feedbackDelegate: IFeedbackDelegate;
private feedbackForm: HTMLFormElement | null;
private feedbackDescriptionInput: HTMLTextAreaElement | null;
private smileyInput: HTMLElement | null;
private frownyInput: HTMLElement | null;
private sendButton: Button;
private hideButton: HTMLInputElement;
private remainingCharacterCount: HTMLElement;
private feedbackForm: HTMLFormElement | null = null;
private feedbackDescriptionInput: HTMLTextAreaElement | null = null;
private smileyInput: HTMLElement | null = null;
private frownyInput: HTMLElement | null = null;
private sendButton: Button | null = null;
private hideButton: HTMLInputElement | null = null;
private remainingCharacterCount: HTMLElement | null = null;
private requestFeatureLink: string | undefined;
......@@ -253,7 +253,7 @@ export class FeedbackDropdown extends Dropdown {
// Checkbox: Hide Feedback Smiley
const hideButtonContainer = dom.append(buttonsContainer, dom.$('div.hide-button-container'));
this.hideButton = dom.append(hideButtonContainer, dom.$('input.hide-button'));
this.hideButton = dom.append(hideButtonContainer, dom.$('input.hide-button')) as HTMLInputElement;
this.hideButton.type = 'checkbox';
this.hideButton.checked = true;
this.hideButton.id = 'hide-button';
......@@ -316,7 +316,7 @@ export class FeedbackDropdown extends Dropdown {
}
private updateCharCountText(): void {
if (this.feedbackDescriptionInput) {
if (this.feedbackDescriptionInput && this.remainingCharacterCount && this.sendButton) {
this.remainingCharacterCount.innerText = this.getCharCountText(this.feedbackDescriptionInput.value.length);
this.sendButton.enabled = this.feedbackDescriptionInput.value.length > 0;
}
......@@ -434,4 +434,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
if (linkColor) {
collector.addRule(`.monaco-workbench .feedback-form .content .channels a { color: ${linkColor}; }`);
}
});
\ No newline at end of file
});
......@@ -47,8 +47,8 @@ class TwitterFeedbackService implements IFeedbackDelegate {
}
export class FeedbackStatusbarConribution extends Disposable implements IWorkbenchContribution {
private dropdown: FeedbackDropdown;
private entry: IStatusbarEntryAccessor;
private dropdown: FeedbackDropdown | undefined;
private entry: IStatusbarEntryAccessor | undefined;
constructor(
@IStatusbarService statusbarService: IStatusbarService,
......@@ -72,15 +72,17 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben
this.dropdown = this._register(this.instantiationService.createInstance(FeedbackDropdown, statusContainr.getElementsByClassName('octicon').item(0), {
contextViewProvider: this.contextViewService,
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService),
onFeedbackVisibilityChange: visible => this.entry.update(this.getStatusEntry(visible))
onFeedbackVisibilityChange: visible => this.entry!.update(this.getStatusEntry(visible))
}));
}
}
if (!this.dropdown.isVisible()) {
this.dropdown.show();
} else {
this.dropdown.hide();
if (this.dropdown) {
if (!this.dropdown.isVisible()) {
this.dropdown.show();
} else {
this.dropdown.hide();
}
}
}
......@@ -92,4 +94,4 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben
};
}
}
\ No newline at end of file
}
......@@ -167,8 +167,9 @@ export class WorkspaceChangeExtHostRelauncher extends Disposable implements IWor
if (!!environmentService.extensionTestsLocationURI) {
return; // no restart when in tests: see https://github.com/Microsoft/vscode/issues/66936
}
if (environmentService.configuration.remoteAuthority) {
windowSevice.reloadWindow(); // TODO aeschli, workaround
windowSevice.reloadWindow(); // TODO@aeschli, workaround
} else {
extensionService.restartExtensionHost();
}
......
......@@ -73,6 +73,11 @@ import { RunAutomaticTasks } from 'vs/workbench/contrib/tasks/browser/runAutomat
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { format } from 'vs/base/common/jsonFormatter';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { applyEdits } from 'vs/base/common/jsonEdit';
import { ITextEditor } from 'vs/workbench/common/editor';
import { ITextEditorSelection } from 'vs/platform/editor/common/editor';
export namespace ConfigureTaskAction {
export const ID = 'workbench.action.tasks.configureTaskRunner';
......@@ -220,7 +225,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@ITerminalInstanceService private readonly terminalInstanceService: ITerminalInstanceService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@ITextModelService private readonly textModelResolverService: ITextModelService
) {
super();
......@@ -769,6 +775,60 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return false;
}
private openEditorAtTask(resource: URI | undefined, task: TaskConfig.CustomTask | TaskConfig.ConfiguringTask | string | undefined): Promise<ITextEditor | null | undefined> {
if (resource === undefined) {
return Promise.resolve(undefined);
}
let selection: ITextEditorSelection | undefined;
return this.fileService.readFile(resource).then(content => content.value).then(async content => {
if (!content) {
return undefined;
}
if (task) {
const contentValue = content.toString();
let stringValue: string;
if (typeof task === 'string') {
stringValue = task;
} else {
const model = (await this.textModelResolverService.createModelReference(resource)).object.textEditorModel;
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
const edits = format(JSON.stringify(task), undefined, { eol, tabSize, insertSpaces });
let stringified = applyEdits(JSON.stringify(task), edits);
const regex = new RegExp(eol + '\\t', 'g');
stringified = stringified.replace(regex, eol + '\t\t\t');
const twoTabs = '\t\t';
stringValue = twoTabs + stringified.slice(0, stringified.length - 1) + twoTabs + stringified.slice(stringified.length - 1);
}
const index = contentValue.indexOf(stringValue);
let startLineNumber = 1;
for (let i = 0; i < index; i++) {
if (contentValue.charAt(i) === '\n') {
startLineNumber++;
}
}
let endLineNumber = startLineNumber;
for (let i = 0; i < stringValue.length; i++) {
if (stringValue.charAt(i) === '\n') {
endLineNumber++;
}
}
selection = startLineNumber > 1 ? { startLineNumber, startColumn: startLineNumber === endLineNumber ? 4 : 3, endLineNumber, endColumn: startLineNumber === endLineNumber ? undefined : 4 } : undefined;
}
return this.editorService.openEditor({
resource,
options: {
pinned: false,
forceReload: true, // because content might have changed
selection,
revealInCenterIfOutsideViewport: !!selection
}
});
});
}
public customize(task: ContributedTask | CustomTask, properties?: CustomizationProperties, openConfig?: boolean): Promise<void> {
const workspaceFolder = task.getWorkspaceFolder();
if (!workspaceFolder) {
......@@ -867,14 +927,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
*/
this.telemetryService.publicLog(AbstractTaskService.CustomizationTelemetryEventName, event);
if (openConfig) {
let resource = workspaceFolder.toResource('.vscode/tasks.json');
this.editorService.openEditor({
resource,
options: {
pinned: false,
forceReload: true // because content might have changed
}
});
this.openEditorAtTask(workspaceFolder.toResource('.vscode/tasks.json'), toCustomize);
}
});
}
......@@ -896,12 +949,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
} else {
resource = (this._workspaceFolders && (this._workspaceFolders.length > 0)) ? this._workspaceFolders[0].toResource('.vscode/tasks.json') : undefined;
}
return this.editorService.openEditor({
resource,
options: {
pinned: false
}
}).then(() => undefined);
return this.openEditorAtTask(resource, task ? task._label : undefined).then(() => undefined);
}
private createRunnableTask(tasks: TaskMap, group: TaskGroup): { task: Task; resolver: ITaskResolver } | undefined {
......
......@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import * as Objects from 'vs/base/common/objects';
import * as Strings from 'vs/base/common/strings';
import * as Assert from 'vs/base/common/assert';
import { join } from 'vs/base/common/path';
import { join, normalize } from 'vs/base/common/path';
import * as Types from 'vs/base/common/types';
import * as UUID from 'vs/base/common/uuid';
import * as Platform from 'vs/base/common/platform';
......@@ -220,6 +220,7 @@ export async function getResource(filename: string, matcher: ProblemMatcher, fil
if (fullPath[0] !== '/') {
fullPath = '/' + fullPath;
}
fullPath = normalize(fullPath);
if (matcher.uriProvider !== undefined) {
return matcher.uriProvider(fullPath);
} else {
......
......@@ -111,15 +111,10 @@ export class BackupFileService implements IBackupFileService {
private impl: IBackupFileService;
constructor(
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IFileService fileService: IFileService
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
@IFileService protected fileService: IFileService
) {
const backupWorkspaceResource = environmentService.configuration.backupWorkspaceResource;
if (backupWorkspaceResource) {
this.impl = new BackupFileServiceImpl(backupWorkspaceResource, this.hashPath, fileService);
} else {
this.impl = new InMemoryBackupFileService(this.hashPath);
}
this.initialize();
}
protected hashPath(resource: URI): string {
......@@ -128,9 +123,25 @@ export class BackupFileService implements IBackupFileService {
return hash(str).toString(16);
}
initialize(backupWorkspaceResource: URI): void {
private initialize(): void {
const backupWorkspaceResource = this.environmentService.configuration.backupWorkspaceResource;
if (backupWorkspaceResource) {
this.impl = new BackupFileServiceImpl(backupWorkspaceResource, this.hashPath, this.fileService);
} else {
this.impl = new InMemoryBackupFileService(this.hashPath);
}
}
reinitialize(): void {
// Re-init implementation (unless we are running in-memory)
if (this.impl instanceof BackupFileServiceImpl) {
this.impl.initialize(backupWorkspaceResource);
const backupWorkspaceResource = this.environmentService.configuration.backupWorkspaceResource;
if (backupWorkspaceResource) {
this.impl.initialize(backupWorkspaceResource);
} else {
this.impl = new InMemoryBackupFileService(this.hashPath);
}
}
}
......@@ -323,7 +334,7 @@ class BackupFileServiceImpl implements IBackupFileService {
return contents.substr(0, newLineIndex);
}
throw new Error(`Could not find ${JSON.stringify(matchingString)} in first ${maximumBytesToRead} bytes of ${file}`);
throw new Error(`Backup: Could not find ${JSON.stringify(matchingString)} in first ${maximumBytesToRead} bytes of ${file}`);
}
async resolveBackupContent<T extends object>(backup: URI): Promise<IResolvedBackup<T>> {
......@@ -357,9 +368,7 @@ class BackupFileServiceImpl implements IBackupFileService {
const content = await this.fileService.readFileStream(backup);
const factory = await createTextBufferFactoryFromStream(content.value, metaPreambleFilter);
// Trigger read for meta data extraction from the filter above
factory.getFirstLineText(1);
// Extract meta data (if any)
let meta: T | undefined;
const metaStartIndex = metaRaw.indexOf(BackupFileServiceImpl.PREAMBLE_META_SEPARATOR);
if (metaStartIndex !== -1) {
......@@ -370,6 +379,15 @@ class BackupFileServiceImpl implements IBackupFileService {
}
}
// We have seen reports (e.g. https://github.com/microsoft/vscode/issues/78500) where
// if VSCode goes down while writing the backup file, the file can turn empty because
// it always first gets truncated and then written to. In this case, we will not find
// the meta-end marker ('\n') and as such the backup can only be invalid. We bail out
// here if that is the case.
if (!metaEndFound) {
throw new Error(`Backup: Could not find meta end marker in ${backup}. The file is probably corrupt.`);
}
return { value: factory, meta };
}
......
......@@ -27,6 +27,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { hashPath, BackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
import { BACKUPS } from 'vs/platform/environment/common/environment';
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
import { VSBuffer } from 'vs/base/common/buffer';
const userdataDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
const appSettingsHome = path.join(userdataDir, 'User');
......@@ -479,6 +480,28 @@ suite('BackupFileService', () => {
await testResolveBackup(fooBarFile, contents, meta, null);
});
test('should throw an error when restoring invalid backup', async () => {
const contents = 'test\nand more stuff';
await service.backupResource(fooBarFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false), 1);
const backup = await service.loadBackupResource(fooBarFile);
if (!backup) {
throw new Error('Unexpected missing backup');
}
await service.fileService.writeFile(backup, VSBuffer.fromString(''));
let err: Error;
try {
await service.resolveBackupContent<IBackupTestMetaData>(backup);
} catch (error) {
err = error;
}
assert.ok(err!);
});
async function testResolveBackup(resource: URI, contents: string, meta?: IBackupTestMetaData, expectedMeta?: IBackupTestMetaData | null) {
if (typeof expectedMeta === 'undefined') {
expectedMeta = meta;
......
......@@ -133,7 +133,7 @@ export class ConfigurationEditingService {
public _serviceBrand: any;
private queue: Queue<void>;
private remoteSettingsResource: URI | null;
private remoteSettingsResource: URI | null = null;
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService,
......
......@@ -170,14 +170,10 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys()));
}
public startExtensionHost(): void {
protected startExtensionHost(): void {
this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys()));
}
public stopExtensionHost(): void {
this._stopExtensionHostProcess();
}
public activateByEvent(activationEvent: string): Promise<void> {
if (this._installedExtensionsReady.isOpen()) {
// Extensions have been scanned and interpreted
......
......@@ -219,16 +219,6 @@ export interface IExtensionService {
*/
restartExtensionHost(): void;
/**
* Starts the extension host.
*/
startExtensionHost(): void;
/**
* Stops the extension host.
*/
stopExtensionHost(): void;
/**
* Modify the environment of the remote extension host
* @param env New properties for the remote extension host
......@@ -282,8 +272,6 @@ export class NullExtensionService implements IExtensionService {
getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { return Object.create(null); }
getInspectPort(): number { return 0; }
restartExtensionHost(): void { }
startExtensionHost(): void { }
stopExtensionHost(): void { }
async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> { }
canAddExtension(): boolean { return false; }
canRemoveExtension(): boolean { return false; }
......
......@@ -5,7 +5,7 @@
import * as nativeWatchdog from 'native-watchdog';
import * as net from 'net';
import * as minimist from 'minimist';
import * as minimist from 'vscode-minimist';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Event, Emitter } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
......
......@@ -213,7 +213,7 @@ export class OutputChannelModelService extends AsbtractOutputChannelModelService
this.instantiationService.createInstance(DelegatedOutputChannelModel, id, modelUri, mimeType, this.outputDir);
}
private _outputDir: Promise<URI> | null;
private _outputDir: Promise<URI> | null = null;
private get outputDir(): Promise<URI> {
if (!this._outputDir) {
const outputDir = URI.file(join(this.environmentService.logsPath, `output_${this.environmentService.configuration.windowId}_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`));
......
......@@ -21,9 +21,11 @@ import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFil
import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export class SearchService extends Disposable implements ISearchService {
_serviceBrand: any;
_serviceBrand!: ServiceIdentifier<any>;
protected diskSearch: ISearchResultProvider;
private readonly fileSearchProviders = new Map<string, ISearchResultProvider>();
......
......@@ -308,7 +308,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
try {
return await this.loadFromBackup(backup, options);
} catch (error) {
// ignore error and continue to load as file below
this.logService.error(error); // ignore error and continue to load as file below
}
}
}
......
......@@ -220,6 +220,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
private async doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): Promise<void> {
const state = this.contextService.getWorkbenchState();
if (this.environmentService.configuration.remoteAuthority) {
// Do not allow workspace folders with scheme different than the current remote scheme
const schemas = this.contextService.getWorkspace().folders.map(f => f.uri.scheme);
if (schemas.length && foldersToAdd.some(f => schemas.indexOf(f.uri.scheme) === -1)) {
......@@ -286,6 +287,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
if (path && !await this.isValidTargetWorkspacePath(path)) {
return;
}
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
const untitledWorkspace = await this.workspaceService.createUntitledWorkspace(folders, remoteAuthority);
if (path) {
......@@ -293,6 +295,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
} else {
path = untitledWorkspace.configPath;
}
return this.enterWorkspace(path);
}
......@@ -300,17 +303,18 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
if (!await this.isValidTargetWorkspacePath(path)) {
return;
}
const workspaceIdentifier = this.getCurrentWorkspaceIdentifier();
if (!workspaceIdentifier) {
return;
}
await this.saveWorkspaceAs(workspaceIdentifier, path);
return this.enterWorkspace(path);
}
async isValidTargetWorkspacePath(path: URI): Promise<boolean> {
const windows = await this.windowsService.getWindows();
// Prevent overwriting a workspace that is currently opened in another window
......@@ -382,30 +386,38 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
const workspace = await this.workspaceService.getWorkspaceIdentifier(path);
// Settings migration (only if we come from a folder workspace)
if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) {
await this.migrateWorkspaceSettings(workspace);
}
const workspaceImpl = this.contextService as WorkspaceService;
await workspaceImpl.initialize(workspace);
// Restart extension host if first root folder changed (impact on deprecated workspace.rootPath API)
// Stop the extension host first to give extensions most time to shutdown
this.extensionService.stopExtensionHost();
const result = await this.windowService.enterWorkspace(path);
if (result) {
// Migrate storage to new workspace
await this.migrateStorage(result.workspace);
// Reinitialize backup service
this.environmentService.configuration.backupPath = result.backupPath;
this.environmentService.configuration.backupWorkspaceResource = result.backupPath ? toBackupWorkspaceResource(result.backupPath, this.environmentService) : undefined;
if (this.backupFileService instanceof BackupFileService) {
this.backupFileService.initialize(toBackupWorkspaceResource(result.backupPath!, this.environmentService));
this.backupFileService.reinitialize();
}
}
// TODO@aeschli: workaround until restarting works
if (this.environmentService.configuration.remoteAuthority) {
this.windowService.reloadWindow(); // TODO aeschli: workaround until restarting works
} else {
this.extensionService.startExtensionHost();
this.windowService.reloadWindow();
}
// Restart the extension host: entering a workspace means a new location for
// storage and potentially a change in the workspace.rootPath property.
else {
this.extensionService.restartExtensionHost();
}
}
......
......@@ -103,7 +103,7 @@ suite('Notifications', () => {
// Error with Action
let item6 = NotificationViewItem.create({ severity: Severity.Error, message: createErrorWithActions('Hello Error', { actions: [new Action('id', 'label')] }) })!;
assert.equal(item6.actions.primary!.length, 1);
assert.equal(item6.actions!.primary!.length, 1);
// Links
let item7 = NotificationViewItem.create({ severity: Severity.Info, message: 'Unable to [Link 1](http://link1.com) open [Link 2](command:open.me "Open This") and [Link 3](command:without.title) and [Invalid Link4](ftp://link4.com)' })!;
......@@ -219,4 +219,4 @@ suite('Notifications', () => {
disposable3.dispose();
assert.ok(!model.statusMessage);
});
});
\ No newline at end of file
});
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as minimist from 'minimist';
import * as minimist from 'vscode-minimist';
import * as path from 'vs/base/common/path';
import { CancellationToken } from 'vs/base/common/cancellation';
import { URI } from 'vs/base/common/uri';
......
......@@ -13,7 +13,7 @@ import { ISearchService } from 'vs/workbench/services/search/common/search';
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as minimist from 'minimist';
import * as minimist from 'vscode-minimist';
import * as path from 'vs/base/common/path';
import { LocalSearchService } from 'vs/workbench/services/search/node/searchService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
......
......@@ -112,11 +112,6 @@
resolved "https://registry.yarnpkg.com/@types/keytar/-/keytar-4.4.0.tgz#ca24e6ee6d0df10c003aafe26e93113b8faf0d8e"
integrity sha512-cq/NkUUy6rpWD8n7PweNQQBpw2o0cf5v6fbkUVEpOB9VzzIvyPvSEId1/goIj+MciW2v1Lw5mRimKO01XgE9EA==
"@types/minimist@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
"@types/mocha@2.2.39":
version "2.2.39"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.39.tgz#f68d63db8b69c38e9558b4073525cf96c4f7a829"
......@@ -9546,6 +9541,11 @@ vscode-fsevents@1.2.12:
dependencies:
nan "^2.14.0"
vscode-minimist@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a"
integrity sha512-cmB72+qDoiCFJ1UKnGUBdGYfXzdpJ3bQM/D/+XhkVk5v7uZgLbYiCz5JcwVyk7NC7hSi5VGtQ4wihzmi12NeXw==
vscode-nls-dev@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.3.1.tgz#15fc03e0c9ca5a150abb838690d9554ac06f77e4"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册