64 lines
2.7 KiB
JavaScript
64 lines
2.7 KiB
JavaScript
// ==UserScript==
|
|
// @name Deep Space Communications Relay Tab Completion
|
|
// @namespace https://hollymcfarland.com
|
|
// @version 2026-08-16
|
|
// @description Tab complete known definitions
|
|
// @author You
|
|
// @match https://dscr.dixonary.co.uk/
|
|
// @grant none
|
|
// ==/UserScript==
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
// Only listen to tab
|
|
if (event.key !== "Tab") return;
|
|
|
|
// Only listen when message box focused
|
|
const inputEl = document.querySelector("#message-input");
|
|
if (document.activeElement !== inputEl) return;
|
|
|
|
// Don't tab out of input box
|
|
event.preventDefault();
|
|
|
|
const input = inputEl.value;
|
|
const cursorPos = inputEl.selectionStart;
|
|
|
|
// I don't even want to _think_ about how to handle tab completion if you have a range selected
|
|
if (cursorPos !== inputEl.selectionEnd) return;
|
|
|
|
// Character behind cursor should be non-whitespace
|
|
// Character after cursor should at least not be a letter
|
|
// Hopefully this accounts for _most_ reasonable signal definitions
|
|
if (!(/\S/.test(input[cursorPos-1]) && (input.length === cursorPos || /[^A-Z]/.test(input[cursorPos])))) return;
|
|
|
|
// Everything from most recent word boundary to the cursor position should be a reasonable estimate of "current signal"
|
|
const currentSignal = /[\w-_]+?$/.exec(input.slice(0, cursorPos).toUpperCase())[0];
|
|
|
|
const signals = JSON.parse(localStorage.getItem("dict")).map((s) => (s.value));
|
|
|
|
const matches = signals.filter((s) => (s.startsWith(currentSignal)));
|
|
|
|
// Give up if current signal isn't a prefix of any signal
|
|
if (!matches.length) return;
|
|
|
|
// Longest common prefix algorithm
|
|
// After loop, i contains number of additional characters (after currentSignal.length) that are shared by all matches
|
|
matches.sort();
|
|
console.log(matches);
|
|
let i = 0;
|
|
for (; i<matches[0].length; i++) {
|
|
const idx = i + currentSignal.length;
|
|
const [first, last] = [matches[0][idx], matches[matches.length-1][idx]];
|
|
if (first === undefined || last === undefined || first !== last) break;
|
|
}
|
|
|
|
const addedCharacters = matches[0].slice(currentSignal.length, currentSignal.length+i);
|
|
|
|
// Put new computed value back into text box and reposition cursor to match
|
|
inputEl.value = input.slice(0, cursorPos) + addedCharacters + input.slice(cursorPos);
|
|
inputEl.selectionStart = cursorPos + i;
|
|
inputEl.selectionEnd = cursorPos + i;
|
|
});
|
|
})(); |