mirror of
https://github.com/dnlbauer/obsidian-dataview-autocompletion.git
synced 2026-09-11 06:35:29 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d85c07126f | ||
|
|
020054857b | ||
|
|
f58f736df4 | ||
|
|
1644899116 | ||
|
|
1debbb51f2 | ||
|
|
dd86b55bed | ||
|
|
8240045641 | ||
|
|
2dae1175f8 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "dataview-autocompletion",
|
||||
"name": "Dataview Autocompletion",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.3",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Adds autocompletion to Dataview metadata fields",
|
||||
"author": "Daniel Bauer",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-dataview-autocompletion",
|
||||
"version": "0.8",
|
||||
"version": "0.8.3",
|
||||
"description": "This is a plugin for Obsidian that provides autocompletion for Dataview metadata fields",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
@@ -8,6 +8,7 @@
|
||||
"build": "npx rollup --config rollup.config.js --environment BUILD:production",
|
||||
"check-format": "npx prettier --check src",
|
||||
"test": "npx jest",
|
||||
"bdd": "npx jest -i --watch --no-cache",
|
||||
"version": "node ersion-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@@ -68,9 +68,19 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
||||
}
|
||||
|
||||
renderSuggestion(value: string, el: HTMLElement): void {
|
||||
// replace marks with bold
|
||||
const formattedHtml = value.replace(/<mark>(.*?)<\/mark>/g, '<span style="font-weight: bold;">$1</span>');
|
||||
el.innerHTML = formattedHtml;
|
||||
// Split the value into parts based on the <mark> tags and their content
|
||||
const parts = value.split(/(<mark>.*?<\/mark>)/g);
|
||||
|
||||
// We cannot use inner HTML; Create a span for each part
|
||||
parts.forEach((part) => {
|
||||
if (part.startsWith("<mark>") && part.endsWith("</mark>")) {
|
||||
const text = part.slice(6, -7); // Remove <mark> and </mark>
|
||||
el.createEl("span", { text, cls: "suggestion-highlight" });
|
||||
} else {
|
||||
// For normal text, create a text node or <span>
|
||||
el.createEl("span", { text: part });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
||||
@@ -159,6 +169,8 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
||||
}
|
||||
|
||||
const page = dataviewApi.page(file.path);
|
||||
if (page === undefined) continue; // not a markdown file
|
||||
|
||||
const fields = Object.keys(page)
|
||||
.filter((k) => k !== "file")
|
||||
.map((k) => [k, page[k]]);
|
||||
@@ -218,6 +230,8 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
||||
const updateCompositeValues = [];
|
||||
|
||||
const page = getAPI(this.app).page(file.path);
|
||||
if (page === undefined) return; // not a markdown file
|
||||
|
||||
const fields = Object.keys(page)
|
||||
.filter((k) => k !== "file")
|
||||
.map((k) => [k, page[k]]);
|
||||
@@ -297,13 +311,12 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
||||
for (const value of this.suggestionsRefs.get(file.path)!) {
|
||||
this.suggestionsRefCount.set(value, this.suggestionsRefCount.get(value)! - 1);
|
||||
if (this.suggestionsRefCount.get(value) === 0) {
|
||||
console.debug("deleting value from suggestion index", value);
|
||||
this.suggestionsList.splice(this.suggestionsList.indexOf(value), 1);
|
||||
}
|
||||
}
|
||||
this.suggestionsRefs.delete(file.path);
|
||||
} else {
|
||||
console.warn("Unknown update type:", type, file, oldPath);
|
||||
console.debug("Unknown update type:", type, file, oldPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
src/main.ts
29
src/main.ts
@@ -1,6 +1,6 @@
|
||||
import { App, Plugin, PluginSettingTab, Setting, TFile } from "obsidian";
|
||||
import { DataviewSuggester } from "./DataviewSuggester";
|
||||
import { getAPI } from "obsidian-dataview";
|
||||
import { getAPI, isPluginEnabled } from "obsidian-dataview";
|
||||
import { SettingsTab } from "./SettingsTab";
|
||||
|
||||
interface DataviewAutocompleteSettings {
|
||||
@@ -15,18 +15,19 @@ const DEFAULT_SETTINGS: DataviewAutocompleteSettings = {
|
||||
|
||||
export default class DataviewAutocompletePlugin extends Plugin {
|
||||
settings: DataviewAutocompleteSettings;
|
||||
suggester: DataviewSuggester | undefined;
|
||||
suggester: DataviewSuggester;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new SettingsTab(this.app, this));
|
||||
|
||||
this.suggester = new DataviewSuggester(this, 10, true, true);
|
||||
this.registerEditorSuggest(this.suggester);
|
||||
|
||||
this.registerEvent(
|
||||
// @ts-ignore
|
||||
this.app.metadataCache.on("dataview:index-ready", () => {
|
||||
if (this.suggester !== undefined) {
|
||||
this.suggester.onDataviewIndexReady();
|
||||
}
|
||||
this.suggester.onDataviewIndexReady();
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -35,24 +36,14 @@ export default class DataviewAutocompletePlugin extends Plugin {
|
||||
// @ts-ignore
|
||||
"dataview:metadata-change",
|
||||
(type: string, file: TFile, oldPath?: string) => {
|
||||
if (this.suggester !== undefined) {
|
||||
this.suggester.onDataviewMetadataChange(type, file, oldPath);
|
||||
}
|
||||
this.suggester.onDataviewMetadataChange(type, file, oldPath);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
// @ts-ignore
|
||||
if (!Object.keys(this.app.plugins.plugins).includes("dataview")) {
|
||||
console.warn("Dataview plugin not installed. Dataview Autocompletion plugin will not work.");
|
||||
} else {
|
||||
// register suggester, requires dataview to be loaded first.
|
||||
console.log("Registering dataview autocompletion suggester");
|
||||
this.suggester = new DataviewSuggester(this, 10, true, true);
|
||||
this.registerEditorSuggest(this.suggester);
|
||||
}
|
||||
});
|
||||
if (isPluginEnabled(this.app) && getAPI(this.app)?.index.initialized) {
|
||||
this.suggester.onDataviewIndexReady();
|
||||
}
|
||||
}
|
||||
|
||||
onunload() {}
|
||||
|
||||
@@ -3,29 +3,28 @@
|
||||
* and captures the enclosed text
|
||||
* If the brackets start a markdown link, they are ignored.
|
||||
* Wiki links don't need to be ignored since Obsidian overwrites suggestions for them.
|
||||
* We are not allowd to use lookbehinds, because iOS does not support them in older versions.
|
||||
*/
|
||||
const filledRegex = new RegExp(
|
||||
"(" +
|
||||
[
|
||||
// pattern for parantheses
|
||||
// pos. lookbehind for opening parantheses; no closing square bracket before to exlude markdown links
|
||||
/(?<=^\(|[^\]]\()/,
|
||||
/.+?/,
|
||||
// pos. lookahead for closing paranthesis; not followed by another one for nested ((test))
|
||||
/(?=\)$|\)[^\)])/,
|
||||
[
|
||||
// pattern for parantheses
|
||||
// look for opening parantheses; no closing or opening square bracket before to exlude markdown links, etc.
|
||||
/(?:^\(|[^\[\]]\()/,
|
||||
/(.+?)/,
|
||||
// pos. lookahead for closing paranthesis; not followed by another one for nested ((test))
|
||||
/(?=\)$|\)[^\)])/,
|
||||
|
||||
/|/,
|
||||
/|/,
|
||||
|
||||
// pattern for square brackets
|
||||
// pos. lookbehind for opening square bracket
|
||||
/(?<=\[)/,
|
||||
/.+?/,
|
||||
// pos. lookahead for closing bracket; not followed by another one ([[test]]) or an opening paranthese (markdown link!)
|
||||
/(?=\]$|\][^\]\(])/,
|
||||
]
|
||||
.map((s) => s.source)
|
||||
.join("") +
|
||||
")",
|
||||
// pattern for square brackets
|
||||
// look for opening square brackets
|
||||
/(?:\[)/,
|
||||
/(.+?)/,
|
||||
// pos. lookahead for closing bracket; not followed by another one ([[test]]) or an opening paranthese (markdown link!)
|
||||
/(?=\]$|\][^\]\(])/,
|
||||
]
|
||||
.map((s) => s.source)
|
||||
.join(""),
|
||||
"g",
|
||||
);
|
||||
|
||||
@@ -52,17 +51,19 @@ export function getTriggerText(line: string, cursorPos: number): [string, number
|
||||
*/
|
||||
function getTriggerTextFromRegex(line: string, cursorPos: number, regex: RegExp): [string, number, number] | null {
|
||||
let matches = Array.from(line.matchAll(regex));
|
||||
console.log(matches);
|
||||
for (const match of matches) {
|
||||
if (match.index === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const matchStart = match!.index;
|
||||
const matchEnd = matchStart + match[1].length;
|
||||
const matchText = match[1] || match[2];
|
||||
const matchStart = match!.index + match[0].indexOf(matchText);
|
||||
const matchEnd = matchStart + matchText.length;
|
||||
const cursorInMatch = cursorPos >= matchStart && cursorPos <= matchEnd;
|
||||
|
||||
if (cursorInMatch) {
|
||||
return [match[1], matchStart, matchEnd];
|
||||
return [matchText, matchStart, matchEnd];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
11
styles.css
11
styles.css
@@ -1,8 +1,3 @@
|
||||
/*
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
|
||||
*/
|
||||
span.suggestion-highlight {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
3
test-vault/.obsidian/community-plugins.json
vendored
3
test-vault/.obsidian/community-plugins.json
vendored
@@ -1,5 +1,6 @@
|
||||
[
|
||||
"sample-plugin",
|
||||
"dataview",
|
||||
"obsidian-dataview-autocompletion"
|
||||
"obsidian-dataview-autocompletion",
|
||||
"dataview-autocompletion"
|
||||
]
|
||||
1
test-vault/not-a-markdown-file.json
Normal file
1
test-vault/not-a-markdown-file.json
Normal file
@@ -0,0 +1 @@
|
||||
{"test": "this is a test file"}
|
||||
Reference in New Issue
Block a user