Add fallback search strategy for @crate search. Fix #96

This commit is contained in:
Folyd 2021-01-28 17:40:49 +08:00
parent ca22e0e8bb
commit 21d9ef9f4c
3 changed files with 53 additions and 20 deletions

2
core

@ -1 +1 @@
Subproject commit cff98bdb4fb3b66b473ec789eb102812b9b6bebf
Subproject commit e834c1c330e06cfd67456d812e7cbdcf52ac83f5

View file

@ -24,9 +24,10 @@ class CrateDocSearchManager {
this.allCrateSearcher = new CrateDocSearch("~", "*", searchIndex);
}
// Search specific crate docs by prefix `@` sigil.
// If that crate not been indexed, fallback to the list of all indexed crates.
search(query) {
query = query.replace("@", "").trim();
let [crateName, keyword] = query.split(" ");
let [crateName, keyword] = CrateDocSearchManager.parseCrateDocsSearchKeyword(query);
let searcher = null;
if (this.cachedCrateSearcher && this.cachedCrateSearcher.name === crateName) {
@ -47,10 +48,17 @@ class CrateDocSearchManager {
list = list.filter(item => !crateName || item.name.toLowerCase().indexOf(crateName) > -1)
.sort((a, b) => a.name.localeCompare(b.name));
list.unshift({
content: crateName, // Non-empty value is required for content, so maybe give it a crate name.
description: `Following ${list.length} crate(s) were added by you, select one to search their docs exclusively.`
});
if (list.length > 0) {
list.unshift({
content: crateName, // Non-empty value is required for content, so maybe give it a crate name.
description: `Following ${list.length} crate(s) were indexed by you, select one to search their docs exclusively.`
});
} else {
list.unshift({
content: `https://docs.rs/${crateName}/?search=${encodeURIComponent(keyword)}`,
description: `Crate ${c.match(crateName)} has not been indexed, search ${keyword ? c.match(keyword) : 'keyword'} on ${c.dim(`https://docs.rs/${crateName}`)} directly`,
});
}
return list;
}
}
@ -59,7 +67,7 @@ class CrateDocSearchManager {
// Push result footer.
results.push({
content: searcher.getSearchUrl(keyword),
description: `Input keyword to search ${c.match(crateName)}'s docs...`,
description: `Search ${keyword ? c.match(keyword) : 'keyword'} on ${c.dim(`https://docs.rs/${crateName}`)} directly`,
});
return results;
}
@ -73,6 +81,12 @@ class CrateDocSearchManager {
return this.allCrateSearcher.search(keyword);
}
static parseCrateDocsSearchKeyword(query) {
query = query.replaceAll("@", "").trim();
let [crateName, ...keyword] = query.split(/\s|:+/i);
return [crateName, keyword.filter(k => k).join('::')];
}
static getCrates() {
return JSON.parse(localStorage.getItem("crates") || "{}");
}

View file

@ -1,5 +1,5 @@
describe("CrateDocSearchManager", function() {
before(function() {
describe("CrateDocSearchManager", function () {
before(function () {
this.crateName = "matches";
this.crateVersion = "0.1.8";
this.searchIndex = {
@ -10,39 +10,58 @@ describe("CrateDocSearchManager", function() {
}
};
});
after(function() {
after(function () {
CrateDocSearchManager.removeCrate(this.crateName);
});
describe("crates", function() {
it("getCrates()", function() {
describe("crates", function () {
it("getCrates()", function () {
CrateDocSearchManager.getCrates().should.deep.equal({});
});
it("addCrate()", function() {
it("addCrate()", function () {
CrateDocSearchManager.addCrate(this.crateName, this.crateVersion, this.searchIndex);
let crates = CrateDocSearchManager.getCrates();
Object.keys(crates).should.contains(this.crateName);
});
it("getSearchIndex()", function() {
it("getSearchIndex()", function () {
let searchIndex = CrateDocSearchManager.getCrateSearchIndex(this.crateName);
searchIndex.should.deep.equal(this.searchIndex);
});
it("removeCrate()", function() {
it("removeCrate()", function () {
CrateDocSearchManager.removeCrate(this.crateName);
CrateDocSearchManager.getCrates().should.deep.equal({});
});
});
describe("search", function() {
describe("search", function () {
let manager = new CrateDocSearchManager();
[["@match", 2], ["@matches", 1], ["@matches m", 5], ["@matches z", 1]]
.forEach(function([keyword, len]) {
it(`"${keyword}" search()`, function() {
.forEach(function ([keyword, len]) {
it(`"${keyword}" search()`, function () {
CrateDocSearchManager.addCrate(this.crateName, this.crateVersion, this.searchIndex);
let result = manager.search(keyword);
result.should.have.lengthOf(len);
});
});
});
describe("parseCrateDocsSearchKeyword", function () {
[
["@tokio", ["tokio", ""]],
["@tokio spawn", ["tokio", "spawn"]],
["@@tokio spawn", ["tokio", "spawn"]],
["@tokio spawn", ["tokio", "spawn"]],
["@tokio::spawn", ["tokio", "spawn"]],
["@tokio:spawn", ["tokio", "spawn"]],
["@tokio task::spawn", ["tokio", "task::spawn"]],
["@tokio::task::spawn", ["tokio", "task::spawn"]],
["@tokio time::sleep::poll", ["tokio", "time::sleep::poll"]],
].forEach(function ([keyword, expected]) {
it(`parseCrateDocsSearchKeyword("${keyword}")`, function () {
let result = CrateDocSearchManager.parseCrateDocsSearchKeyword(keyword);
result.should.deep.equal(expected);
});
});
});
});