| |
| |
| |
| |
|
|
| import { AutoCompleteOption } from './AutoCompleteOption.js'; |
| import { |
| formatMacroSignature, |
| createSourceIndicator, |
| createAliasIndicator, |
| renderMacroDetails, |
| } from '../macros/MacroBrowser.js'; |
| import { enumIcons } from '../slash-commands/SlashCommandCommonEnumsProvider.js'; |
|
|
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export class EnhancedMacroAutoCompleteOption extends AutoCompleteOption { |
| |
| #macro; |
|
|
| |
| #context = null; |
|
|
| |
| |
| |
| |
| constructor(macro, context = null) { |
| |
| super(macro.name, enumIcons.macro); |
| this.#macro = macro; |
| this.#context = context; |
| |
| this.nameOffset = 2; |
| } |
|
|
| |
| get macro() { |
| return this.#macro; |
| } |
|
|
| |
| |
| |
| |
| |
| renderItem() { |
| const li = document.createElement('li'); |
| li.classList.add('item', 'macro-ac-item'); |
| li.setAttribute('data-name', this.name); |
| li.setAttribute('data-option-type', 'macro'); |
|
|
| |
| const type = document.createElement('span'); |
| type.classList.add('type', 'monospace'); |
| type.textContent = '{}'; |
| li.append(type); |
|
|
| |
| const specs = document.createElement('span'); |
| specs.classList.add('specs'); |
|
|
| |
| const nameEl = document.createElement('span'); |
| nameEl.classList.add('name', 'monospace'); |
|
|
| |
| const sigText = formatMacroSignature(this.#macro); |
| for (const char of sigText) { |
| const span = document.createElement('span'); |
| span.textContent = char; |
| nameEl.append(span); |
| } |
| specs.append(nameEl); |
| li.append(specs); |
|
|
| |
| const stopgap = document.createElement('span'); |
| stopgap.classList.add('stopgap'); |
| li.append(stopgap); |
|
|
| |
| const help = document.createElement('span'); |
| help.classList.add('help'); |
| const content = document.createElement('span'); |
| content.classList.add('helpContent'); |
| content.textContent = this.#macro.description || ''; |
| help.append(content); |
| li.append(help); |
|
|
| |
| const aliasIcon = createAliasIndicator(this.#macro); |
| if (aliasIcon) { |
| aliasIcon.classList.add('macro-ac-indicator'); |
| li.append(aliasIcon); |
| } |
|
|
| |
| const sourceIcon = createSourceIndicator(this.#macro); |
| sourceIcon.classList.add('macro-ac-indicator'); |
| li.append(sourceIcon); |
|
|
| return li; |
| } |
|
|
| |
| |
| |
| |
| |
| renderDetails() { |
| const frag = document.createDocumentFragment(); |
|
|
| |
| const currentArgIndex = this.#context?.currentArgIndex ?? -1; |
|
|
| |
| if (currentArgIndex >= 0) { |
| const hint = this.#renderArgumentHint(); |
| if (hint) frag.append(hint); |
| } |
|
|
| |
| const details = renderMacroDetails(this.#macro, { currentArgIndex }); |
|
|
| |
| details.classList.add('macro-ac-details'); |
| frag.append(details); |
|
|
| return frag; |
| } |
|
|
| |
| |
| |
| |
| #renderArgumentHint() { |
| if (!this.#context || this.#context.currentArgIndex < 0) return null; |
|
|
| const argIndex = this.#context.currentArgIndex; |
| const isListArg = argIndex >= this.#macro.maxArgs; |
|
|
| |
| if (isListArg && !this.#macro.list) return null; |
|
|
| const hint = document.createElement('div'); |
| hint.classList.add('macro-ac-arg-hint'); |
|
|
| const icon = document.createElement('i'); |
| icon.classList.add('fa-solid', 'fa-arrow-right'); |
| hint.append(icon); |
|
|
| if (isListArg) { |
| |
| const listIndex = argIndex - this.#macro.maxArgs + 1; |
| const text = document.createElement('span'); |
| text.innerHTML = `<strong>List item ${listIndex}</strong>`; |
| hint.append(text); |
| } else { |
| |
| const argDef = this.#macro.unnamedArgDefs[argIndex]; |
| let optionalLabel = ''; |
| if (argDef?.optional) { |
| optionalLabel = argDef.defaultValue !== undefined |
| ? ` <em>(optional, default: ${argDef.defaultValue === '' ? '<empty string>' : argDef.defaultValue})</em>` |
| : ' <em>(optional)</em>'; |
| } |
| const text = document.createElement('span'); |
| text.innerHTML = `<strong>${argDef?.name || `Argument ${argIndex + 1}`}</strong>${optionalLabel}`; |
| if (argDef?.type) { |
| const typeSpan = document.createElement('code'); |
| typeSpan.classList.add('macro-ac-hint-type'); |
| if (Array.isArray(argDef.type)) { |
| typeSpan.textContent = argDef.type.join(' | '); |
| typeSpan.title = `Accepts: ${argDef.type.join(', ')}`; |
| } else { |
| typeSpan.textContent = argDef.type; |
| } |
| text.append(' ', typeSpan); |
| } |
| hint.append(text); |
|
|
| if (argDef?.description) { |
| const descSpan = document.createElement('span'); |
| descSpan.classList.add('macro-ac-hint-desc'); |
| descSpan.textContent = ` — ${argDef.description}`; |
| hint.append(descSpan); |
| } |
|
|
| if (argDef?.sampleValue) { |
| const sampleSpan = document.createElement('span'); |
| sampleSpan.classList.add('macro-ac-hint-sample'); |
| sampleSpan.textContent = ` (e.g. ${argDef.sampleValue})`; |
| hint.append(sampleSpan); |
| } |
| } |
|
|
| return hint; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function parseMacroContext(macroText, cursorOffset) { |
| const parts = []; |
| let currentPart = ''; |
| let partStart = 0; |
| let i = 0; |
|
|
| while (i < macroText.length) { |
| if (macroText[i] === ':' && macroText[i + 1] === ':') { |
| parts.push({ text: currentPart, start: partStart, end: i }); |
| currentPart = ''; |
| i += 2; |
| partStart = i; |
| } else { |
| currentPart += macroText[i]; |
| i++; |
| } |
| } |
| |
| parts.push({ text: currentPart, start: partStart, end: macroText.length }); |
|
|
| |
| let currentArgIndex = -1; |
| for (let idx = 0; idx < parts.length; idx++) { |
| const part = parts[idx]; |
| if (cursorOffset >= part.start && cursorOffset <= part.end) { |
| currentArgIndex = idx - 1; |
| break; |
| } |
| } |
|
|
| |
| if (currentArgIndex === -1 && cursorOffset >= parts[parts.length - 1].end) { |
| currentArgIndex = parts.length - 1; |
| } |
|
|
| return { |
| fullText: macroText, |
| cursorOffset, |
| identifier: parts[0]?.text.trim() || '', |
| args: parts.slice(1).map(p => p.text), |
| currentArgIndex, |
| }; |
| } |
|
|