diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 42fc0969568..522986d937a 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1869,32 +1869,6 @@ export function safeInnerHtml(node: HTMLElement, value: string, extraDomPurifyCo } } -/** - * Convert a Unicode string to a string in which each 16-bit unit occupies only one byte - * - * From https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa - */ -function toBinary(str: string): string { - const codeUnits = new Uint16Array(str.length); - for (let i = 0; i < codeUnits.length; i++) { - codeUnits[i] = str.charCodeAt(i); - } - let binary = ''; - const uint8array = new Uint8Array(codeUnits.buffer); - for (let i = 0; i < uint8array.length; i++) { - binary += String.fromCharCode(uint8array[i]); - } - return binary; -} - -/** - * Version of the global `btoa` function that handles multi-byte characters instead - * of throwing an exception. - */ -export function multibyteAwareBtoa(str: string): string { - return btoa(toBinary(str)); -} - type ModifierKey = 'alt' | 'ctrl' | 'shift' | 'meta'; export interface IModifierKeyStatus { diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 5d4d135ca89..58f94f52efc 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -1361,3 +1361,30 @@ export class InvisibleCharacters { } export const Ellipsis = '\u2026'; + +/** + * Convert a Unicode string to a string in which each 16-bit unit occupies only one byte + * + * From https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa + */ +function toBinary(str: string): string { + const codeUnits = new Uint16Array(str.length); + for (let i = 0; i < codeUnits.length; i++) { + codeUnits[i] = str.charCodeAt(i); + } + let binary = ''; + const uint8array = new Uint8Array(codeUnits.buffer); + for (let i = 0; i < uint8array.length; i++) { + binary += String.fromCharCode(uint8array[i]); + } + return binary; +} + +/** + * Version of the global `btoa` function that handles multi-byte characters instead + * of throwing an exception. + */ + +export function multibyteAwareBtoa(str: string): string { + return btoa(toBinary(str)); +} diff --git a/src/vs/base/test/browser/dom.test.ts b/src/vs/base/test/browser/dom.test.ts index 92aed203498..345efd026e8 100644 --- a/src/vs/base/test/browser/dom.test.ts +++ b/src/vs/base/test/browser/dom.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { $, h, multibyteAwareBtoa, trackAttributes, copyAttributes, disposableWindowInterval, getWindows, getWindowsCount, getWindowId, getWindowById, hasWindow, getWindow, getDocument, isHTMLElement, SafeTriangle } from '../../browser/dom.js'; +import { $, h, trackAttributes, copyAttributes, disposableWindowInterval, getWindows, getWindowsCount, getWindowId, getWindowById, hasWindow, getWindow, getDocument, isHTMLElement, SafeTriangle } from '../../browser/dom.js'; import { asCssValueWithDefault } from '../../../base/browser/cssValue.js'; import { ensureCodeWindow, isAuxiliaryWindow, mainWindow } from '../../browser/window.js'; import { DeferredPromise, timeout } from '../../common/async.js'; @@ -76,12 +76,6 @@ suite('dom', () => { assert(!element.classList.contains('bar')); }); - test('multibyteAwareBtoa', () => { - assert.ok(multibyteAwareBtoa('hello world').length > 0); - assert.ok(multibyteAwareBtoa('平仮名').length > 0); - assert.ok(multibyteAwareBtoa(new Array(100000).fill('vs').join('')).length > 0); // https://github.com/microsoft/vscode/issues/112013 - }); - suite('$', () => { test('should build simple nodes', () => { const div = $('div'); diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts index dca2a40410e..9355afd375d 100644 --- a/src/vs/base/test/common/strings.test.ts +++ b/src/vs/base/test/common/strings.test.ts @@ -662,6 +662,12 @@ suite('Strings', () => { assert.strictEqual(strings.InvisibleCharacters.containsInvisibleCharacter('a\u{e015a}\u000bb'), true); }); + test('multibyteAwareBtoa', () => { + assert.ok(strings.multibyteAwareBtoa('hello world').length > 0); + assert.ok(strings.multibyteAwareBtoa('平仮名').length > 0); + assert.ok(strings.multibyteAwareBtoa(new Array(100000).fill('vs').join('')).length > 0); // https://github.com/microsoft/vscode/issues/112013 + }); + ensureNoDisposablesAreLeakedInTestSuite(); }); diff --git a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts index e343c5a3147..5e9387f7a88 100644 --- a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { multibyteAwareBtoa } from '../../../base/browser/dom.js'; +import { multibyteAwareBtoa } from '../../../base/common/strings.js'; import { CancelablePromise, createCancelablePromise } from '../../../base/common/async.js'; import { VSBuffer } from '../../../base/common/buffer.js'; import { CancellationToken } from '../../../base/common/cancellation.js'; diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 640c0b8bfe8..42d71b82052 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -5,7 +5,8 @@ import './media/sidebysideeditor.css'; import { localize } from '../../../../nls.js'; -import { Dimension, $, clearNode, multibyteAwareBtoa } from '../../../../base/browser/dom.js'; +import { Dimension, $, clearNode } from '../../../../base/browser/dom.js'; +import { multibyteAwareBtoa } from '../../../../base/common/strings.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; import { IEditorControl, IEditorPane, IEditorOpenContext, EditorExtensions, SIDE_BY_SIDE_EDITOR_ID, SideBySideEditor as Side, IEditorPaneSelection, IEditorPaneWithSelection, IEditorPaneSelectionChangeEvent, isEditorPaneWithSelection, EditorPaneSelectionCompareResult } from '../../../common/editor.js'; import { SideBySideEditorInput } from '../../../common/editor/sideBySideEditorInput.js'; diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 3de940f1771..1fdcca78407 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -29,7 +29,8 @@ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { EditorActivation, ITextEditorOptions } from '../../../../platform/editor/common/editor.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { isEqual } from '../../../../base/common/resources.js'; -import { Dimension, multibyteAwareBtoa } from '../../../../base/browser/dom.js'; +import { Dimension } from '../../../../base/browser/dom.js'; +import { multibyteAwareBtoa } from '../../../../base/common/strings.js'; import { ByteSize, FileOperationError, FileOperationResult, IFileService, TooLargeFileOperationError } from '../../../../platform/files/common/files.js'; import { IBoundarySashes } from '../../../../base/browser/ui/sash/sash.js'; import { IPreferencesService } from '../../../services/preferences/common/preferences.js';