/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { CompletionItemKind, TextEdit, Range, Position, FileType } from '../htmlLanguageTypes'; import { startsWith } from '../utils/strings'; export class PathCompletionParticipant { constructor(dataManager, readDirectory) { this.dataManager = dataManager; this.readDirectory = readDirectory; this.atributeCompletions = []; } onHtmlAttributeValue(context) { if (this.dataManager.isPathAttribute(context.tag, context.attribute)) { this.atributeCompletions.push(context); } } async computeCompletions(document, documentContext) { const result = { items: [], isIncomplete: false }; for (const attributeCompletion of this.atributeCompletions) { const fullValue = stripQuotes(document.getText(attributeCompletion.range)); if (isCompletablePath(fullValue)) { if (fullValue === '.' || fullValue === '..') { result.isIncomplete = true; } else { const replaceRange = pathToReplaceRange(attributeCompletion.value, fullValue, attributeCompletion.range); const suggestions = await this.providePathSuggestions(attributeCompletion.value, replaceRange, document, documentContext); for (const item of suggestions) { result.items.push(item); } } } } return result; } async providePathSuggestions(valueBeforeCursor, replaceRange, document, documentContext) { const valueBeforeLastSlash = valueBeforeCursor.substring(0, valueBeforeCursor.lastIndexOf('/') + 1); // keep the last slash let parentDir = documentContext.resolveReference(valueBeforeLastSlash || '.', document.uri); if (parentDir) { try { const result = []; const infos = await this.readDirectory(parentDir); for (const [name, type] of infos) { // Exclude paths that start with `.` if (name.charCodeAt(0) !== CharCode_dot) { result.push(createCompletionItem(name, type === FileType.Directory, replaceRange)); } } return result; } catch (e) { // ignore } } return []; } } const CharCode_dot = '.'.charCodeAt(0); function stripQuotes(fullValue) { if (startsWith(fullValue, `'`) || startsWith(fullValue, `"`)) { return fullValue.slice(1, -1); } else { return fullValue; } } function isCompletablePath(value) { if (startsWith(value, 'http') || startsWith(value, 'https') || startsWith(value, '//')) { return false; } return true; } function pathToReplaceRange(valueBeforeCursor, fullValue, range) { let replaceRange; const lastIndexOfSlash = valueBeforeCursor.lastIndexOf('/'); if (lastIndexOfSlash === -1) { replaceRange = shiftRange(range, 1, -1); } else { // For cases where cursor is in the middle of attribute value, like