mirror of
https://github.com/dnlbauer/obsidian-dataview-autocompletion.git
synced 2026-09-10 22:25:29 +00:00
ufuzzy suggestions
This commit is contained in:
6
package-lock.json
generated
6
package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@leeoniya/ufuzzy": "^1.0.17",
|
||||||
"@rollup/plugin-commonjs": "^28.0.1",
|
"@rollup/plugin-commonjs": "^28.0.1",
|
||||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
"rollup": "^2.79.2",
|
"rollup": "^2.79.2",
|
||||||
@@ -1093,6 +1094,11 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@leeoniya/ufuzzy": {
|
||||||
|
"version": "1.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@leeoniya/ufuzzy/-/ufuzzy-1.0.17.tgz",
|
||||||
|
"integrity": "sha512-bGNsu11VP70ZgN+bP9SOQ9rsX6Tu/RzLJQ5F5TzgM9IaZncZweu7lDwcMfPAQ9RW3TVMfnbMCD/NnowkjyT+dQ=="
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"typescript": "4.7.4"
|
"typescript": "4.7.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@leeoniya/ufuzzy": "^1.0.17",
|
||||||
"@rollup/plugin-commonjs": "^28.0.1",
|
"@rollup/plugin-commonjs": "^28.0.1",
|
||||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
"rollup": "^2.79.2",
|
"rollup": "^2.79.2",
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ import {
|
|||||||
TFile,
|
TFile,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import { getTriggerText } from "./trigger";
|
import { getTriggerText } from "./trigger";
|
||||||
|
import uFuzzy from "@leeoniya/ufuzzy";
|
||||||
|
|
||||||
export class DataviewSuggester extends EditorSuggest<String> {
|
export class DataviewSuggester extends EditorSuggest<String> {
|
||||||
|
suggestionsList: string[] = [];
|
||||||
|
searcher: uFuzzy = new uFuzzy({});
|
||||||
|
|
||||||
constructor(plugin: Plugin) {
|
constructor(plugin: Plugin) {
|
||||||
super(plugin.app);
|
super(plugin.app);
|
||||||
}
|
}
|
||||||
@@ -36,34 +40,22 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
|||||||
getSuggestions(
|
getSuggestions(
|
||||||
context: EditorSuggestContext,
|
context: EditorSuggestContext,
|
||||||
): string[] | Promise<string[]> {
|
): string[] | Promise<string[]> {
|
||||||
const suggestions: string[] = [];
|
let idxs = this.searcher.filter(this.suggestionsList, context.query);
|
||||||
// TODO use official dv api?
|
if (idxs != null && idxs.length > 0) {
|
||||||
// @ts-ignore
|
let info = this.searcher.info(
|
||||||
for (const page of this.app.plugins.plugins.dataview.index.pages) {
|
idxs,
|
||||||
const fields = page[1].fields;
|
this.suggestionsList,
|
||||||
for (let [key, val] of fields) {
|
context.query,
|
||||||
let arrayVal;
|
);
|
||||||
if (!Array.isArray(val)) {
|
let order = this.searcher.sort(
|
||||||
arrayVal = [val];
|
info,
|
||||||
} else {
|
this.suggestionsList,
|
||||||
arrayVal = val;
|
context.query,
|
||||||
}
|
);
|
||||||
|
|
||||||
for (const value of arrayVal) {
|
return order.map((i) => this.suggestionsList[info.idx[i]]);
|
||||||
// TODO whitespace in match
|
|
||||||
// Fuzzy matching?
|
|
||||||
const suggestion = key + ":: " + value;
|
|
||||||
if (
|
|
||||||
suggestion.includes(context.query) &&
|
|
||||||
!suggestions.includes(suggestion)
|
|
||||||
) {
|
|
||||||
suggestions.push(key + ":: " + value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
console.log(suggestions);
|
return [];
|
||||||
return suggestions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSuggestion(value: string, el: HTMLElement): void {
|
renderSuggestion(value: string, el: HTMLElement): void {
|
||||||
@@ -71,7 +63,6 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
||||||
console.log("selected", value);
|
|
||||||
const { editor, start, end } = this.context!;
|
const { editor, start, end } = this.context!;
|
||||||
editor.replaceRange(value, start, end);
|
editor.replaceRange(value, start, end);
|
||||||
|
|
||||||
@@ -81,4 +72,42 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
|||||||
};
|
};
|
||||||
editor.setCursor(newCursorPos);
|
editor.setCursor(newCursorPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public buildNewIndex() {
|
||||||
|
console.log("Rebuilding dataview suggestion index");
|
||||||
|
const newSuggestions: string[] = [];
|
||||||
|
|
||||||
|
// Iterate all pages of the Dataview index, and ingest all fields into suggestions
|
||||||
|
// TODO: can we use official dataview api?
|
||||||
|
// @ts-ignore
|
||||||
|
for (const page of this.app.plugins.plugins.dataview.index.pages) {
|
||||||
|
const fields = page[1].fields;
|
||||||
|
for (let [key, val] of fields) {
|
||||||
|
// fields can be a single value or a dict, so we need to handle both
|
||||||
|
let arrayVal;
|
||||||
|
if (!Array.isArray(val)) {
|
||||||
|
arrayVal = [val];
|
||||||
|
} else {
|
||||||
|
arrayVal = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add composite value "key:: value" to suggestions list
|
||||||
|
for (const value of arrayVal) {
|
||||||
|
const compositeValue = key + ":: " + value;
|
||||||
|
if (newSuggestions.indexOf(compositeValue) === -1) {
|
||||||
|
newSuggestions.push(compositeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace old index
|
||||||
|
this.suggestionsList = newSuggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// possible types: update, rename, delete. rename has oldPath
|
||||||
|
public onMetadataChange(type: string, file: TFile, oldPath?: string) {
|
||||||
|
// TODO handle efficiently with delta updates
|
||||||
|
this.buildNewIndex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/main.ts
19
src/main.ts
@@ -1,4 +1,4 @@
|
|||||||
import { App, Plugin, PluginSettingTab, Setting } from "obsidian";
|
import { App, Plugin, PluginSettingTab, Setting, TFile } from "obsidian";
|
||||||
import { DataviewSuggester } from "./DataviewSuggester";
|
import { DataviewSuggester } from "./DataviewSuggester";
|
||||||
|
|
||||||
interface DataviewAutocompleteSettings {
|
interface DataviewAutocompleteSettings {
|
||||||
@@ -19,6 +19,23 @@ export default class DataviewAutocompletePlugin extends Plugin {
|
|||||||
// register suggester
|
// register suggester
|
||||||
this.suggester = new DataviewSuggester(this);
|
this.suggester = new DataviewSuggester(this);
|
||||||
this.registerEditorSuggest(this.suggester);
|
this.registerEditorSuggest(this.suggester);
|
||||||
|
|
||||||
|
this.registerEvent(
|
||||||
|
// @ts-ignore
|
||||||
|
this.app.metadataCache.on("dataview:index-ready", () => {
|
||||||
|
this.suggester.buildNewIndex();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.metadataCache.on(
|
||||||
|
// @ts-ignore
|
||||||
|
"dataview:metadata-change",
|
||||||
|
(type: string, file: TFile, oldPath?: string) => {
|
||||||
|
this.suggester.onMetadataChange(type, file, oldPath);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onunload() {}
|
onunload() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user