mirror of
https://github.com/Microsoft/vscode
synced 2024-10-13 14:57:14 +00:00
Merge remote-tracking branch 'origin/master' into tyriar/xterm-update
This commit is contained in:
commit
86f3cb92d8
|
@ -60,6 +60,18 @@ interface PreviewStyleLoadErrorMessage extends WebviewMessage {
|
|||
};
|
||||
}
|
||||
|
||||
export class PreviewDocumentVersion {
|
||||
public constructor(
|
||||
public readonly resource: vscode.Uri,
|
||||
public readonly version: number,
|
||||
) { }
|
||||
|
||||
public equals(other: PreviewDocumentVersion): boolean {
|
||||
return this.resource.fsPath === other.resource.fsPath
|
||||
&& this.version === other.version;
|
||||
}
|
||||
}
|
||||
|
||||
export class MarkdownPreview extends Disposable {
|
||||
|
||||
public static viewType = 'markdown.preview';
|
||||
|
@ -71,7 +83,7 @@ export class MarkdownPreview extends Disposable {
|
|||
private throttleTimer: any;
|
||||
private line: number | undefined = undefined;
|
||||
private firstUpdate = true;
|
||||
private currentVersion?: { resource: vscode.Uri, version: number };
|
||||
private currentVersion?: PreviewDocumentVersion;
|
||||
private forceUpdate = false;
|
||||
private isScrolling = false;
|
||||
private _disposed: boolean = false;
|
||||
|
@ -389,7 +401,8 @@ export class MarkdownPreview extends Disposable {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.forceUpdate && this.currentVersion && this.currentVersion.resource.fsPath === resource.fsPath && this.currentVersion.version === document.version) {
|
||||
const pendingVersion = new PreviewDocumentVersion(resource, document.version);
|
||||
if (!this.forceUpdate && this.currentVersion && this.currentVersion.equals(pendingVersion)) {
|
||||
if (this.line) {
|
||||
this.updateForView(resource, this.line);
|
||||
}
|
||||
|
@ -397,12 +410,16 @@ export class MarkdownPreview extends Disposable {
|
|||
}
|
||||
this.forceUpdate = false;
|
||||
|
||||
this.currentVersion = { resource, version: document.version };
|
||||
this.currentVersion = pendingVersion;
|
||||
if (this._resource === resource) {
|
||||
const content = await this._contentProvider.provideTextDocumentContent(document, this._previewConfigurations, this.line, this.state);
|
||||
// Another call to `doUpdate` may have happened.
|
||||
// Make sure we are still updating for the correct document
|
||||
if (this.currentVersion && this.currentVersion.equals(pendingVersion)) {
|
||||
this.setContent(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static getWebviewOptions(
|
||||
resource: vscode.Uri,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { snippetForFunctionCall } from "../utils/snippetForFunctionCall";
|
||||
import { snippetForFunctionCall } from '../utils/snippetForFunctionCall';
|
||||
|
||||
suite('typescript function call snippets', () => {
|
||||
test('Should use label as function name', async () => {
|
||||
|
|
|
@ -370,7 +370,7 @@ class InlineImageView {
|
|||
dispose: () => combinedDisposable(disposables).dispose()
|
||||
};
|
||||
|
||||
const cacheKey = descriptor.resource.toString();
|
||||
const cacheKey = `${descriptor.resource.toString()}:${descriptor.etag}`;
|
||||
|
||||
let ctrlPressed = false;
|
||||
let altPressed = false;
|
||||
|
|
|
@ -203,7 +203,7 @@ export class OpenFileHandler extends QuickOpenHandler {
|
|||
const queryOptions: IFileQueryBuilderOptions = {
|
||||
_reason: 'openFileHandler',
|
||||
extraFileResources: getOutOfWorkspaceEditorResources(this.editorService, this.contextService),
|
||||
filePattern: query.value,
|
||||
filePattern: query.original,
|
||||
cacheKey
|
||||
};
|
||||
|
||||
|
|
|
@ -2013,7 +2013,7 @@ class TaskService extends Disposable implements ITaskService {
|
|||
Severity.Info,
|
||||
nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: {0}', this.ignoredWorkspaceFolders.map(f => f.name).join(', ')),
|
||||
[{
|
||||
label: nls.localize('TaskService.notAgain', 'Don\'t Show Again'),
|
||||
label: nls.localize('TaskService.notAgain', "Don't Show Again"),
|
||||
isSecondary: true,
|
||||
run: () => {
|
||||
this.storageService.store(TaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE);
|
||||
|
|
|
@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB
|
|||
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager';
|
||||
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
|
@ -969,19 +969,41 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}
|
||||
|
||||
this._isExiting = true;
|
||||
let exitCodeMessage: string;
|
||||
let exitCodeMessage: string | undefined;
|
||||
|
||||
// Create exit code message
|
||||
if (exitCode) {
|
||||
if (exitCode === SHELL_PATH_INVALID_EXIT_CODE) {
|
||||
exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidPath', 'The terminal shell path does not exist: {0}', this._shellLaunchConfig.executable);
|
||||
} else if (this._processManager && this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) {
|
||||
let args = '';
|
||||
if (typeof this._shellLaunchConfig.args === 'string') {
|
||||
args = ` ${this._shellLaunchConfig.args}`;
|
||||
} else if (this._shellLaunchConfig.args && this._shellLaunchConfig.args.length) {
|
||||
args = ' ' + this._shellLaunchConfig.args.map(a => {
|
||||
if (typeof a === 'string' && a.indexOf(' ') !== -1) {
|
||||
return `'${a}'`;
|
||||
}
|
||||
return a;
|
||||
}).join(' ');
|
||||
}
|
||||
if (this._shellLaunchConfig.executable) {
|
||||
exitCodeMessage = nls.localize('terminal.integrated.launchFailed', 'The terminal process command \'{0}{1}\' failed to launch (exit code: {2})', this._shellLaunchConfig.executable, args, exitCode);
|
||||
} else {
|
||||
exitCodeMessage = nls.localize('terminal.integrated.launchFailedExtHost', 'The terminal process failed to launch (exit code: {0})', exitCode);
|
||||
}
|
||||
} else {
|
||||
exitCodeMessage = nls.localize('terminal.integrated.exitedWithCode', 'The terminal process terminated with exit code: {0}', exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
this._logService.debug(`Terminal process exit (id: ${this.id})${this._processManager ? ' state ' + this._processManager.processState : ''}`);
|
||||
|
||||
// Only trigger wait on exit when the exit was *not* triggered by the
|
||||
// user (via the `workbench.action.terminal.kill` command).
|
||||
if (this._shellLaunchConfig.waitOnExit && (!this._processManager || this._processManager.processState !== ProcessState.KILLED_BY_USER)) {
|
||||
if (exitCode) {
|
||||
this._xterm.writeln(exitCodeMessage!);
|
||||
if (exitCodeMessage) {
|
||||
this._xterm.writeln(exitCodeMessage);
|
||||
}
|
||||
if (typeof this._shellLaunchConfig.waitOnExit === 'string') {
|
||||
let message = this._shellLaunchConfig.waitOnExit;
|
||||
|
@ -996,29 +1018,14 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}
|
||||
} else {
|
||||
this.dispose();
|
||||
if (exitCode) {
|
||||
if (exitCodeMessage) {
|
||||
if (this._processManager && this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) {
|
||||
let args = '';
|
||||
if (typeof this._shellLaunchConfig.args === 'string') {
|
||||
args = this._shellLaunchConfig.args;
|
||||
} else if (this._shellLaunchConfig.args && this._shellLaunchConfig.args.length) {
|
||||
args = ' ' + this._shellLaunchConfig.args.map(a => {
|
||||
if (typeof a === 'string' && a.indexOf(' ') !== -1) {
|
||||
return `'${a}'`;
|
||||
}
|
||||
return a;
|
||||
}).join(' ');
|
||||
}
|
||||
if (this._shellLaunchConfig.executable) {
|
||||
this._notificationService.error(nls.localize('terminal.integrated.launchFailed', 'The terminal process command \'{0}{1}\' failed to launch (exit code: {2})', this._shellLaunchConfig.executable, args, exitCode));
|
||||
} else {
|
||||
this._notificationService.error(nls.localize('terminal.integrated.launchFailedExtHost', 'The terminal process failed to launch (exit code: {0})', exitCode));
|
||||
}
|
||||
this._notificationService.error(exitCodeMessage);
|
||||
} else {
|
||||
if (this._configHelper.config.showExitAlert) {
|
||||
this._notificationService.error(exitCodeMessage!);
|
||||
this._notificationService.error(exitCodeMessage);
|
||||
} else {
|
||||
console.warn(exitCodeMessage!);
|
||||
console.warn(exitCodeMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ export const TERMINAL_CONFIG_SECTION = 'terminal.integrated';
|
|||
export const DEFAULT_LETTER_SPACING = 0;
|
||||
export const MINIMUM_LETTER_SPACING = -5;
|
||||
export const DEFAULT_LINE_HEIGHT = 1;
|
||||
export const SHELL_PATH_INVALID_EXIT_CODE = -1;
|
||||
|
||||
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
|
||||
|
||||
|
@ -695,7 +696,6 @@ export const enum ProcessState {
|
|||
KILLED_BY_PROCESS
|
||||
}
|
||||
|
||||
|
||||
export interface ITerminalProcessExtHostProxy extends IDisposable {
|
||||
readonly terminalId: number;
|
||||
|
||||
|
|
|
@ -11,13 +11,13 @@ import * as fs from 'fs';
|
|||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalChildProcess, SHELL_PATH_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
||||
private _exitCode: number;
|
||||
private _closeTimeout: any;
|
||||
private _ptyProcess: pty.IPty;
|
||||
private _ptyProcess: pty.IPty | undefined;
|
||||
private _currentTitle: string = '';
|
||||
private _processStartupComplete: Promise<void>;
|
||||
private _isDisposed: boolean = false;
|
||||
|
@ -69,37 +69,39 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
experimentalUseConpty: useConpty
|
||||
};
|
||||
|
||||
try {
|
||||
this._ptyProcess = pty.spawn(shellLaunchConfig.executable!, shellLaunchConfig.args || [], options);
|
||||
this._processStartupComplete = new Promise<void>(c => {
|
||||
this.onProcessIdReady((pid) => {
|
||||
c();
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
// The only time this is expected to happen is when the file specified to launch with does not exist.
|
||||
this._exitCode = 2;
|
||||
fs.stat(shellLaunchConfig.executable!, (err) => {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
this._exitCode = SHELL_PATH_INVALID_EXIT_CODE;
|
||||
this._queueProcessExit();
|
||||
this._processStartupComplete = Promise.resolve(undefined);
|
||||
return;
|
||||
}
|
||||
this._ptyProcess.on('data', (data) => {
|
||||
this.setupPtyProcess(shellLaunchConfig, options);
|
||||
});
|
||||
}
|
||||
|
||||
private setupPtyProcess(shellLaunchConfig: IShellLaunchConfig, options: pty.IPtyForkOptions): void {
|
||||
const ptyProcess = pty.spawn(shellLaunchConfig.executable!, shellLaunchConfig.args || [], options);
|
||||
this._ptyProcess = ptyProcess;
|
||||
this._processStartupComplete = new Promise<void>(c => {
|
||||
this.onProcessIdReady(() => c());
|
||||
});
|
||||
ptyProcess.on('data', (data) => {
|
||||
this._onProcessData.fire(data);
|
||||
if (this._closeTimeout) {
|
||||
clearTimeout(this._closeTimeout);
|
||||
this._queueProcessExit();
|
||||
}
|
||||
});
|
||||
this._ptyProcess.on('exit', (code) => {
|
||||
ptyProcess.on('exit', (code) => {
|
||||
this._exitCode = code;
|
||||
this._queueProcessExit();
|
||||
});
|
||||
|
||||
this._setupTitlePolling(ptyProcess);
|
||||
// TODO: We should no longer need to delay this since pty.spawn is sync
|
||||
setTimeout(() => {
|
||||
this._sendProcessId();
|
||||
this._sendProcessId(ptyProcess);
|
||||
}, 500);
|
||||
this._setupTitlePolling();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
@ -114,15 +116,15 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
this._onProcessTitleChanged.dispose();
|
||||
}
|
||||
|
||||
private _setupTitlePolling() {
|
||||
private _setupTitlePolling(ptyProcess: pty.IPty) {
|
||||
// Send initial timeout async to give event listeners a chance to init
|
||||
setTimeout(() => {
|
||||
this._sendProcessTitle();
|
||||
this._sendProcessTitle(ptyProcess);
|
||||
}, 0);
|
||||
// Setup polling
|
||||
this._titleInterval = setInterval(() => {
|
||||
if (this._currentTitle !== this._ptyProcess.process) {
|
||||
this._sendProcessTitle();
|
||||
if (this._currentTitle !== ptyProcess.process) {
|
||||
this._sendProcessTitle(ptyProcess);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
@ -146,7 +148,9 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
// Attempt to kill the pty, it may have already been killed at this
|
||||
// point but we want to make sure
|
||||
try {
|
||||
if (this._ptyProcess) {
|
||||
this._ptyProcess.kill();
|
||||
}
|
||||
} catch (ex) {
|
||||
// Swallow, the pty has already been killed
|
||||
}
|
||||
|
@ -155,15 +159,15 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
});
|
||||
}
|
||||
|
||||
private _sendProcessId() {
|
||||
this._onProcessIdReady.fire(this._ptyProcess.pid);
|
||||
private _sendProcessId(ptyProcess: pty.IPty) {
|
||||
this._onProcessIdReady.fire(ptyProcess.pid);
|
||||
}
|
||||
|
||||
private _sendProcessTitle(): void {
|
||||
private _sendProcessTitle(ptyProcess: pty.IPty): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
this._currentTitle = this._ptyProcess.process;
|
||||
this._currentTitle = ptyProcess.process;
|
||||
this._onProcessTitleChanged.fire(this._currentTitle);
|
||||
}
|
||||
|
||||
|
@ -176,7 +180,7 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
}
|
||||
|
||||
public input(data: string): void {
|
||||
if (this._isDisposed) {
|
||||
if (this._isDisposed || !this._ptyProcess) {
|
||||
return;
|
||||
}
|
||||
this._ptyProcess.write(data);
|
||||
|
@ -188,8 +192,10 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
}
|
||||
// Ensure that cols and rows are always >= 1, this prevents a native
|
||||
// exception in winpty.
|
||||
if (this._ptyProcess) {
|
||||
this._ptyProcess.resize(Math.max(cols, 1), Math.max(rows, 1));
|
||||
}
|
||||
}
|
||||
|
||||
public getInitialCwd(): Promise<string> {
|
||||
return Promise.resolve(this._initialCwd);
|
||||
|
@ -198,6 +204,10 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
public getCwd(): Promise<string> {
|
||||
if (platform.isMacintosh) {
|
||||
return new Promise<string>(resolve => {
|
||||
if (!this._ptyProcess) {
|
||||
resolve(this._initialCwd);
|
||||
return;
|
||||
}
|
||||
exec('lsof -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => {
|
||||
if (stdout !== '') {
|
||||
resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1));
|
||||
|
@ -208,6 +218,10 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
|||
|
||||
if (platform.isLinux) {
|
||||
return new Promise<string>(resolve => {
|
||||
if (!this._ptyProcess) {
|
||||
resolve(this._initialCwd);
|
||||
return;
|
||||
}
|
||||
fs.readlink('/proc/' + this._ptyProcess.pid + '/cwd', (err, linkedstr) => {
|
||||
if (err) {
|
||||
resolve(this._initialCwd);
|
||||
|
|
|
@ -22,6 +22,7 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { readdir } from 'vs/base/node/pfs';
|
||||
import { IFileQuery, IFolderQuery, IProgressMessage, ISearchEngineStats, IRawFileMatch, ISearchEngine, ISearchEngineSuccess } from 'vs/workbench/services/search/common/search';
|
||||
import { spawnRipgrepCmd } from './ripgrepFileSearch';
|
||||
import { prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer';
|
||||
|
||||
interface IDirectoryEntry {
|
||||
base: string;
|
||||
|
@ -76,7 +77,7 @@ export class FileWalker {
|
|||
this.errors = [];
|
||||
|
||||
if (this.filePattern) {
|
||||
this.normalizedFilePatternLowercase = strings.stripWildcards(this.filePattern).toLowerCase();
|
||||
this.normalizedFilePatternLowercase = prepareQuery(this.filePattern).value;
|
||||
}
|
||||
|
||||
this.globalExcludePattern = config.excludePattern && glob.parse(config.excludePattern);
|
||||
|
|
|
@ -312,7 +312,7 @@ export class SearchService implements IRawSearchService {
|
|||
|
||||
// Pattern match on results
|
||||
const results: IRawFileMatch[] = [];
|
||||
const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase();
|
||||
const normalizedSearchValueLowercase = prepareQuery(searchValue).value;
|
||||
for (const entry of cachedEntries) {
|
||||
|
||||
// Check if this entry is a match for the search value
|
||||
|
|
|
@ -290,25 +290,25 @@ suite('FileSearchEngine', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('Files: NPE (CamelCase)', function (done: () => void) {
|
||||
this.timeout(testTimeout);
|
||||
const engine = new FileSearchEngine({
|
||||
type: QueryType.File,
|
||||
folderQueries: ROOT_FOLDER_QUERY,
|
||||
filePattern: 'NullPE'
|
||||
});
|
||||
// test('Files: NPE (CamelCase)', function (done: () => void) {
|
||||
// this.timeout(testTimeout);
|
||||
// const engine = new FileSearchEngine({
|
||||
// type: QueryType.File,
|
||||
// folderQueries: ROOT_FOLDER_QUERY,
|
||||
// filePattern: 'NullPE'
|
||||
// });
|
||||
|
||||
let count = 0;
|
||||
engine.search((result) => {
|
||||
if (result) {
|
||||
count++;
|
||||
}
|
||||
}, () => { }, (error) => {
|
||||
assert.ok(!error);
|
||||
assert.equal(count, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
// let count = 0;
|
||||
// engine.search((result) => {
|
||||
// if (result) {
|
||||
// count++;
|
||||
// }
|
||||
// }, () => { }, (error) => {
|
||||
// assert.ok(!error);
|
||||
// assert.equal(count, 1);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
test('Files: *.*', function (done: () => void) {
|
||||
this.timeout(testTimeout);
|
||||
|
|
Loading…
Reference in a new issue