12 Commits
0.8.2 ... 0.9.0

Author SHA1 Message Date
daniel
c3f44af074 bump version 2024-12-23 01:16:06 +01:00
daniel
57be38b005 chore: add prettier write script 2024-12-23 01:12:41 +01:00
daniel
e744b48536 add highlighting and suggestion note 2024-12-23 01:11:44 +01:00
daniel
b79d363c9f fix: inserted value should not use display value if display value is undefined 2024-12-23 00:46:19 +01:00
Daniel Bauer
2d9194265a fix: typo 2024-12-21 12:37:34 +01:00
Daniel Bauer
27f2e64884 Update README.md 2024-12-20 22:36:28 +01:00
Daniel Bauer
779bd0bd68 Merge pull request #2 from dnlbauer/dnlbauer-patch-1
Feat: Update Readme
2024-12-19 13:45:12 +01:00
Daniel Bauer
910d343948 Feat: Update Readme 2024-12-19 13:36:27 +01:00
Daniel Bauer
5802a6cd5d chore: remove debug statements 2024-12-18 11:11:17 +01:00
Daniel Bauer
d85c07126f bump version 2024-12-18 11:07:11 +01:00
Daniel Bauer
020054857b feat: remove lookbehinds, make compatible with iOS 2024-12-18 11:07:06 +01:00
Daniel Bauer
f58f736df4 feat: replace innerHTML call with createEL (obsidian plugin guidelines) 2024-12-18 10:34:00 +01:00
7 changed files with 118 additions and 33 deletions

View File

@@ -3,10 +3,24 @@
This is a plugin for Obsidian (https://obsidian.md). This is a plugin for Obsidian (https://obsidian.md).
Obsidian Dataview Autocomplete enhances the functionality of the popular [Dataview plugin](https://github.com/blacksmithgu/obsidian-dataview) Obsidian Dataview Autocomplete enhances the functionality of the popular [Dataview plugin](https://github.com/blacksmithgu/obsidian-dataview)
by providing autocomplete suggestions for metadata fields in the editor. by providing autocomplete suggestions for metadata fields in the editor. This makes it easy to reuse existing fields and reduces typing errors.
![Demo](./assets/demo.gif) ![Demo](./assets/demo.gif)
## Features
- Provides autocomplete suggestions for inline metadata fields used by Dataview.
- Customizable ignored fields and files for suggestions.
## Installation
While plugin is [waiting](https://github.com/obsidianmd/obsidian-releases/pull/4913) to be reviewed and added to the community plugin list, you can install it manually following the steps below:
1. Download the latest release files (manifest.json, styles.css, main.js) from the Releases page.
2. Create a folder named "dataview-autocompletion" in the Obsidian plugins folder (.obsidian/plugins).
3. Copy the files from step 1 into the new folder.
4. Enable the plugin in the Obsidian settings under the "Community plugins" section. You might have to restart Obsidian to rsee the plugin.
## License ## License
This project is licensed under the **MIT** License. See [LICENSE](./LICENSE) This project is licensed under the **MIT** License. See [LICENSE](./LICENSE)

View File

@@ -1,7 +1,7 @@
{ {
"id": "dataview-autocompletion", "id": "dataview-autocompletion",
"name": "Dataview Autocompletion", "name": "Dataview Autocompletion",
"version": "0.8.2", "version": "0.9.0",
"minAppVersion": "0.15.0", "minAppVersion": "0.15.0",
"description": "Adds autocompletion to Dataview metadata fields", "description": "Adds autocompletion to Dataview metadata fields",
"author": "Daniel Bauer", "author": "Daniel Bauer",

View File

@@ -1,13 +1,15 @@
{ {
"name": "obsidian-dataview-autocompletion", "name": "obsidian-dataview-autocompletion",
"version": "0.8.2", "version": "0.9.0",
"description": "This is a plugin for Obsidian that provides autocompletion for Dataview metadata fields", "description": "This is a plugin for Obsidian that provides autocompletion for Dataview metadata fields",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"dev": "npx rollup --config rollup.config.js -w", "dev": "npx rollup --config rollup.config.js -w",
"build": "npx rollup --config rollup.config.js --environment BUILD:production", "build": "npx rollup --config rollup.config.js --environment BUILD:production",
"check-format": "npx prettier --check src", "check-format": "npx prettier --check src",
"fix-format": "npx prettier --write src",
"test": "npx jest", "test": "npx jest",
"bdd": "npx jest -i --watch --no-cache",
"version": "node ersion-bump.mjs && git add manifest.json versions.json" "version": "node ersion-bump.mjs && git add manifest.json versions.json"
}, },
"keywords": [ "keywords": [

View File

@@ -14,6 +14,10 @@ const createBaseConfig = (outdir) => ({
src: "manifest.json", src: "manifest.json",
dest: outdir, dest: outdir,
}, },
{
src: "styles.css",
dest: outdir,
},
], ],
}), }),
), ),

View File

@@ -5,12 +5,16 @@ import {
EditorSuggest, EditorSuggest,
EditorSuggestContext, EditorSuggestContext,
EditorSuggestTriggerInfo, EditorSuggestTriggerInfo,
htmlToMarkdown,
MarkdownRenderer,
MarkdownView,
TFile, TFile,
} from "obsidian"; } from "obsidian";
import { getTriggerText } from "./trigger"; import { getTriggerText } from "./trigger";
import uFuzzy from "@leeoniya/ufuzzy"; import uFuzzy from "@leeoniya/ufuzzy";
import { getAPI, DataviewApi } from "obsidian-dataview"; import { getAPI, DataviewApi } from "obsidian-dataview";
import DataviewAutocompletePlugin from "./main"; import DataviewAutocompletePlugin from "./main";
import { parentPort } from "worker_threads";
export class DataviewSuggester extends EditorSuggest<String> { export class DataviewSuggester extends EditorSuggest<String> {
plugin: DataviewAutocompletePlugin; plugin: DataviewAutocompletePlugin;
@@ -68,9 +72,40 @@ export class DataviewSuggester extends EditorSuggest<String> {
} }
renderSuggestion(value: string, el: HTMLElement): void { renderSuggestion(value: string, el: HTMLElement): void {
// replace marks with bold // Split the value into parts based on the <mark> tags and their content
const formattedHtml = value.replace(/<mark>(.*?)<\/mark>/g, '<span style="font-weight: bold;">$1</span>'); const parts = value.split(/(<mark>.*?<\/mark>)/g);
el.innerHTML = formattedHtml;
const container = el.createDiv("dataview-suggestion-content");
const titleDiv = container.createDiv("dataview-suggestion-title");
parts.forEach((textPart) => {
if (textPart.startsWith("<mark>") && textPart.endsWith("</mark>")) {
const text = textPart.slice(6, -7); // Remove <mark> and </mark>
titleDiv.createEl("span", { text, cls: "dataview-suggestion-highlight" });
} else {
titleDiv.appendText(textPart);
}
});
if (value.indexOf("[[") !== -1 || value.indexOf("]]") !== -1 || value.indexOf("](") !== -1) {
const noteDiv = container.createDiv("dataview-suggestion-note");
let suggestionText = "";
parts.forEach((textPart) => {
if (textPart.startsWith("<mark>") && textPart.endsWith("</mark>")) {
const text = textPart.slice(6, -7); // Remove <mark> and </mark>
suggestionText += text;
} else {
suggestionText += textPart;
}
});
MarkdownRenderer.render(
this.app,
htmlToMarkdown(suggestionText),
noteDiv,
this.context!.file.path,
this.app.workspace.getActiveViewOfType(MarkdownView)!,
);
}
} }
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void { selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
@@ -112,14 +147,16 @@ export class DataviewSuggester extends EditorSuggest<String> {
// If the value is a string, number or boolean, we can simply convert it to a string // If the value is a string, number or boolean, we can simply convert it to a string
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
stringValue = value.toString(); stringValue = value.toString();
} else if (dataviewAPI.value.typeOf(value) === "link" && value.type === "file" && value.display !== undefined) { } else if (dataviewAPI.value.typeOf(value) === "link" && value.type === "file") {
// value.toString always adds a display value to wiki-style links. // parse wiki-style links
// parse wiki-style links without display value manually here to prevent this from happening for [[filename]] if (value.display !== undefined) {
stringValue = `[[${value.path.split("/").pop().replace(".md", "")}]]`; stringValue = `[[${value.path.split("/").pop().replace(".md", "")}|${value.display}]]`;
} else {
stringValue = `[[${value.path.split("/").pop().replace(".md", "")}]]`;
}
} else { } else {
stringValue = dataviewAPI.value.toString(value); stringValue = dataviewAPI.value.toString(value);
} }
return `${key}:: ${stringValue}`; return `${key}:: ${stringValue}`;
} }

View File

@@ -3,29 +3,28 @@
* and captures the enclosed text * and captures the enclosed text
* If the brackets start a markdown link, they are ignored. * If the brackets start a markdown link, they are ignored.
* Wiki links don't need to be ignored since Obsidian overwrites suggestions for them. * 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( const filledRegex = new RegExp(
"(" + [
[ // pattern for parantheses
// pattern for parantheses // look for opening parantheses; no closing or opening square bracket before to exlude markdown links, etc.
// 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))
// pos. lookahead for closing paranthesis; not followed by another one for nested ((test)) /(?=\)$|\)[^\)])/,
/(?=\)$|\)[^\)])/,
/|/, /|/,
// pattern for square brackets // pattern for square brackets
// pos. lookbehind for opening square bracket // look for opening square brackets
/(?<=\[)/, /(?:\[)/,
/.+?/, /(.+?)/,
// pos. lookahead for closing bracket; not followed by another one ([[test]]) or an opening paranthese (markdown link!) // pos. lookahead for closing bracket; not followed by another one ([[test]]) or an opening paranthese (markdown link!)
/(?=\]$|\][^\]\(])/, /(?=\]$|\][^\]\(])/,
] ]
.map((s) => s.source) .map((s) => s.source)
.join("") + .join(""),
")",
"g", "g",
); );
@@ -57,12 +56,13 @@ function getTriggerTextFromRegex(line: string, cursorPos: number, regex: RegExp)
continue; continue;
} }
const matchStart = match!.index; const matchText = match[1] || match[2];
const matchEnd = matchStart + match[1].length; const matchStart = match!.index + match[0].indexOf(matchText);
const matchEnd = matchStart + matchText.length;
const cursorInMatch = cursorPos >= matchStart && cursorPos <= matchEnd; const cursorInMatch = cursorPos >= matchStart && cursorPos <= matchEnd;
if (cursorInMatch) { if (cursorInMatch) {
return [match[1], matchStart, matchEnd]; return [matchText, matchStart, matchEnd];
} }
} }
return null; return null;

28
styles.css Normal file
View File

@@ -0,0 +1,28 @@
div.dataview-suggestion-content {
display: flex;
flex-direction: column;
overflow: hidden;
text-overflow: ellipsis;
margin-inline-end: auto;
}
div.dataview-suggestion-title {
overflow-wrap: break-word;
}
div.dataview-suggestion-note p {
margin-block: 0px;
}
div.dataview-suggestion-note{
font-size: 0.8em;
color: var(--text-muted);
width: 100%;
flex-basis: 100%;
overflow-wrap: break-word;
}
span.dataview-suggestion-highlight {
font-weight: bold;
}