mirror of
https://github.com/huhu/rust-search-extension
synced 2024-11-14 15:47:12 +00:00
Add RustSearchOmnibox class
This commit is contained in:
parent
2cd58ec1d6
commit
68d011e310
2 changed files with 346 additions and 305 deletions
334
extension/lib.js
Normal file
334
extension/lib.js
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
import settings from "./settings.js";
|
||||||
|
import Statistics from "./statistics.js";
|
||||||
|
import HistoryCommand from "./core/command/history.js";
|
||||||
|
import CrateDocManager from "./crate-manager.js";
|
||||||
|
import { Compat } from "./core/index.js";
|
||||||
|
import {
|
||||||
|
LINT_URL,
|
||||||
|
REDIRECT_URL,
|
||||||
|
} from "./constants.js";
|
||||||
|
|
||||||
|
export default class RustSearchOmnibox {
|
||||||
|
static async run({
|
||||||
|
omnibox,
|
||||||
|
stdSearcher,
|
||||||
|
nightlySearcher,
|
||||||
|
crateDocSearcher,
|
||||||
|
crateSearcher,
|
||||||
|
attributeSearcher,
|
||||||
|
bookSearcher,
|
||||||
|
caniuseSearcher,
|
||||||
|
lintSearcher,
|
||||||
|
commandManager,
|
||||||
|
}) {
|
||||||
|
// All dynamic setting items. Those items will been updated
|
||||||
|
// in chrome.storage.onchange listener callback.
|
||||||
|
let isOfflineMode = await settings.isOfflineMode;
|
||||||
|
let offlineDocPath = await settings.offlineDocPath;
|
||||||
|
let defaultSearch = await settings.defaultSearch;
|
||||||
|
let crateRegistry = await settings.crateRegistry;
|
||||||
|
|
||||||
|
function formatDoc(index, doc) {
|
||||||
|
let content = doc.href;
|
||||||
|
let description = doc.displayPath + `<match>${doc.name}</match>`;
|
||||||
|
if (doc.desc) {
|
||||||
|
description += ` - <dim>${Compat.escape(Compat.eliminateTags(doc.desc))}</dim>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.queryType === "s" || doc.queryType === "src") {
|
||||||
|
let url = new URL(doc.href);
|
||||||
|
url.search = "?mode=src";
|
||||||
|
content = url.toString();
|
||||||
|
description = `[Source code] ${description}`;
|
||||||
|
}
|
||||||
|
return { content, description };
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapCrateSearchAppendix(appendix) {
|
||||||
|
return [
|
||||||
|
appendix,
|
||||||
|
{
|
||||||
|
content: "remind",
|
||||||
|
description: `Remind: <dim>We only indexed the top 20K crates. Sorry for the inconvenience if your desired crate not show.</dim>`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
omnibox.bootstrap({
|
||||||
|
onSearch: (query) => {
|
||||||
|
return stdSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: formatDoc,
|
||||||
|
onAppend: (query) => {
|
||||||
|
return [{
|
||||||
|
content: stdSearcher.getSearchUrl(query),
|
||||||
|
description: `Search Rust docs <match>${query}</match> on ${isOfflineMode ? "offline mode" : stdSearcher.getRootPath()}`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
onEmptyNavigate: (content, disposition) => {
|
||||||
|
commandManager.handleCommandEnterEvent(content, disposition);
|
||||||
|
},
|
||||||
|
beforeNavigate: async (query, content) => {
|
||||||
|
if (content && /^@\w+$/i.test(content.trim())) {
|
||||||
|
// Case: @crate, redirect to that crate's docs.rs page
|
||||||
|
return `https://docs.rs/${content.replace("@", "")}`;
|
||||||
|
} else if (content && /^https?.*\/~\/\*\/.*/ig.test(content)) {
|
||||||
|
// Sanitize docs url which from all crates doc search mode. (Prefix with "~")
|
||||||
|
// Here is the url instance: https://docs.rs/~/*/reqwest/fn.get.html
|
||||||
|
let [_, __, libName] = new URL(content).pathname.slice(1).split("/");
|
||||||
|
let crate = await CrateDocManager.getCrateByName(libName);
|
||||||
|
const crateVersion = await settings.keepCratesUpToDate ? "latest" : crate.version;
|
||||||
|
return content.replace("/~/", `/${crate.crateName || libName}/`).replace("/*/", `/${crateVersion}/`);
|
||||||
|
} else {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
afterNavigated: async (query, result) => {
|
||||||
|
// Ignore the command history
|
||||||
|
if (query?.startsWith(":")) return;
|
||||||
|
|
||||||
|
// Only keep the latest 100 of search history.
|
||||||
|
let historyItem = await HistoryCommand.record(query, result, 100);
|
||||||
|
let statistics = await Statistics.load();
|
||||||
|
await statistics.record(historyItem, true);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addRegexQueryEvent(/^s(?:rc)?:/i, {
|
||||||
|
name: "Source code",
|
||||||
|
onSearch: (query) => {
|
||||||
|
return stdSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: formatDoc,
|
||||||
|
onAppend: (query) => {
|
||||||
|
return [{
|
||||||
|
content: stdSearcher.getSearchUrl(query),
|
||||||
|
description: `Search Rust docs <match>${query}</match> on ${isOfflineMode ? "offline mode" : stdSearcher.getRootPath()}`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Nightly std docs search
|
||||||
|
omnibox.addPrefixQueryEvent("/", {
|
||||||
|
name: "Nightly docs",
|
||||||
|
onSearch: (query) => {
|
||||||
|
query = query.replaceAll("/", "").trim();
|
||||||
|
return nightlySearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, doc) => {
|
||||||
|
let { content, description } = formatDoc(index, doc);
|
||||||
|
return { content, description: '[Nightly] ' + description };
|
||||||
|
},
|
||||||
|
onAppend: (query) => {
|
||||||
|
query = query.replaceAll("/", "").trim();
|
||||||
|
return [{
|
||||||
|
content: nightlySearcher.getSearchUrl(query),
|
||||||
|
description: `Search nightly Rust docs <match>${query}</match> on ${nightlySearcher.getRootPath()}`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("~", {
|
||||||
|
name: "External docs",
|
||||||
|
isDefaultSearch: () => {
|
||||||
|
return defaultSearch.thirdPartyDocs;
|
||||||
|
},
|
||||||
|
searchPriority: 1,
|
||||||
|
onSearch: async (query) => {
|
||||||
|
return await crateDocSearcher.searchAll(query);
|
||||||
|
},
|
||||||
|
onFormat: formatDoc,
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("@", {
|
||||||
|
name: "Crate docs",
|
||||||
|
onSearch: async (query) => {
|
||||||
|
return await crateDocSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, item) => {
|
||||||
|
if ('content' in item) {
|
||||||
|
// 1. Crate list header.
|
||||||
|
// 2. Crate result footer
|
||||||
|
return item;
|
||||||
|
} else if ('href' in item) {
|
||||||
|
return formatDoc(index, item);
|
||||||
|
} else {
|
||||||
|
// Crate name list.
|
||||||
|
let content = `@${item.name}`;
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
description: `<match>${content}</match> v${item.version} - <dim>${Compat.escape(Compat.eliminateTags(item.doc))}</dim>`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAppend: () => {
|
||||||
|
return [{
|
||||||
|
content: chrome.runtime.getURL("manage/crates.html"),
|
||||||
|
description: `Remind: <dim>Select here to manage all your indexed crates</dim>`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("!", {
|
||||||
|
name: "docs.rs",
|
||||||
|
isDefaultSearch: () => {
|
||||||
|
return defaultSearch.docsRs;
|
||||||
|
},
|
||||||
|
searchPriority: 2,
|
||||||
|
onSearch: (query) => {
|
||||||
|
return crateSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, crate) => {
|
||||||
|
return {
|
||||||
|
content: `https://docs.rs/${crate.id}`,
|
||||||
|
description: `${Compat.capitalize("docs.rs")}: <match>${crate.id}</match> v${crate.version} - <dim>${Compat.escape(Compat.eliminateTags(crate.description))}</dim>`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAppend: (query) => {
|
||||||
|
let keyword = query.replace(/[!\s]/g, "");
|
||||||
|
return wrapCrateSearchAppendix({
|
||||||
|
content: "https://docs.rs/releases/search?query=" + encodeURIComponent(keyword),
|
||||||
|
description: "Search Rust crates for " + `<match>${keyword}</match>` + " on https://docs.rs",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("!!", {
|
||||||
|
name: "crates.io",
|
||||||
|
onSearch: (query) => {
|
||||||
|
return crateSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, crate) => {
|
||||||
|
return {
|
||||||
|
content: `https://${crateRegistry}/crates/${crate.id}`,
|
||||||
|
description: `${Compat.capitalize(crateRegistry)}: <match>${crate.id}</match> v${crate.version} - <dim>${Compat.escape(Compat.eliminateTags(crate.description))}</dim>`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAppend: (query) => {
|
||||||
|
let keyword = query.replace(/[!\s]/g, "");
|
||||||
|
return wrapCrateSearchAppendix({
|
||||||
|
content: `https://${crateRegistry}/search?q=` + encodeURIComponent(keyword),
|
||||||
|
description: "Search Rust crates for " + `<match>${keyword}</match>` + ` on https://${crateRegistry}`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("!!!", {
|
||||||
|
name: "Repository",
|
||||||
|
onSearch: (query) => {
|
||||||
|
return crateSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, crate) => {
|
||||||
|
return {
|
||||||
|
content: `${REDIRECT_URL}?crate=${crate.id}`,
|
||||||
|
description: `${Compat.capitalize("repository")}: <match>${crate.id}</match> v${crate.version} - <dim>${Compat.escape(Compat.eliminateTags(crate.description))}</dim>`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAppend: (query) => {
|
||||||
|
let keyword = query.replace(/[!\s]/g, "");
|
||||||
|
return wrapCrateSearchAppendix({
|
||||||
|
content: "https://github.com/search?q=" + encodeURIComponent(keyword),
|
||||||
|
description: "Search Rust crates for " + `<match>${keyword}</match>` + " on https://github.com",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("#", {
|
||||||
|
name: "Attributes",
|
||||||
|
isDefaultSearch: () => {
|
||||||
|
return defaultSearch.attributes;
|
||||||
|
},
|
||||||
|
searchPriority: 3,
|
||||||
|
onSearch: (query) => {
|
||||||
|
query = query.replace(/[[\]]/g, "");
|
||||||
|
return attributeSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, attribute) => {
|
||||||
|
return {
|
||||||
|
content: attribute.href,
|
||||||
|
description: `Attribute: <match>#[${attribute.name}]</match> <dim>${Compat.escape(attribute.description)}</dim>`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("?", {
|
||||||
|
name: "Can I use",
|
||||||
|
onSearch: (query) => {
|
||||||
|
return caniuseSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, feat, query) => {
|
||||||
|
return {
|
||||||
|
content: `https://caniuse.rs/features/${feat.slug}`,
|
||||||
|
description: `Can I use: <match>${Compat.escape(feat.match)}</match> [${feat.version}] - <dim>${Compat.escape(feat.description)}</dim>`
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onAppend: () => {
|
||||||
|
return [{
|
||||||
|
content: ":rfc",
|
||||||
|
description: `Remind: <dim>you can use</dim> :rfc <dim>command to search all Rust RFCs.</dim>`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addRegexQueryEvent(/^`?e\d{2,4}`?$/i, {
|
||||||
|
name: "Error code",
|
||||||
|
onSearch: (query) => {
|
||||||
|
query = query.replace("`", "");
|
||||||
|
let baseIndex = parseInt(query.slice(1).padEnd(4, '0'));
|
||||||
|
let result = [];
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
let errorIndex = 'E' + String(baseIndex++).padStart(4, "0").toUpperCase();
|
||||||
|
result.push(errorIndex);
|
||||||
|
}
|
||||||
|
let baseUrl = isOfflineMode ? offlineDocPath : 'https://doc.rust-lang.org/';
|
||||||
|
return result.map(errorCode => {
|
||||||
|
return {
|
||||||
|
content: `${baseUrl}error_codes/${errorCode}.html`,
|
||||||
|
description: `Open error code <match>${errorCode}</match> on ${isOfflineMode ? 'offline mode' : 'https://doc.rust-lang.org/error_codes/error-index.html'}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent("%", {
|
||||||
|
name: "Books",
|
||||||
|
onSearch: (query) => {
|
||||||
|
return bookSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (index, page) => {
|
||||||
|
let parentTitles = page.parentTitles || [];
|
||||||
|
return {
|
||||||
|
content: page.url,
|
||||||
|
description: `${[...parentTitles.map(t => Compat.escape(t)), `<match>${Compat.escape(page.title)}</match>`].join(" > ")} - <dim>${page.name}</dim>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAppend: () => {
|
||||||
|
return [{
|
||||||
|
content: ":book",
|
||||||
|
description: `Remind: <dim>you can use</dim> :book <dim>command to search all Rust books.</dim>`,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent(">", {
|
||||||
|
name: "Clippy lints",
|
||||||
|
onSearch: (query) => {
|
||||||
|
return lintSearcher.search(query);
|
||||||
|
},
|
||||||
|
onFormat: (_, lint) => {
|
||||||
|
return {
|
||||||
|
content: `${LINT_URL}#${lint.name}`,
|
||||||
|
description: `Clippy lint: [${lint.level}] <match>${lint.name}</match> - <dim>${Compat.escape(Compat.eliminateTags(lint.description))}</dim>`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
omnibox.addPrefixQueryEvent(":", {
|
||||||
|
name: "Commands",
|
||||||
|
onSearch: async (query) => {
|
||||||
|
return commandManager.execute(query);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import settings from "./settings.js";
|
import settings from "./settings.js";
|
||||||
import Statistics from "./statistics.js";
|
|
||||||
import attributesIndex from "./index/attributes.js";
|
import attributesIndex from "./index/attributes.js";
|
||||||
import IndexManager from "./index-manager.js";
|
import IndexManager from "./index-manager.js";
|
||||||
import CrateSearch from "./search/crate.js";
|
import CrateSearch from "./search/crate.js";
|
||||||
|
@ -19,14 +18,11 @@ import SimpleCommand from "./core/command/simple.js";
|
||||||
import OpenCommand from "./core/command/open.js";
|
import OpenCommand from "./core/command/open.js";
|
||||||
import HistoryCommand from "./core/command/history.js";
|
import HistoryCommand from "./core/command/history.js";
|
||||||
import CommandManager from "./core/command/manager.js";
|
import CommandManager from "./core/command/manager.js";
|
||||||
import CrateDocManager from "./crate-manager.js";
|
|
||||||
import { Compat } from "./core/index.js";
|
|
||||||
import {
|
import {
|
||||||
INDEX_UPDATE_URL,
|
INDEX_UPDATE_URL,
|
||||||
LINT_URL,
|
|
||||||
REDIRECT_URL,
|
|
||||||
RUST_RELEASE_README_URL,
|
RUST_RELEASE_README_URL,
|
||||||
} from "./constants.js";
|
} from "./constants.js";
|
||||||
|
import RustSearchOmnibox from "./lib.js";
|
||||||
|
|
||||||
|
|
||||||
async function start(omnibox) {
|
async function start(omnibox) {
|
||||||
|
@ -96,306 +92,17 @@ async function start(omnibox) {
|
||||||
return "https://doc.rust-lang.org/nightly/";
|
return "https://doc.rust-lang.org/nightly/";
|
||||||
});
|
});
|
||||||
|
|
||||||
let formatDoc = (index, doc) => {
|
RustSearchOmnibox.run({
|
||||||
let content = doc.href;
|
omnibox,
|
||||||
let description = doc.displayPath + `<match>${doc.name}</match>`;
|
stdSearcher,
|
||||||
if (doc.desc) {
|
nightlySearcher,
|
||||||
description += ` - <dim>${Compat.escape(Compat.eliminateTags(doc.desc))}</dim>`;
|
crateDocSearcher,
|
||||||
}
|
crateSearcher,
|
||||||
|
attributeSearcher,
|
||||||
if (doc.queryType === "s" || doc.queryType === "src") {
|
bookSearcher,
|
||||||
let url = new URL(doc.href);
|
caniuseSearcher,
|
||||||
url.search = "?mode=src";
|
lintSearcher,
|
||||||
content = url.toString();
|
commandManager,
|
||||||
description = `[Source code] ${description}`;
|
|
||||||
}
|
|
||||||
return { content, description };
|
|
||||||
};
|
|
||||||
|
|
||||||
omnibox.bootstrap({
|
|
||||||
onSearch: (query) => {
|
|
||||||
return stdSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: formatDoc,
|
|
||||||
onAppend: (query) => {
|
|
||||||
return [{
|
|
||||||
content: stdSearcher.getSearchUrl(query),
|
|
||||||
description: `Search Rust docs <match>${query}</match> on ${isOfflineMode ? "offline mode" : stdSearcher.getRootPath()}`,
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
onEmptyNavigate: (content, disposition) => {
|
|
||||||
commandManager.handleCommandEnterEvent(content, disposition);
|
|
||||||
},
|
|
||||||
beforeNavigate: async (query, content) => {
|
|
||||||
if (content && /^@\w+$/i.test(content.trim())) {
|
|
||||||
// Case: @crate, redirect to that crate's docs.rs page
|
|
||||||
return `https://docs.rs/${content.replace("@", "")}`;
|
|
||||||
} else if (content && /^https?.*\/~\/\*\/.*/ig.test(content)) {
|
|
||||||
// Sanitize docs url which from all crates doc search mode. (Prefix with "~")
|
|
||||||
// Here is the url instance: https://docs.rs/~/*/reqwest/fn.get.html
|
|
||||||
let [_, __, libName] = new URL(content).pathname.slice(1).split("/");
|
|
||||||
let crate = await CrateDocManager.getCrateByName(libName);
|
|
||||||
const crateVersion = await settings.keepCratesUpToDate ? "latest" : crate.version;
|
|
||||||
return content.replace("/~/", `/${crate.crateName || libName}/`).replace("/*/", `/${crateVersion}/`);
|
|
||||||
} else {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
afterNavigated: async (query, result) => {
|
|
||||||
// Ignore the command history
|
|
||||||
if (query?.startsWith(":")) return;
|
|
||||||
|
|
||||||
// Only keep the latest 100 of search history.
|
|
||||||
let historyItem = await HistoryCommand.record(query, result, 100);
|
|
||||||
let statistics = await Statistics.load();
|
|
||||||
await statistics.record(historyItem, true);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addRegexQueryEvent(/^s(?:rc)?:/i, {
|
|
||||||
name: "Source code",
|
|
||||||
onSearch: (query) => {
|
|
||||||
return stdSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: formatDoc,
|
|
||||||
onAppend: (query) => {
|
|
||||||
return [{
|
|
||||||
content: stdSearcher.getSearchUrl(query),
|
|
||||||
description: `Search Rust docs <match>${query}</match> on ${isOfflineMode ? "offline mode" : stdSearcher.getRootPath()}`,
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Nightly std docs search
|
|
||||||
omnibox.addPrefixQueryEvent("/", {
|
|
||||||
name: "Nightly docs",
|
|
||||||
onSearch: (query) => {
|
|
||||||
query = query.replaceAll("/", "").trim();
|
|
||||||
return nightlySearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, doc) => {
|
|
||||||
let { content, description } = formatDoc(index, doc);
|
|
||||||
return { content, description: '[Nightly] ' + description };
|
|
||||||
},
|
|
||||||
onAppend: (query) => {
|
|
||||||
query = query.replaceAll("/", "").trim();
|
|
||||||
return [{
|
|
||||||
content: nightlySearcher.getSearchUrl(query),
|
|
||||||
description: `Search nightly Rust docs <match>${query}</match> on ${nightlySearcher.getRootPath()}`,
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("~", {
|
|
||||||
name: "External docs",
|
|
||||||
isDefaultSearch: () => {
|
|
||||||
return defaultSearch.thirdPartyDocs;
|
|
||||||
},
|
|
||||||
searchPriority: 1,
|
|
||||||
onSearch: async (query) => {
|
|
||||||
return await crateDocSearcher.searchAll(query);
|
|
||||||
},
|
|
||||||
onFormat: formatDoc,
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("@", {
|
|
||||||
name: "Crate docs",
|
|
||||||
onSearch: async (query) => {
|
|
||||||
return await crateDocSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, item) => {
|
|
||||||
if ('content' in item) {
|
|
||||||
// 1. Crate list header.
|
|
||||||
// 2. Crate result footer
|
|
||||||
return item;
|
|
||||||
} else if ('href' in item) {
|
|
||||||
return formatDoc(index, item);
|
|
||||||
} else {
|
|
||||||
// Crate name list.
|
|
||||||
let content = `@${item.name}`;
|
|
||||||
return {
|
|
||||||
content,
|
|
||||||
description: `<match>${content}</match> v${item.version} - <dim>${Compat.escape(Compat.eliminateTags(item.doc))}</dim>`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onAppend: () => {
|
|
||||||
return [{
|
|
||||||
content: chrome.runtime.getURL("manage/crates.html"),
|
|
||||||
description: `Remind: <dim>Select here to manage all your indexed crates</dim>`,
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function wrapCrateSearchAppendix(appendix) {
|
|
||||||
return [
|
|
||||||
appendix,
|
|
||||||
{
|
|
||||||
content: "remind",
|
|
||||||
description: `Remind: <dim>We only indexed the top 20K crates. Sorry for the inconvenience if your desired crate not show.</dim>`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("!", {
|
|
||||||
name: "docs.rs",
|
|
||||||
isDefaultSearch: () => {
|
|
||||||
return defaultSearch.docsRs;
|
|
||||||
},
|
|
||||||
searchPriority: 2,
|
|
||||||
onSearch: (query) => {
|
|
||||||
return crateSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, crate) => {
|
|
||||||
return {
|
|
||||||
content: `https://docs.rs/${crate.id}`,
|
|
||||||
description: `${Compat.capitalize("docs.rs")}: <match>${crate.id}</match> v${crate.version} - <dim>${Compat.escape(Compat.eliminateTags(crate.description))}</dim>`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onAppend: (query) => {
|
|
||||||
let keyword = query.replace(/[!\s]/g, "");
|
|
||||||
return wrapCrateSearchAppendix({
|
|
||||||
content: "https://docs.rs/releases/search?query=" + encodeURIComponent(keyword),
|
|
||||||
description: "Search Rust crates for " + `<match>${keyword}</match>` + " on https://docs.rs",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("!!", {
|
|
||||||
name: "crates.io",
|
|
||||||
onSearch: (query) => {
|
|
||||||
return crateSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, crate) => {
|
|
||||||
return {
|
|
||||||
content: `https://${crateRegistry}/crates/${crate.id}`,
|
|
||||||
description: `${Compat.capitalize(crateRegistry)}: <match>${crate.id}</match> v${crate.version} - <dim>${Compat.escape(Compat.eliminateTags(crate.description))}</dim>`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onAppend: (query) => {
|
|
||||||
let keyword = query.replace(/[!\s]/g, "");
|
|
||||||
return wrapCrateSearchAppendix({
|
|
||||||
content: `https://${crateRegistry}/search?q=` + encodeURIComponent(keyword),
|
|
||||||
description: "Search Rust crates for " + `<match>${keyword}</match>` + ` on https://${crateRegistry}`,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("!!!", {
|
|
||||||
name: "Repository",
|
|
||||||
onSearch: (query) => {
|
|
||||||
return crateSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, crate) => {
|
|
||||||
return {
|
|
||||||
content: `${REDIRECT_URL}?crate=${crate.id}`,
|
|
||||||
description: `${Compat.capitalize("repository")}: <match>${crate.id}</match> v${crate.version} - <dim>${Compat.escape(Compat.eliminateTags(crate.description))}</dim>`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onAppend: (query) => {
|
|
||||||
let keyword = query.replace(/[!\s]/g, "");
|
|
||||||
return wrapCrateSearchAppendix({
|
|
||||||
content: "https://github.com/search?q=" + encodeURIComponent(keyword),
|
|
||||||
description: "Search Rust crates for " + `<match>${keyword}</match>` + " on https://github.com",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("#", {
|
|
||||||
name: "Attributes",
|
|
||||||
isDefaultSearch: () => {
|
|
||||||
return defaultSearch.attributes;
|
|
||||||
},
|
|
||||||
searchPriority: 3,
|
|
||||||
onSearch: (query) => {
|
|
||||||
query = query.replace(/[[\]]/g, "");
|
|
||||||
return attributeSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, attribute) => {
|
|
||||||
return {
|
|
||||||
content: attribute.href,
|
|
||||||
description: `Attribute: <match>#[${attribute.name}]</match> <dim>${Compat.escape(attribute.description)}</dim>`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("?", {
|
|
||||||
name: "Can I use",
|
|
||||||
onSearch: (query) => {
|
|
||||||
return caniuseSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, feat, query) => {
|
|
||||||
return {
|
|
||||||
content: `https://caniuse.rs/features/${feat.slug}`,
|
|
||||||
description: `Can I use: <match>${Compat.escape(feat.match)}</match> [${feat.version}] - <dim>${Compat.escape(feat.description)}</dim>`
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onAppend: () => {
|
|
||||||
return [{
|
|
||||||
content: ":rfc",
|
|
||||||
description: `Remind: <dim>you can use</dim> :rfc <dim>command to search all Rust RFCs.</dim>`,
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addRegexQueryEvent(/^`?e\d{2,4}`?$/i, {
|
|
||||||
name: "Error code",
|
|
||||||
onSearch: (query) => {
|
|
||||||
query = query.replace("`", "");
|
|
||||||
let baseIndex = parseInt(query.slice(1).padEnd(4, '0'));
|
|
||||||
let result = [];
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
let errorIndex = 'E' + String(baseIndex++).padStart(4, "0").toUpperCase();
|
|
||||||
result.push(errorIndex);
|
|
||||||
}
|
|
||||||
let baseUrl = isOfflineMode ? offlineDocPath : 'https://doc.rust-lang.org/';
|
|
||||||
return result.map(errorCode => {
|
|
||||||
return {
|
|
||||||
content: `${baseUrl}error_codes/${errorCode}.html`,
|
|
||||||
description: `Open error code <match>${errorCode}</match> on ${isOfflineMode ? 'offline mode' : 'https://doc.rust-lang.org/error_codes/error-index.html'}`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent("%", {
|
|
||||||
name: "Books",
|
|
||||||
onSearch: (query) => {
|
|
||||||
return bookSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (index, page) => {
|
|
||||||
let parentTitles = page.parentTitles || [];
|
|
||||||
return {
|
|
||||||
content: page.url,
|
|
||||||
description: `${[...parentTitles.map(t => Compat.escape(t)), `<match>${Compat.escape(page.title)}</match>`].join(" > ")} - <dim>${page.name}</dim>`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onAppend: () => {
|
|
||||||
return [{
|
|
||||||
content: ":book",
|
|
||||||
description: `Remind: <dim>you can use</dim> :book <dim>command to search all Rust books.</dim>`,
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent(">", {
|
|
||||||
name: "Clippy lints",
|
|
||||||
onSearch: (query) => {
|
|
||||||
return lintSearcher.search(query);
|
|
||||||
},
|
|
||||||
onFormat: (_, lint) => {
|
|
||||||
return {
|
|
||||||
content: `${LINT_URL}#${lint.name}`,
|
|
||||||
description: `Clippy lint: [${lint.level}] <match>${lint.name}</match> - <dim>${Compat.escape(Compat.eliminateTags(lint.description))}</dim>`,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
omnibox.addPrefixQueryEvent(":", {
|
|
||||||
name: "Commands",
|
|
||||||
onSearch: async (query) => {
|
|
||||||
return commandManager.execute(query);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!omnibox.extensionMode) return;
|
if (!omnibox.extensionMode) return;
|
||||||
|
|
Loading…
Reference in a new issue