Part III
This commit is contained in:
parent
779a5e6604
commit
849cf204de
|
@ -473,7 +473,7 @@ export class Session {
|
|||
if (!search) {
|
||||
this.send({
|
||||
event: "packageSearched",
|
||||
results: this.config.pkg!.popular || [],
|
||||
results: [],
|
||||
search: "",
|
||||
});
|
||||
return;
|
||||
|
|
|
@ -832,6 +832,7 @@ output = "Hello, world!"
|
|||
code: `(defvar x (* 123 234))`,
|
||||
},
|
||||
pkg: {
|
||||
index: ["https://melpa.org/#/", "https://elpa.gnu.org/"],
|
||||
install: `emacs -Q --batch --eval "(progn (require 'package) (push '(\"melpa\" . \"https://melpa.org/packages/\") package-archives) (package-initialize) (unless (ignore-errors (>= (length (directory-files \"~/.emacs.d/elpa/archives\")) 4)) (package-refresh-contents)) (package-install 'NAME))"`,
|
||||
uninstall: `ls ~/.emacs.d/elpa | grep -- - | grep '^NAME-[0-9]' | while read pkg; do emacs -Q --batch --eval "(progn (require 'package) (push '(\"melpa\" . \"https://melpa.org/packages/\") package-archives) (package-initialize) (unless (ignore-errors (>= (length (directory-files \"~/.emacs.d/elpa/archives\")) 4)) (package-refresh-contents)) (call-interactively 'package-delete))" <<< "$pkg"; done`,
|
||||
all: `set -o pipefail; (curl -sS https://elpa.gnu.org/packages/ | grep '<td>' | grep -Eo '[^>]+</a>' | grep -Eo '^[^<]+' && curl -sS https://melpa.org/archive.json | jq -r 'keys | .[]') | sort | uniq`,
|
||||
|
@ -1377,6 +1378,7 @@ PLEASE GIVE UP
|
|||
`,
|
||||
},
|
||||
pkg: {
|
||||
index: "https://www.npmjs.com/",
|
||||
install: "yarn add NAME",
|
||||
uninstall: "yarn remove NAME",
|
||||
search:
|
||||
|
@ -2114,6 +2116,7 @@ binding_irb.run(IRB.conf)
|
|||
`,
|
||||
},
|
||||
pkg: {
|
||||
index: "https://rubygems.org/",
|
||||
install: "gem install --user-install NAME",
|
||||
uninstall: "gem uninstall --user-install NAME",
|
||||
search: `curl -sS 'https://rubygems.org/api/v1/search.json?query=NAME' | jq -r 'map(.name) | .[]'`,
|
||||
|
|
|
@ -22,6 +22,8 @@ import "bootstrap";
|
|||
|
||||
import "xterm/css/xterm.css";
|
||||
|
||||
import { autocomplete } from "./util";
|
||||
|
||||
const DEBUG = window.location.hash === "#debug";
|
||||
const config: RijuConfig = (window as any).rijuConfig;
|
||||
|
||||
|
@ -362,6 +364,10 @@ async function main() {
|
|||
if (config.pkg) {
|
||||
document.getElementById("packagesButton")!.classList.add("visible");
|
||||
$("#packagesModal").on("shown.bs.modal", () => {
|
||||
const searchInput = document.getElementById(
|
||||
"packagesSearch"
|
||||
) as HTMLInputElement;
|
||||
|
||||
if (!packagesTermOpened) {
|
||||
packagesTermOpened = true;
|
||||
|
||||
|
@ -374,19 +380,17 @@ async function main() {
|
|||
packagesFitAddon.fit();
|
||||
window.addEventListener("resize", () => packagesFitAddon.fit());
|
||||
|
||||
const searchInput = document.getElementById(
|
||||
"packagesSearch"
|
||||
) as HTMLInputElement;
|
||||
searchInput.addEventListener(
|
||||
"input",
|
||||
_.debounce(() => {
|
||||
sendMessage({ event: "packageSearch", search: searchInput.value });
|
||||
}, 100)
|
||||
);
|
||||
handlePackageSearchResults = (results: string[]) => {
|
||||
console.log("got results:", results);
|
||||
};
|
||||
handlePackageSearchResults = autocomplete(searchInput);
|
||||
}
|
||||
|
||||
searchInput.value = "";
|
||||
searchInput.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
const MAX_AUTOCOMPLETE_ITEMS = 5;
|
||||
|
||||
export function autocomplete(
|
||||
input: HTMLInputElement
|
||||
): (results: string[]) => void {
|
||||
let results: string[] = [];
|
||||
let currentIndex = -1;
|
||||
let origValue = input.value;
|
||||
|
||||
const close = () => {
|
||||
currentIndex = -1;
|
||||
for (const elt of Array.from(
|
||||
input.parentElement!.getElementsByClassName("autocomplete-items")
|
||||
)) {
|
||||
input.parentElement!.removeChild(elt);
|
||||
}
|
||||
};
|
||||
|
||||
const updateActive = () => {
|
||||
Array.from(
|
||||
input.parentElement!.querySelectorAll(".autocomplete-items div")
|
||||
).forEach((elt, index) => {
|
||||
if (index === currentIndex) {
|
||||
elt.classList.add("autocomplete-active");
|
||||
} else {
|
||||
elt.classList.remove("autocomplete-active");
|
||||
}
|
||||
});
|
||||
if (currentIndex === -1) {
|
||||
input.value = origValue;
|
||||
} else if (currentIndex >= 0 && currentIndex < results.length) {
|
||||
input.value = results[currentIndex];
|
||||
}
|
||||
};
|
||||
|
||||
// input.addEventListener("blur", () => autocompleteClose(input));
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (currentIndex === -1) {
|
||||
origValue = input.value;
|
||||
}
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
currentIndex -= 1;
|
||||
if (currentIndex < -1) {
|
||||
currentIndex = results.length - 1;
|
||||
}
|
||||
updateActive();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "ArrowDown":
|
||||
currentIndex += 1;
|
||||
if (currentIndex >= results.length) {
|
||||
currentIndex = -1;
|
||||
}
|
||||
updateActive();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
});
|
||||
return (newResults: string[]) => {
|
||||
results = newResults.slice(0, MAX_AUTOCOMPLETE_ITEMS);
|
||||
if (document.activeElement !== input) return;
|
||||
close();
|
||||
if (results.length === 0) return;
|
||||
const eltsDiv = document.createElement("div");
|
||||
eltsDiv.classList.add("autocomplete-items");
|
||||
results.forEach((result, index) => {
|
||||
const eltDiv = document.createElement("div");
|
||||
eltDiv.innerText = result;
|
||||
eltDiv.addEventListener("click", () => select(index));
|
||||
eltsDiv.appendChild(eltDiv);
|
||||
});
|
||||
input.parentNode!.appendChild(eltsDiv);
|
||||
};
|
||||
}
|
|
@ -71,3 +71,28 @@ body {
|
|||
#packagesSearch {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.autocomplete-items {
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
border: 1px solid #d4d4d4;
|
||||
border-bottom: none;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.autocomplete-items div {
|
||||
background-color: white;
|
||||
cursor: pointer;
|
||||
padding: 5px 11px;
|
||||
border-bottom: 1px solid #d4d4d4;
|
||||
}
|
||||
|
||||
.autocomplete-items div:hover {
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
|
||||
.autocomplete-active {
|
||||
background-color: DodgerBlue !important;
|
||||
color: white;
|
||||
}
|
||||
|
|
|
@ -56,5 +56,6 @@ module.exports = (_, argv) => ({
|
|||
alias: {
|
||||
vscode: require.resolve("monaco-languageclient/lib/vscode-compatibility"),
|
||||
},
|
||||
extensions: [".js", ".ts"],
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue