From 5b8482eb3ec550ddef80dc3c61ca046d73f124fc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 12 Mar 2019 12:21:09 +0100 Subject: [PATCH] - use buffered output channel service for nodeless --- src/vs/base/common/hash.ts | 100 +--------------- src/vs/base/common/uint.ts | 108 ++++++++++++++++++ .../browser/nodeless.simpleservices.ts | 2 +- .../contrib/output/browser/outputActions.ts | 43 ++++--- .../contrib/output/browser/outputServices.ts | 2 +- .../output/common/outputChannelModel.ts | 14 ++- src/vs/workbench/workbench.nodeless.main.ts | 2 +- 7 files changed, 145 insertions(+), 126 deletions(-) create mode 100644 src/vs/base/common/uint.ts diff --git a/src/vs/base/common/hash.ts b/src/vs/base/common/hash.ts index a4bad6fe5a2..85c79a04b1b 100644 --- a/src/vs/base/common/hash.ts +++ b/src/vs/base/common/hash.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { isString } from 'vs/base/common/types'; +import { toUint8ArrayBuffer } from 'vs/base/common/uint'; /** * Return a hash value for an object. @@ -76,7 +77,7 @@ export class Hasher { //#region SHA1 export function computeSHA1Hash(value: string): string { - const data = encodeToArrayBuffer(value); + const data = toUint8ArrayBuffer(value); const hash = new SHA1(); if (data.byteLength) { @@ -137,7 +138,7 @@ class SHA1 { let data: Uint8Array; if (isString(arg)) { - data = new Uint8Array(encodeToArrayBuffer(arg)); + data = new Uint8Array(toUint8ArrayBuffer(arg)); } else if (arg instanceof ArrayBuffer) { data = new Uint8Array(arg); } else if (arg instanceof DataView) { @@ -301,101 +302,6 @@ function multiply64(a: number, b: number): number[] { return [(c3 << 16 | c2) >>> 0, (c1 << 16 | c0) >>> 0]; } -function encodeToArrayBuffer(str: string): ArrayBuffer { - let i: number, len: number, length = 0, charCode = 0, trailCharCode = 0, codepoint = 0; - - // First pass, for the size - for (i = 0, len = str.length; i < len; i++) { - charCode = str.charCodeAt(i); - - // Surrogate pair - if (charCode >= 0xD800 && charCode < 0xDC00) { - trailCharCode = str.charCodeAt(++i); - - if (!(trailCharCode >= 0xDC00 && trailCharCode < 0xE000)) { - throw new Error('Invalid char code'); - } - - // Code point can be obtained by subtracting 0xD800 and 0xDC00 from both char codes respectively - // and joining the 10 least significant bits from each, finally adding 0x10000. - codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000; - - } else { - codepoint = charCode; - } - - length += byteSizeInUTF8(codepoint); - } - - let result = new ArrayBuffer(length); - let view = new Uint8Array(result); - let pos = 0; - - // Second pass, for the data - for (i = 0, len = str.length; i < len; i++) { - charCode = str.charCodeAt(i); - - if (charCode >= 0xD800 && charCode < 0xDC00) { - trailCharCode = str.charCodeAt(++i); - codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000; - } else { - codepoint = charCode; - } - - pos += writeUTF8(codepoint, view, pos); - } - - return result; -} - -function byteSizeInUTF8(codePoint: number): number { - codePoint = codePoint >>> 0; - - if (codePoint < 0x80) { - return 1; - } else if (codePoint < 0x800) { - return 2; - } else if (codePoint < 0x10000) { - return 3; - } else if (codePoint < 0x200000) { - return 4; - } else if (codePoint < 0x4000000) { - return 5; - } else if (codePoint < 0x80000000) { - return 6; - } else { - throw new Error('Code point 0x' + toHexString(codePoint) + ' not encodable in UTF8.'); - } -} - -function writeUTF8(codePoint: number, buffer: Uint8Array, pos: number): number { - - // How many bits needed for codePoint - let byteSize = byteSizeInUTF8(codePoint); - - // 0xxxxxxx - if (byteSize === 1) { - buffer[pos] = codePoint; - return 1; - } - - // 110xxxxx 10xxxxxx - // 1110xxxx 10xxxxxx 10xxxxxx - // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - - // first byte - buffer[pos] = ((0xFC << (6 - byteSize)) | (codePoint >>> (6 * (byteSize - 1)))) & 0xFF; - - // successive bytes - for (let i = 1; i < byteSize; i++) { - buffer[pos + i] = (0x80 | (0x3F & (codePoint >>> (6 * (byteSize - i - 1))))) & 0xFF; - } - - return byteSize; -} - function copy(dest: Uint8Array, destIndex: number, src: Uint8Array, srcIndex: number, count: number): number { const len = Math.min(dest.byteLength - destIndex, src.byteLength - srcIndex, count); diff --git a/src/vs/base/common/uint.ts b/src/vs/base/common/uint.ts new file mode 100644 index 00000000000..d01cd6bb382 --- /dev/null +++ b/src/vs/base/common/uint.ts @@ -0,0 +1,108 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export function toUint8ArrayBuffer(str: string): ArrayBuffer { + + let i: number, len: number, length = 0, charCode = 0, trailCharCode = 0, codepoint = 0; + + // First pass, for the size + for (i = 0, len = str.length; i < len; i++) { + charCode = str.charCodeAt(i); + + // Surrogate pair + if (charCode >= 0xD800 && charCode < 0xDC00) { + trailCharCode = str.charCodeAt(++i); + + if (!(trailCharCode >= 0xDC00 && trailCharCode < 0xE000)) { + throw new Error('Invalid char code'); + } + + // Code point can be obtained by subtracting 0xD800 and 0xDC00 from both char codes respectively + // and joining the 10 least significant bits from each, finally adding 0x10000. + codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000; + + } else { + codepoint = charCode; + } + + length += byteSizeInUTF8(codepoint); + } + + let result = new ArrayBuffer(length); + let view = new Uint8Array(result); + let pos = 0; + + // Second pass, for the data + for (i = 0, len = str.length; i < len; i++) { + charCode = str.charCodeAt(i); + + if (charCode >= 0xD800 && charCode < 0xDC00) { + trailCharCode = str.charCodeAt(++i); + codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000; + } else { + codepoint = charCode; + } + + pos += writeUTF8(codepoint, view, pos); + } + + return result; +} + +function byteSizeInUTF8(codePoint: number): number { + codePoint = codePoint >>> 0; + + if (codePoint < 0x80) { + return 1; + } else if (codePoint < 0x800) { + return 2; + } else if (codePoint < 0x10000) { + return 3; + } else if (codePoint < 0x200000) { + return 4; + } else if (codePoint < 0x4000000) { + return 5; + } else if (codePoint < 0x80000000) { + return 6; + } else { + throw new Error('Code point 0x' + toHexString(codePoint) + ' not encodable in UTF8.'); + } +} + +function writeUTF8(codePoint: number, buffer: Uint8Array, pos: number): number { + + // How many bits needed for codePoint + let byteSize = byteSizeInUTF8(codePoint); + + // 0xxxxxxx + if (byteSize === 1) { + buffer[pos] = codePoint; + return 1; + } + + // 110xxxxx 10xxxxxx + // 1110xxxx 10xxxxxx 10xxxxxx + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + // first byte + buffer[pos] = ((0xFC << (6 - byteSize)) | (codePoint >>> (6 * (byteSize - 1)))) & 0xFF; + + // successive bytes + for (let i = 1; i < byteSize; i++) { + buffer[pos + i] = (0x80 | (0x3F & (codePoint >>> (6 * (byteSize - i - 1))))) & 0xFF; + } + + return byteSize; +} + +function leftPad(value: string, length: number, char: string = '0'): string { + return new Array(length - value.length + 1).join(char) + value; +} + +function toHexString(value: number, bitsize: number = 32): string { + return leftPad((value >>> 0).toString(16), bitsize / 4); +} diff --git a/src/vs/workbench/browser/nodeless.simpleservices.ts b/src/vs/workbench/browser/nodeless.simpleservices.ts index 9bc5d5afd2f..ca40a05fe3e 100644 --- a/src/vs/workbench/browser/nodeless.simpleservices.ts +++ b/src/vs/workbench/browser/nodeless.simpleservices.ts @@ -259,7 +259,7 @@ export class SimpleEnvironmentService implements IEnvironmentService { wait: boolean; status: boolean; log?: string; - logsPath: string; + logsPath: string = '/nodeless/logs'; verbose: boolean; skipGettingStarted: boolean; skipReleaseNotes: boolean; diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index e4b4f70de0e..02bf8197c34 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -155,33 +155,30 @@ export class SwitchOutputActionItem extends SelectActionItem { } private updateOtions(): void { + const groups = groupBy(this.outputService.getChannelDescriptors(), (c1: IOutputChannelDescriptor, c2: IOutputChannelDescriptor) => { + if (!c1.log && c2.log) { + return -1; + } + if (c1.log && !c2.log) { + return 1; + } + return 0; + }); + this.outputChannels = groups[0] || []; + this.logChannels = groups[1] || []; + const showSeparator = this.outputChannels.length && this.logChannels.length; + const separatorIndex = showSeparator ? this.outputChannels.length : -1; + const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))]; + let selected = 0; const activeChannel = this.outputService.getActiveChannel(); if (activeChannel) { - const selectedChannel = activeChannel.id; - const groups = groupBy(this.outputService.getChannelDescriptors(), (c1: IOutputChannelDescriptor, c2: IOutputChannelDescriptor) => { - if (!c1.log && c2.log) { - return -1; - } - if (c1.log && !c2.log) { - return 1; - } - return 0; - }); - this.outputChannels = groups[0] || []; - this.logChannels = groups[1] || []; - const showSeparator = this.outputChannels.length && this.logChannels.length; - const separatorIndex = showSeparator ? this.outputChannels.length : -1; - const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))]; - let selected = 0; - if (selectedChannel) { - selected = this.outputChannels.map(c => c.id).indexOf(selectedChannel); - if (selected === -1) { - const logChannelIndex = this.logChannels.map(c => c.id).indexOf(selectedChannel); - selected = logChannelIndex !== -1 ? separatorIndex + 1 + logChannelIndex : 0; - } + selected = this.outputChannels.map(c => c.id).indexOf(activeChannel.id); + if (selected === -1) { + const logChannelIndex = this.logChannels.map(c => c.id).indexOf(activeChannel.id); + selected = logChannelIndex !== -1 ? separatorIndex + 1 + logChannelIndex : 0; } - this.setOptions(options.map((label, index) => { text: label, isDisabled: (index === separatorIndex ? true : undefined) }), Math.max(0, selected)); } + this.setOptions(options.map((label, index) => { text: label, isDisabled: (index === separatorIndex ? true : undefined) }), Math.max(0, selected)); } } diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index 9f545ac8384..15963e4e2e0 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -155,7 +155,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo private onDidRegisterChannel(channelId: string): void { const channel = this.createChannel(channelId); this.channels.set(channelId, channel); - if (this.activeChannelIdInStorage === channelId) { + if (!this.activeChannel || this.activeChannelIdInStorage === channelId) { this.activeChannel = channel; this.onDidPanelOpen(this.panelService.getActivePanel(), true) .then(() => this._onActiveOutputChannel.fire(channelId)); diff --git a/src/vs/workbench/services/output/common/outputChannelModel.ts b/src/vs/workbench/services/output/common/outputChannelModel.ts index 79b5496c55c..c053d1fd0aa 100644 --- a/src/vs/workbench/services/output/common/outputChannelModel.ts +++ b/src/vs/workbench/services/output/common/outputChannelModel.ts @@ -17,6 +17,7 @@ import { isNumber } from 'vs/base/common/types'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { binarySearch } from 'vs/base/common/arrays'; +import { toUint8ArrayBuffer } from 'vs/base/common/uint'; export interface IOutputChannelModel extends IDisposable { readonly onDidAppendedContent: Event; @@ -184,7 +185,7 @@ class OutputFileListener extends Disposable { /** * An output channel driven by a file and does not support appending messages. */ -export class FileOutputChannelModel extends AbstractFileOutputChannelModel implements IOutputChannelModel { +class FileOutputChannelModel extends AbstractFileOutputChannelModel implements IOutputChannelModel { private readonly fileHandler: OutputFileListener; @@ -210,7 +211,7 @@ export class FileOutputChannelModel extends AbstractFileOutputChannelModel imple loadModel(): Promise { this.loadModelPromise = this.fileService.resolveContent(this.file, { position: this.startOffset, encoding: 'utf8' }) .then(content => { - this.endOffset = this.startOffset + Buffer.from(content.value).byteLength; + this.endOffset = this.startOffset + this.getByteLength(content.value); this.etag = content.etag; return this.createModel(content.value); }); @@ -235,7 +236,7 @@ export class FileOutputChannelModel extends AbstractFileOutputChannelModel imple .then(content => { this.etag = content.etag; if (content.value) { - this.endOffset = this.endOffset + Buffer.from(content.value).byteLength; + this.endOffset = this.endOffset + this.getByteLength(content.value); this.appendToModel(content.value); } this.updateInProgress = false; @@ -257,6 +258,13 @@ export class FileOutputChannelModel extends AbstractFileOutputChannelModel imple this.updateInProgress = false; } + protected getByteLength(str: string): number { + if (typeof Buffer !== undefined) { + return Buffer.from(str).byteLength; + } + return toUint8ArrayBuffer(str).byteLength; + } + update(size?: number): void { if (this.model) { if (!this.updateInProgress) { diff --git a/src/vs/workbench/workbench.nodeless.main.ts b/src/vs/workbench/workbench.nodeless.main.ts index 7b4f28c2a9f..b1f93878f58 100644 --- a/src/vs/workbench/workbench.nodeless.main.ts +++ b/src/vs/workbench/workbench.nodeless.main.ts @@ -110,7 +110,7 @@ import 'vs/workbench/services/progress/browser/progressService2'; import 'vs/workbench/services/editor/browser/codeEditorService'; // import 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import 'vs/workbench/services/preferences/browser/preferencesService'; -// import 'vs/workbench/services/output/node/outputChannelModelService'; +import 'vs/workbench/services/output/common/outputChannelModelService'; // import 'vs/workbench/services/configuration/node/jsonEditingService'; import 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import 'vs/workbench/services/textfile/common/textFileService'; -- GitLab