Merge pull request #5145 from vchernetskyi993/master

Added path prefixes for bmarks
This commit is contained in:
Oliver Blanthorn 2025-05-14 09:50:32 +00:00 committed by GitHub
commit 5270e1ef53
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 103 additions and 17 deletions

View file

@ -9,7 +9,7 @@ class BmarkCompletionOption
constructor(
public value: string,
bmark: browser.bookmarks.BookmarkTreeNode,
bmark: providers.Bookmark,
) {
super()
if (!bmark.title) {
@ -17,11 +17,11 @@ class BmarkCompletionOption
}
// Push properties we want to fuzmatch on
this.fuseKeys.push(bmark.title, bmark.url)
this.fuseKeys.push(bmark.path, bmark.title, bmark.url)
this.html = html`<tr class="BmarkCompletionOption option">
<td class="prefix">${"".padEnd(2)}</td>
<td class="title">${bmark.title}</td>
<td class="title">${bmark.path}${bmark.title}</td>
<td class="content">
<a class="url" target="_blank" href=${bmark.url}
>${bmark.url}</a

View file

@ -1,5 +1,6 @@
import * as config from "@src/lib/config"
import { browserBg } from "@src/lib/webext"
import Fuse from "fuse.js"
export function newtaburl() {
// In the nonewtab version, this will return `null` and upset getURL.
@ -8,20 +9,16 @@ export function newtaburl() {
return newtab !== null ? browser.runtime.getURL(newtab) : null
}
export async function getBookmarks(query: string) {
// Search bookmarks, dedupe and sort by most recent.
let bookmarks = await browserBg.bookmarks.search({ query })
export type Bookmark = { path: string } & browser.bookmarks.BookmarkTreeNode
// Remove folder nodes and bad URLs
bookmarks = bookmarks.filter(b => {
try {
return new URL(b.url)
} catch (e) {
return false
}
})
bookmarks.sort((a, b) => b.dateAdded - a.dateAdded)
/**
* Search bookmarks, deduplicate and sort by most recent.
*/
export async function getBookmarks(query: string): Promise<Bookmark[]> {
let bookmarks =
config.get("bmarkfoldersearch") == "true"
? await fuseBookmarksSearch(query)
: await builtInBookmarksSearch(query)
// Remove duplicate bookmarks
const seen = new Map<string, string>()
@ -36,6 +33,90 @@ export async function getBookmarks(query: string) {
return bookmarks
}
/**
* Uses Browser API to search for bookmark by name and URL.
*/
async function builtInBookmarksSearch(query: string): Promise<Bookmark[]> {
const bookmarks = await browserBg.bookmarks.search({ query })
return bookmarks
.map(b => ({ path: "", ...b }))
.filter(isValidBookmark)
.sort((a, b) => b.dateAdded - a.dateAdded)
}
let allBookmarks: Bookmark[]
let bookmarksFuse: Fuse<Bookmark>
/**
* Caches all bookmarks to be able to search by any property.
* Searches by path, name and URL.
*/
async function fuseBookmarksSearch(query: string): Promise<Bookmark[]> {
allBookmarks = allBookmarks || (await collectBookmarks())
bookmarksFuse =
bookmarksFuse ||
new Fuse(allBookmarks, {
keys: ["path", "title", "url"],
findAllMatches: true,
ignoreLocation: true,
ignoreFieldNorm: true,
threshold: config.get("completionfuzziness"),
})
return query ? bookmarksFuse.search(query).map(r => r.item) : allBookmarks
}
async function collectBookmarks(): Promise<Bookmark[]> {
const root = await browserBg.bookmarks.getTree()
const bookmarks = root.flatMap(flattenChildren)
const bookmarksDictionary = bookmarks.reduce((dict, bookmark) => {
dict[bookmark.id] = bookmark
return dict
}, {})
return bookmarks
.map(bookmark => ({
path: buildBookmarkPath("", bookmark, bookmarksDictionary),
...bookmark,
}))
.filter(isValidBookmark)
.sort((a, b) => b.dateAdded - a.dateAdded)
}
function flattenChildren(
node: browser.bookmarks.BookmarkTreeNode,
): browser.bookmarks.BookmarkTreeNode[] {
if (!node.children) {
return [node]
}
return [node, ...node.children.flatMap(flattenChildren)]
}
function buildBookmarkPath(
path: string,
bookmark: browser.bookmarks.BookmarkTreeNode,
bookmarksDictionary: { string?: browser.bookmarks.BookmarkTreeNode },
): string {
if (!bookmark.parentId) {
return path
}
const parent = bookmarksDictionary[bookmark.parentId]
return buildBookmarkPath(
`${parent.title}/${path}`,
parent,
bookmarksDictionary,
)
}
/**
* Bookmark is not a folder and has valid URL.
*/
function isValidBookmark(bookmark: Bookmark): boolean {
try {
return !!new URL(bookmark.url)
} catch (e) {
return false
}
}
export async function getSearchUrls(query: string) {
const suconf = config.get("searchurls")
@ -105,7 +186,7 @@ export async function getCombinedHistoryBmarks(
const combinedMap = new Map<string, any>(
bookmarks.map(bmark => [
bmark.url,
{ title: bmark.title, url: bmark.url, bmark },
{ title: `${bmark.path}${bmark.title}`, url: bmark.url, bmark },
]),
)
history.forEach(page => {

View file

@ -1167,6 +1167,11 @@ export class default_config {
*/
bmarkweight = 100
/**
* Should folders be shown and filtered in bookmark searches.
*/
bmarkfoldersearch: "true" | "false" = "false"
/**
* When displaying searchurls in history completions, how many page views to pretend they have.
*/