diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index d3d0ec9..3bac509 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -669,9 +669,105 @@ async function autocomplete(textArea, prompt, fixedTag = null) { let umiSubPrompts = [...prompt.matchAll(UMI_PROMPT_REGEX)]; let umiTags = []; + let umiTagsWithOperators = [] + + const insertAt = (str,char,pos) => str.slice(0,pos) + char + str.slice(pos); + umiSubPrompts.forEach(umiSubPrompt => { umiTags = umiTags.concat([...umiSubPrompt[0].matchAll(UMI_TAG_REGEX)].map(x => x[1].toLowerCase())); + + const start = umiSubPrompt.index; + const end = umiSubPrompt.index + umiSubPrompt[0].length; + if (textArea.selectionStart >= start && textArea.selectionStart <= end) { + umiTagsWithOperators = insertAt(umiSubPrompt[0], '###', textArea.selectionStart - start); + } }); + + const promptSplitToTags = umiTagsWithOperators.replace(']###[', '][').split("]["); + + const clean = (str) => str + .replaceAll('>', '') + .replaceAll('<', '') + .replaceAll('[', '') + .replaceAll(']', '') + .trim(); + + const matches = promptSplitToTags.reduce((acc, curr) => { + isOptional = curr.includes("|"); + isNegative = curr.startsWith("--"); + let out; + if (isOptional) { + out = { + hasCursor: curr.includes("###"), + tags: clean(curr).split('|').map(x => ({ + hasCursor: x.includes("###"), + isNegative: x.startsWith("--"), + tag: clean(x).replaceAll("###", '').replaceAll("--", '') + })) + }; + acc.optional.push(out); + acc.all.push(...out.tags.map(x => x.tag)); + } else if (isNegative) { + out = { + hasCursor: curr.includes("###"), + tags: clean(curr).replaceAll("###", '').split('|'), + }; + out.tags = out.tags.map(x => x.startsWith("--") ? x.substring(2) : x); + acc.negative.push(out); + acc.all.push(...out.tags); + } else { + out = { + hasCursor: curr.includes("###"), + tags: clean(curr).replaceAll("###", '').split('|'), + }; + acc.positive.push(out); + acc.all.push(...out.tags); + } + return acc; + }, { positive: [], negative: [], optional: [], all: [] }); + + console.log({ matches }) + + const filteredWildcards = (tagword) => { + const wildcards = yamlWildcards.filter(x => { + let tags = x[1]; + const matchesNeg = + matches.negative.length === 0 + || matches.negative.every(x => + x.hasCursor + || x.tags.every(t => !tags[t]) + ); + if (!matchesNeg) return false; + const matchesPos = + matches.positive.length === 0 + || matches.positive.every(x => + x.hasCursor + || x.tags.every(t => tags[t]) + ); + if (!matchesPos) return false; + const matchesOpt = + matches.optional.length === 0 + || matches.optional.some(x => + x.tags.some(t => + t.hasCursor + || t.isNegative + ? !tags[t.tag] + : tags[t.tag] + )); + if (!matchesOpt) return false; + return true; + }).reduce((acc, val) => { + Object.keys(val[1]).forEach(tag => acc[tag] = acc[tag] + 1 || 1); + return acc; + }, {}); + + return Object.entries(wildcards) + .sort((a, b) => b[1] - a[1]) + .filter(x => + x[0] === tagword + || !matches.all.includes(x[0]) + ); + } if (umiTags.length > 0) { // Get difference for subprompt @@ -682,33 +778,33 @@ async function autocomplete(textArea, prompt, fixedTag = null) { // Show all condition let showAll = tagword.endsWith("[") || tagword.endsWith("[--") || tagword.endsWith("|"); - console.log(tagword, umiTags, diff, tagCountChange) - // Exit early if the user closed the bracket manually if ((!diff || diff.length === 0 || (diff.length === 1 && tagCountChange < 0)) && !showAll) { if (!hideBlocked) hideResults(textArea); return; } - let umiTagword = diff[0]; + let umiTagword = diff[0] || ''; let tempResults = []; if (umiTagword && umiTagword.length > 0) { umiTagword = umiTagword.toLowerCase().replace(/[\n\r]/g, ""); originalTagword = tagword; tagword = umiTagword; - + let filteredWildcardsSorted = filteredWildcards(umiTagword); let searchRegex = new RegExp(`(^|[^a-zA-Z])${escapeRegExp(umiTagword)}`, 'i') let baseFilter = x => x[0].toLowerCase().search(searchRegex) > -1; let spaceIncludeFilter = x => x[0].toLowerCase().replaceAll(" ", "_").search(searchRegex) > -1; - tempResults = yamlWildcards.filter(x => baseFilter(x) || spaceIncludeFilter(x)) // Filter by tagword + tempResults = filteredWildcardsSorted.filter(x => baseFilter(x) || spaceIncludeFilter(x)) // Filter by tagword results = tempResults.map(x => [x[0].trim(), "yamlWildcard", x[1]]); // Mark as yaml wildcard } else if (showAll) { - results = yamlWildcards.map(x => [x[0].trim(), "yamlWildcard", x[1]]); // Mark as yaml wildcard + let filteredWildcardsSorted = filteredWildcards(""); + results = filteredWildcardsSorted.map(x => [x[0].trim(), "yamlWildcard", x[1]]); // Mark as yaml wildcard originalTagword = tagword; tagword = ""; } } else { - results = yamlWildcards.map(x => [x[0].trim(), "yamlWildcard", x[1]]); // Mark as yaml wildcard + let filteredWildcardsSorted = filteredWildcards(""); + results = filteredWildcardsSorted.map(x => [x[0].trim(), "yamlWildcard", x[1]]); // Mark as yaml wildcard originalTagword = tagword; tagword = ""; } @@ -770,6 +866,7 @@ async function autocomplete(textArea, prompt, fixedTag = null) { // Guard for empty results if (!results.length) { + console.log('No results found for "' + tagword + '"'); hideResults(textArea); return; } @@ -907,7 +1004,16 @@ async function setup() { try { let yamlTags = (await readFile(`${tagBasePath}/temp/wcet.txt?${new Date().getTime()}`)).split("\n"); // Split into tag, count pairs - yamlWildcards = yamlTags.map(x => x.trim().split(",")); + yamlWildcards = yamlTags.map(x => x + .trim() + .split(",")) + .map(([i, ...rest]) => [ + i, + rest.reduce((a, b) => { + a[b.toLowerCase()] = true; + return a; + }, {}), + ]); } catch (e) { console.error("Error loading yaml wildcards: " + e); } diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index d1a2435..d1012bb 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -61,16 +61,14 @@ def get_ext_wildcard_tags(): for path in WILDCARD_EXT_PATHS: yaml_files.extend(p for p in path.rglob("*.yml")) yaml_files.extend(p for p in path.rglob("*.yaml")) + count = 0 for path in yaml_files: try: with open(path, encoding="utf8") as file: data = yaml.safe_load(file) for item in data: - for _, tag in enumerate(data[item]['Tags']): - if tag not in wildcard_tags: - wildcard_tags[tag] = 1 - else: - wildcard_tags[tag] += 1 + wildcard_tags[count] = ','.join(data[item]['Tags']) + count += 1 except yaml.YAMLError as exc: print(exc) # Sort by count