add sorting by priority

This commit is contained in:
pythongosssss
2023-08-28 10:34:23 +01:00
parent 4ecef08774
commit 3120ce89f5
3 changed files with 99 additions and 26 deletions
+10 -1
View File
@@ -50,7 +50,16 @@ app.registerExtension({
"pysssss.customwords",
text.split("\n").reduce((p, n) => {
n = n.trim();
p[n] = { text: n };
const pos = n.lastIndexOf(",");
let priority = undefined;
if (pos > -1) {
const v = parseInt(n.substr(pos + 1).trim());
if (!isNaN(v)) {
priority = v;
n = n.substr(0, pos).trim();
}
}
p[n] = { text: n, priority };
return p;
}, {})
);
+21
View File
@@ -4,6 +4,7 @@
position: absolute;
font-family: sans-serif;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.4);
z-index: 9999;
}
.pysssss-autocomplete-item {
@@ -24,6 +25,26 @@
text-decoration-color: dodgerblue;
}
.pysssss-autocomplete-priority {
margin-left: auto;
font-size: 10px;
color: #fff;
padding: 2px 4px 2px 14px;
position: relative;
}
.pysssss-autocomplete-priority::after {
content: "";
display: block;
background: rgba(255, 255, 255, 0.25);
width: calc(100% - 10px);
height: 100%;
position: absolute;
left: 10px;
top: 0;
border-radius: 5px;
}
.pysssss-autocomplete-item-info {
margin-left: auto;
transition: filter 0.2s;
+68 -25
View File
@@ -306,6 +306,8 @@ class TextAreaCaretHelper {
export class TextAreaAutoComplete {
static groups = {};
/** @type {Record<string, {text: string, priority?: number; info?: Function}>} */
static words = {};
/** @type {HTMLTextAreaElement} */
@@ -320,8 +322,6 @@ export class TextAreaAutoComplete {
this.dropdown = $el("div.pysssss-autocomplete");
this.#setup();
setTimeout(() => this.#update(), 100);
}
#setup() {
@@ -342,17 +342,17 @@ export class TextAreaAutoComplete {
case "ArrowUp":
e.preventDefault();
if (this.selected.index) {
this.#setSelected(this.currentWords[this.selected.index - 1]);
this.#setSelected(this.currentWords[this.selected.index - 1].wordInfo);
} else {
this.#setSelected(this.currentWords[this.currentWords.length - 1]);
this.#setSelected(this.currentWords[this.currentWords.length - 1].wordInfo);
}
break;
case "ArrowDown":
e.preventDefault();
if (this.selected.index === this.currentWords.length - 1) {
this.#setSelected(this.currentWords[0]);
this.#setSelected(this.currentWords[0].wordInfo);
} else {
this.#setSelected(this.currentWords[this.selected.index + 1]);
this.#setSelected(this.currentWords[this.selected.index + 1].wordInfo);
}
break;
case "Tab":
@@ -413,14 +413,45 @@ export class TextAreaAutoComplete {
#getFilteredWords(term) {
term = term.toLocaleLowerCase();
return Object.keys(TextAreaAutoComplete.words)
.filter((w) => {
const t = w.toLocaleLowerCase();
return t !== term && t.startsWith(term);
})
.sort((a, b) => a.length - b.length)
.slice(0, 20)
.map((k) => TextAreaAutoComplete.words[k]);
const priorityMatches = [];
const prefixMatches = [];
const includesMatches = [];
for (const word of Object.keys(TextAreaAutoComplete.words)) {
const lowerWord = word.toLocaleLowerCase();
if (lowerWord === term) {
// Dont include exact matches
continue;
}
const pos = lowerWord.indexOf(term);
if (pos === -1) {
// No match
continue;
}
const wordInfo = TextAreaAutoComplete.words[word];
if (wordInfo.priority) {
priorityMatches.push({ pos, wordInfo });
} else if (pos) {
includesMatches.push({ pos, wordInfo });
} else {
prefixMatches.push({ pos, wordInfo });
}
}
priorityMatches.sort(
(a, b) =>
b.wordInfo.priority - a.wordInfo.priority ||
a.wordInfo.text.length - b.wordInfo.text.length ||
a.wordInfo.text.localeCompare(b.wordInfo.text)
);
const top = priorityMatches.length * 0.2;
return priorityMatches
.slice(0, top)
.concat(prefixMatches, priorityMatches.slice(top), includesMatches)
.slice(0, 20);
}
#update() {
@@ -448,23 +479,35 @@ export class TextAreaAutoComplete {
this.dropdown.style.display = "";
let hasSelected = false;
const items = this.currentWords.map((w, i) => {
const items = this.currentWords.map(({ wordInfo, pos }, i) => {
const parts = [
$el("span", {
textContent: wordInfo.text.substr(0, pos),
}),
$el("span.pysssss-autocomplete-highlight", {
textContent: w.text.substring(0, before.length),
textContent: wordInfo.text.substr(pos, before.length),
}),
$el("span", {
textContent: w.text.substring(before.length),
textContent: wordInfo.text.substr(pos + before.length),
}),
];
if (w.info) {
if (wordInfo.priority) {
parts.push(
$el("span.pysssss-autocomplete-priority", {
textContent: wordInfo.priority,
})
);
}
if (wordInfo.info) {
parts.push(
$el("a.pysssss-autocomplete-item-info", {
textContent: "ℹ️",
title: "View info...",
onclick: (e) => {
e.stopPropagation();
w.info();
wordInfo.info();
e.preventDefault();
},
})
@@ -475,29 +518,29 @@ export class TextAreaAutoComplete {
{
onclick: () => {
this.el.focus();
this.helper.insertAtCursor(w.text.substr(before.length));
this.helper.insertAtCursor(wordInfo.text.substr(before.length));
setTimeout(() => {
this.#update();
}, 150);
},
onmousemove: () => {
this.#setSelected(w);
this.#setSelected(wordInfo);
},
},
parts
);
if (w === this.selected) {
if (wordInfo === this.selected) {
hasSelected = true;
}
w.index = i;
w.el = item;
wordInfo.index = i;
wordInfo.el = item;
return item;
});
this.#setSelected(hasSelected ? this.selected : this.currentWords[0]);
this.#setSelected(hasSelected ? this.selected : this.currentWords[0].wordInfo);
this.dropdown.replaceChildren(...items);
if (!this.dropdown.parentElement) {