| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { matchesFuzzy } from './filters.js';
- import { ltrim } from './strings.js';
- import { ThemeIcon } from './themables.js';
- const iconStartMarker = '$(';
- const iconsRegex = new RegExp(`\\$\\(${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?\\)`, 'g'); // no capturing groups
- const escapeIconsRegex = new RegExp(`(\\\\)?${iconsRegex.source}`, 'g');
- export function escapeIcons(text) {
- return text.replace(escapeIconsRegex, (match, escaped) => escaped ? match : `\\${match}`);
- }
- const markdownEscapedIconsRegex = new RegExp(`\\\\${iconsRegex.source}`, 'g');
- export function markdownEscapeEscapedIcons(text) {
- // Need to add an extra \ for escaping in markdown
- return text.replace(markdownEscapedIconsRegex, match => `\\${match}`);
- }
- const stripIconsRegex = new RegExp(`(\\s)?(\\\\)?${iconsRegex.source}(\\s)?`, 'g');
- /**
- * Takes a label with icons (`$(iconId)xyz`) and strips the icons out (`xyz`)
- */
- export function stripIcons(text) {
- if (text.indexOf(iconStartMarker) === -1) {
- return text;
- }
- return text.replace(stripIconsRegex, (match, preWhitespace, escaped, postWhitespace) => escaped ? match : preWhitespace || postWhitespace || '');
- }
- /**
- * Takes a label with icons (`$(iconId)xyz`), removes the icon syntax adds whitespace so that screen readers can read the text better.
- */
- export function getCodiconAriaLabel(text) {
- if (!text) {
- return '';
- }
- return text.replace(/\$\((.*?)\)/g, (_match, codiconName) => ` ${codiconName} `).trim();
- }
- const _parseIconsRegex = new RegExp(`\\$\\(${ThemeIcon.iconNameCharacter}+\\)`, 'g');
- /**
- * Takes a label with icons (`abc $(iconId)xyz`) and returns the text (`abc xyz`) and the offsets of the icons (`[3]`)
- */
- export function parseLabelWithIcons(input) {
- _parseIconsRegex.lastIndex = 0;
- let text = '';
- const iconOffsets = [];
- let iconsOffset = 0;
- while (true) {
- const pos = _parseIconsRegex.lastIndex;
- const match = _parseIconsRegex.exec(input);
- const chars = input.substring(pos, match === null || match === void 0 ? void 0 : match.index);
- if (chars.length > 0) {
- text += chars;
- for (let i = 0; i < chars.length; i++) {
- iconOffsets.push(iconsOffset);
- }
- }
- if (!match) {
- break;
- }
- iconsOffset += match[0].length;
- }
- return { text, iconOffsets };
- }
- export function matchesFuzzyIconAware(query, target, enableSeparateSubstringMatching = false) {
- const { text, iconOffsets } = target;
- // Return early if there are no icon markers in the word to match against
- if (!iconOffsets || iconOffsets.length === 0) {
- return matchesFuzzy(query, text, enableSeparateSubstringMatching);
- }
- // Trim the word to match against because it could have leading
- // whitespace now if the word started with an icon
- const wordToMatchAgainstWithoutIconsTrimmed = ltrim(text, ' ');
- const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutIconsTrimmed.length;
- // match on value without icon
- const matches = matchesFuzzy(query, wordToMatchAgainstWithoutIconsTrimmed, enableSeparateSubstringMatching);
- // Map matches back to offsets with icon and trimming
- if (matches) {
- for (const match of matches) {
- const iconOffset = iconOffsets[match.start + leadingWhitespaceOffset] /* icon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
- match.start += iconOffset;
- match.end += iconOffset;
- }
- }
- return matches;
- }
|