mirror of
https://github.com/dnlbauer/obsidian-dataview-autocompletion.git
synced 2026-09-11 14:45:30 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b10656c2c3 | ||
|
|
cc078fae6a | ||
|
|
b6cdf6cb47 | ||
|
|
5bfb3116bc | ||
|
|
dac07242cd | ||
|
|
c3f44af074 | ||
|
|
57be38b005 | ||
|
|
e744b48536 | ||
|
|
b79d363c9f | ||
|
|
2d9194265a | ||
|
|
27f2e64884 | ||
|
|
779bd0bd68 | ||
|
|
910d343948 | ||
|
|
5802a6cd5d |
18
README.md
18
README.md
@@ -3,9 +3,23 @@
|
|||||||
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.
|
||||||
|
|
||||||

|
<img src="./assets/demo.gif" alt="Demo" width="400" >
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
|||||||
BIN
assets/demo.gif
BIN
assets/demo.gif
Binary file not shown.
|
Before Width: | Height: | Size: 853 KiB After Width: | Height: | Size: 1.5 MiB |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "dataview-autocompletion",
|
"id": "dataview-autocompletion",
|
||||||
"name": "Dataview Autocompletion",
|
"name": "Dataview Autocompletion",
|
||||||
"version": "0.8.3",
|
"version": "0.9.1",
|
||||||
"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",
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-dataview-autocompletion",
|
"name": "obsidian-dataview-autocompletion",
|
||||||
"version": "0.8.3",
|
"version": "0.9.1",
|
||||||
"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",
|
"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"
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import {
|
|||||||
EditorSuggest,
|
EditorSuggest,
|
||||||
EditorSuggestContext,
|
EditorSuggestContext,
|
||||||
EditorSuggestTriggerInfo,
|
EditorSuggestTriggerInfo,
|
||||||
|
htmlToMarkdown,
|
||||||
|
MarkdownRenderer,
|
||||||
|
MarkdownView,
|
||||||
TFile,
|
TFile,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import { getTriggerText } from "./trigger";
|
import { getTriggerText } from "./trigger";
|
||||||
@@ -67,31 +70,57 @@ export class DataviewSuggester extends EditorSuggest<String> {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSuggestion(value: string, el: HTMLElement): void {
|
renderMarkdownSuggestion(value: string, el: HTMLElement): void {
|
||||||
// Split the value into parts based on the <mark> tags and their content
|
// render markdown preview of inline dataview metadata field
|
||||||
const parts = value.split(/(<mark>.*?<\/mark>)/g);
|
let suggestionText = this.context!.editor.getLine(this.context!.start.line).slice(
|
||||||
|
this.context!.start.ch - 1,
|
||||||
|
this.context!.start.ch,
|
||||||
|
)!;
|
||||||
|
suggestionText += value.replace(/<mark>(.*?)<\/mark>/g, "$1");
|
||||||
|
suggestionText += suggestionText.startsWith("(") ? ")" : "]";
|
||||||
|
|
||||||
// We cannot use inner HTML; Create a span for each part
|
MarkdownRenderer.render(
|
||||||
parts.forEach((part) => {
|
this.app,
|
||||||
if (part.startsWith("<mark>") && part.endsWith("</mark>")) {
|
htmlToMarkdown(suggestionText),
|
||||||
const text = part.slice(6, -7); // Remove <mark> and </mark>
|
el,
|
||||||
el.createEl("span", { text, cls: "suggestion-highlight" });
|
this.context!.file.path,
|
||||||
|
this.app.workspace.getActiveViewOfType(MarkdownView)!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSourceSuggestion(value: string, el: HTMLElement): void {
|
||||||
|
// render source text with highlights
|
||||||
|
// replaces <mark>...</mark> with <span>...</span>
|
||||||
|
const parts = value.split(/(<mark>.*?<\/mark>)/g);
|
||||||
|
parts.forEach((textPart) => {
|
||||||
|
if (textPart.startsWith("<mark>") && textPart.endsWith("</mark>")) {
|
||||||
|
const text = textPart.slice(6, -7); // Remove <mark> and </mark>
|
||||||
|
el.createEl("span", { text, cls: "dataview-suggestion-highlight" });
|
||||||
} else {
|
} else {
|
||||||
// For normal text, create a text node or <span>
|
el.appendText(textPart);
|
||||||
el.createEl("span", { text: part });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderSuggestion(value: string, el: HTMLElement): void {
|
||||||
|
const container = el.createDiv("dataview-suggestion-content");
|
||||||
|
const titleDiv = container.createDiv("dataview-suggestion-title");
|
||||||
|
const noteDiv = container.createDiv("dataview-suggestion-note");
|
||||||
|
|
||||||
|
this.renderMarkdownSuggestion(value, titleDiv);
|
||||||
|
this.renderSourceSuggestion(value, noteDiv);
|
||||||
|
}
|
||||||
|
|
||||||
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
||||||
const { editor, start, end } = this.context!;
|
|
||||||
// remove marks from selection
|
// remove marks from selection
|
||||||
value = value.replace(/<mark>(.*?)<\/mark>/g, "$1");
|
value = value.replace(/<mark>(.*?)<\/mark>/g, "$1");
|
||||||
|
|
||||||
|
const { editor, start, end } = this.context!;
|
||||||
editor.replaceRange(value, start, end);
|
editor.replaceRange(value, start, end);
|
||||||
|
|
||||||
const newCursorPos = {
|
const newCursorPos = {
|
||||||
line: end.line + 1,
|
line: end.line,
|
||||||
ch: 0,
|
ch: start.ch + value.length + 1,
|
||||||
};
|
};
|
||||||
editor.setCursor(newCursorPos);
|
editor.setCursor(newCursorPos);
|
||||||
}
|
}
|
||||||
@@ -122,14 +151,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", "")}|${value.display}]]`;
|
||||||
|
} else {
|
||||||
stringValue = `[[${value.path.split("/").pop().replace(".md", "")}]]`;
|
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}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ export function getTriggerText(line: string, cursorPos: number): [string, number
|
|||||||
*/
|
*/
|
||||||
function getTriggerTextFromRegex(line: string, cursorPos: number, regex: RegExp): [string, number, number] | null {
|
function getTriggerTextFromRegex(line: string, cursorPos: number, regex: RegExp): [string, number, number] | null {
|
||||||
let matches = Array.from(line.matchAll(regex));
|
let matches = Array.from(line.matchAll(regex));
|
||||||
console.log(matches);
|
|
||||||
for (const match of matches) {
|
for (const match of matches) {
|
||||||
if (match.index === undefined) {
|
if (match.index === undefined) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
28
styles.css
28
styles.css
@@ -1,3 +1,29 @@
|
|||||||
span.suggestion-highlight {
|
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-title 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;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.dataview-suggestion-highlight {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user