feat: use prettier

This commit is contained in:
Daniel Bauer
2024-12-12 19:14:52 +01:00
parent 8eb4da6381
commit 8beb4ac67d
23 changed files with 6411 additions and 5706 deletions

View File

@@ -1,10 +1,17 @@
# top-most EditorConfig file
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 4
tab_width = 4
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.json]
charset = utf-8
indent_style = space
indent_size = 2
[*.{ts,js}]
charset = utf-8
indent_style = space
indent_size = 4

1
.husky/pre-commit Normal file
View File

@@ -0,0 +1 @@
npx lint-staged

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
# Ignore artifacts:
build
coverage
test-vault

1
.prettierrc Normal file
View File

@@ -0,0 +1 @@
{}

8
.prettierrc.json Normal file
View File

@@ -0,0 +1,8 @@
{
"tabWidth": 4,
"semi": true,
"embeddedLanguageFormatting": "off",
"parser": "typescript",
"printWidth": 120,
"arrowParens": "avoid"
}

View File

@@ -6,6 +6,7 @@ This project uses TypeScript to provide type checking and documentation.
The repo depends on the latest plugin API (obsidian.d.ts) in TypeScript Definition format, which contains TSDoc comments describing what it does.
This sample plugin demonstrates some of the basic functionality the plugin API can do.
- Adds a ribbon icon, which shows a Notice when clicked.
- Adds a command "Open Sample Modal" which opens a Modal.
- Adds a plugin setting tab to the settings page.
@@ -56,7 +57,8 @@ Quick starting guide for new plugin devs:
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
## Improve code quality with eslint (optional)
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
- To use eslint with this project, make sure to install eslint from terminal:
- `npm install -g eslint`
- To use eslint to analyze this project use this command:
@@ -73,7 +75,7 @@ The simple way is to set the `fundingUrl` field to your link in your `manifest.j
```json
{
"fundingUrl": "https://buymeacoffee.com"
"fundingUrl": "https://buymeacoffee.com"
}
```
@@ -81,11 +83,11 @@ If you have multiple URLs, you can also do:
```json
{
"fundingUrl": {
"Buy Me a Coffee": "https://buymeacoffee.com",
"GitHub Sponsor": "https://github.com/sponsors",
"Patreon": "https://www.patreon.com/"
}
"fundingUrl": {
"Buy Me a Coffee": "https://buymeacoffee.com",
"GitHub Sponsor": "https://github.com/sponsors",
"Patreon": "https://www.patreon.com/"
}
}
```

View File

@@ -2,48 +2,48 @@ import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
const banner =
`/*
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;
const prod = (process.argv[2] === "production");
const prod = process.argv[2] === "production";
const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["main.ts"],
bundle: true,
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtins],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
minify: prod,
banner: {
js: banner,
},
entryPoints: ["main.ts"],
bundle: true,
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtins,
],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
minify: prod,
});
if (prod) {
await context.rebuild();
process.exit(0);
await context.rebuild();
process.exit(0);
} else {
await context.watch();
await context.watch();
}

View File

@@ -1,11 +1,11 @@
{
"id": "sample-plugin",
"name": "Sample Plugin",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Demonstrates some of the capabilities of the Obsidian API.",
"author": "Obsidian",
"authorUrl": "https://obsidian.md",
"fundingUrl": "https://obsidian.md/pricing",
"isDesktopOnly": false
"id": "sample-plugin",
"name": "Sample Plugin",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Demonstrates some of the capabilities of the Obsidian API.",
"author": "Obsidian",
"authorUrl": "https://obsidian.md",
"fundingUrl": "https://obsidian.md/pricing",
"isDesktopOnly": false
}

11130
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,47 @@
{
"name": "obsidian-sample-plugin",
"version": "1.0.0",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"main": "main.js",
"scripts": {
"dev": "npx rollup --config rollup.config.js -w",
"build": "npx rollup --config rollup.config.js --environment BUILD:production",
"test": "npx jest",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"babel-jest": "^29.7.0",
"builtin-modules": "3.3.0",
"esbuild": "0.17.3",
"obsidian": "latest",
"ts-jest": "^29.2.5",
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"rollup": "^2.79.2",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-typescript2": "^0.36.0"
},
"jest": {
"transform": {
"^.+\\.(ts|tsx|js|jsx)$": "ts-jest"
}
}
"name": "obsidian-sample-plugin",
"version": "1.0.0",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"main": "main.js",
"scripts": {
"dev": "npx rollup --config rollup.config.js -w",
"build": "npx rollup --config rollup.config.js --environment BUILD:production",
"test": "npx jest",
"version": "node version-bump.mjs && git add manifest.json versions.json",
"prepare": "husky"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"babel-jest": "^29.7.0",
"builtin-modules": "3.3.0",
"esbuild": "0.17.3",
"husky": "^9.1.7",
"lint-staged": "^15.2.11",
"obsidian": "latest",
"prettier": "3.4.2",
"ts-jest": "^29.2.5",
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"rollup": "^2.79.2",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-typescript2": "^0.36.0"
},
"jest": {
"transform": {
"^.+\\.(ts|tsx|js|jsx)$": "ts-jest"
}
},
"lint-staged": {
"**/*": "prettier --write --ignore-unknown"
}
}

View File

@@ -5,15 +5,13 @@ import typescript2 from "rollup-plugin-typescript2";
const BASE_CONFIG = {
input: "src/main.ts",
external: ["obsidian"]
external: ["obsidian"],
};
const getRollupPlugins = (tsconfig, ...plugins) =>
[
typescript2(tsconfig),
nodeResolve({ browser: true }),
commonjs(),
].concat(plugins);
[typescript2(tsconfig), nodeResolve({ browser: true }), commonjs()].concat(
plugins,
);
const DEV_PLUGIN_CONFIG = {
...BASE_CONFIG,
@@ -28,10 +26,16 @@ const DEV_PLUGIN_CONFIG = {
undefined,
copy({
targets: [
{ src: "manifest.json", dest: "test-vault/.obsidian/plugins/dataview-suggester/" },
{ src: "styles.css", dest: "test-vault/.obsidian/plugins/dataview-suggester/" },
{
src: "manifest.json",
dest: "test-vault/.obsidian/plugins/dataview-suggester/",
},
{
src: "styles.css",
dest: "test-vault/.obsidian/plugins/dataview-suggester/",
},
],
})
}),
),
};

View File

@@ -1,72 +1,84 @@
import { App, Editor, Plugin, EditorPosition, EditorSuggest, EditorSuggestContext, EditorSuggestTriggerInfo, TFile } from 'obsidian';
import { getTriggerText } from './trigger';
import {
App,
Editor,
Plugin,
EditorPosition,
EditorSuggest,
EditorSuggestContext,
EditorSuggestTriggerInfo,
TFile,
} from "obsidian";
import { getTriggerText } from "./trigger";
export class DataviewSuggester extends EditorSuggest<String> {
constructor(plugin: Plugin) {
super(plugin.app);
}
constructor(plugin: Plugin) {
super(plugin.app)
}
onTrigger(
cursor: EditorPosition,
editor: Editor,
file: TFile,
): EditorSuggestTriggerInfo | null {
const line = editor.getLine(cursor.line);
onTrigger(
cursor: EditorPosition,
editor: Editor,
file: TFile,
): EditorSuggestTriggerInfo | null {
const line = editor.getLine(cursor.line);
let trigger = getTriggerText(line, cursor.ch)
if (trigger !== null) {
return {
query: trigger[0],
start: { line: cursor.line, ch: trigger[1] },
end: { line: cursor.line, ch: trigger[2] },
}
}
return null
}
let trigger = getTriggerText(line, cursor.ch);
if (trigger !== null) {
return {
query: trigger[0],
start: { line: cursor.line, ch: trigger[1] },
end: { line: cursor.line, ch: trigger[2] },
};
}
return null;
}
getSuggestions(context: EditorSuggestContext): string[] | Promise<string[]> {
const suggestions: string[] = []
// TODO use official dv 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) {
let arrayVal
if (!Array.isArray(val)) {
arrayVal = [val]
} else {
arrayVal = val
}
getSuggestions(
context: EditorSuggestContext,
): string[] | Promise<string[]> {
const suggestions: string[] = [];
// TODO use official dv 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) {
let arrayVal;
if (!Array.isArray(val)) {
arrayVal = [val];
} else {
arrayVal = val;
}
for (const value of arrayVal) {
// TODO whitespace in match
// Fuzzy matching?
const suggestion = key + ":: " + value
if (suggestion.includes(context.query) && !suggestions.includes(suggestion)) {
suggestions.push(key+ ":: " + value)
}
}
}
for (const value of arrayVal) {
// 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 suggestions;
}
}
console.log(suggestions)
return suggestions
}
renderSuggestion(value: string, el: HTMLElement): void {
el.setText(value);
}
renderSuggestion(value: string, el: HTMLElement): void {
el.setText(value)
}
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
console.log("selected", value);
const { editor, start, end } = this.context!;
editor.replaceRange(value, start, end);
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
console.log("selected", value)
const { editor, start, end } = this.context!;
editor.replaceRange(value, start, end);
const newCursorPos = {
line: end.line + 1,
ch: 0,
};
editor.setCursor(newCursorPos);
}
const newCursorPos = {
line: end.line + 1,
ch: 0,
};
editor.setCursor(newCursorPos);
}
}

View File

@@ -1,35 +1,37 @@
import { App, Plugin, PluginSettingTab, Setting } from 'obsidian';
import { DataviewSuggester } from './DataviewSuggester';
import { App, Plugin, PluginSettingTab, Setting } from "obsidian";
import { DataviewSuggester } from "./DataviewSuggester";
interface DataviewAutocompleteSettings {
// mySetting: string;
// mySetting: string;
}
const DEFAULT_SETTINGS: DataviewAutocompleteSettings = {
// mySetting: 'default'
}
// mySetting: 'default'
};
export default class DataviewAutocompletePlugin extends Plugin {
settings: DataviewAutocompleteSettings;
suggester: DataviewSuggester
settings: DataviewAutocompleteSettings;
suggester: DataviewSuggester;
async onload() {
await this.loadSettings();
// register suggester
this.suggester = new DataviewSuggester(this);
this.registerEditorSuggest(this.suggester);
}
async onload() {
await this.loadSettings();
onunload() {
// register suggester
this.suggester = new DataviewSuggester(this);
this.registerEditorSuggest(this.suggester);
}
}
onunload() {}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async loadSettings() {
this.settings = Object.assign(
{},
DEFAULT_SETTINGS,
await this.loadData(),
);
}
async saveSettings() {
await this.saveData(this.settings);
}
}
async saveSettings() {
await this.saveData(this.settings);
}
}

View File

@@ -1,139 +1,262 @@
import { getTriggerText } from "./trigger"
import { getTriggerText } from "./trigger";
describe("trigger", () => {
describe("empty", () => {
test("empty parantheses", () => {
expect(getTriggerText("() testing", 1)).toEqual(["", 1, 1])
})
expect(getTriggerText("() testing", 1)).toEqual(["", 1, 1]);
});
test("empty square brackets", () => {
expect(getTriggerText("[] testing", 1)).toEqual(["", 1, 1])
})
expect(getTriggerText("[] testing", 1)).toEqual(["", 1, 1]);
});
test("empty square brackets in text", () => {
expect(getTriggerText("test [] testing", 6)).toEqual(["", 6, 6])
})
expect(getTriggerText("test [] testing", 6)).toEqual(["", 6, 6]);
});
// test("not match empty double square brackets", () => {
// expect(getTriggerText("[[]] testing", 2)).toEqual(null)
// })
test("multiple empty brackets in text", () => {
expect(getTriggerText("test [] and [] testing", 13)).toEqual(["", 13, 13])
})
})
expect(getTriggerText("test [] and [] testing", 13)).toEqual([
"",
13,
13,
]);
});
});
describe("text in parantheses", () => {
test("text behind", () => {
expect(getTriggerText("(capture) testing", 1)).toEqual(["capture", 1, 8])
})
expect(getTriggerText("(capture) testing", 1)).toEqual([
"capture",
1,
8,
]);
});
test("text before", () => {
expect(getTriggerText("testing (capture)", 12)).toEqual(["capture", 9, 16])
})
expect(getTriggerText("testing (capture)", 12)).toEqual([
"capture",
9,
16,
]);
});
test("text behind no whitespace", () => {
expect(getTriggerText("(capture)testing", 1)).toEqual(["capture", 1, 8])
})
expect(getTriggerText("(capture)testing", 1)).toEqual([
"capture",
1,
8,
]);
});
test("text before no whitespace", () => {
expect(getTriggerText("test(capture)", 5)).toEqual(["capture", 5, 12])
})
expect(getTriggerText("test(capture)", 5)).toEqual([
"capture",
5,
12,
]);
});
test("text before and behind", () => {
expect(getTriggerText("test (capture) testing", 6)).toEqual(["capture", 6, 13])
})
expect(getTriggerText("test (capture) testing", 6)).toEqual([
"capture",
6,
13,
]);
});
test("text and colon", () => {
expect(getTriggerText("(capture:) testing", 1)).toEqual(["capture:", 1, 9])
})
expect(getTriggerText("(capture:) testing", 1)).toEqual([
"capture:",
1,
9,
]);
});
test("text and double colon", () => {
expect(getTriggerText("(capture::) testing", 1)).toEqual(["capture::", 1, 10])
})
expect(getTriggerText("(capture::) testing", 1)).toEqual([
"capture::",
1,
10,
]);
});
test("metadata field", () => {
expect(getTriggerText("(capture::Bob) testing", 1)).toEqual(["capture::Bob", 1, 13])
})
expect(getTriggerText("(capture::Bob) testing", 1)).toEqual([
"capture::Bob",
1,
13,
]);
});
test("metadata field with whitespace", () => {
expect(getTriggerText("(capture:: Bob) testing", 1)).toEqual(["capture:: Bob", 1, 14])
})
expect(getTriggerText("(capture:: Bob) testing", 1)).toEqual([
"capture:: Bob",
1,
14,
]);
});
test("metadata field with more white space", () => {
expect(getTriggerText("(capture:: Bob) testing", 1)).toEqual(["capture:: Bob", 1, 16])
})
expect(getTriggerText("(capture:: Bob) testing", 1)).toEqual([
"capture:: Bob",
1,
16,
]);
});
test("text with markdown link", () => {
expect(getTriggerText("([[test]]) testing", 1)).toEqual(["[[test]]", 1, 9])
})
expect(getTriggerText("([[test]]) testing", 1)).toEqual([
"[[test]]",
1,
9,
]);
});
test("text with aliased markdown link", () => {
expect(getTriggerText("([[test|display]]) testing", 1)).toEqual(["[[test|display]]", 1, 17])
})
expect(getTriggerText("([[test|display]]) testing", 1)).toEqual([
"[[test|display]]",
1,
17,
]);
});
test("text with wiki link", () => {
expect(getTriggerText("([[test](https://example.com)]) testing", 1)).toEqual(["[[test](https://example.com)]", 1, 30])
})
expect(
getTriggerText("([[test](https://example.com)]) testing", 1),
).toEqual(["[[test](https://example.com)]", 1, 30]);
});
test("text with wiki link local", () => {
expect(getTriggerText("([[test](test)]) testing", 1)).toEqual(["[[test](test)]", 1, 15])
})
})
expect(getTriggerText("([[test](test)]) testing", 1)).toEqual([
"[[test](test)]",
1,
15,
]);
});
});
describe("text in square brackets", () => {
test("text behind", () => {
expect(getTriggerText("[capture] testing", 1)).toEqual(["capture", 1, 8])
})
expect(getTriggerText("[capture] testing", 1)).toEqual([
"capture",
1,
8,
]);
});
test("text before", () => {
expect(getTriggerText("testing [capture]", 12)).toEqual(["capture", 9, 16])
})
expect(getTriggerText("testing [capture]", 12)).toEqual([
"capture",
9,
16,
]);
});
test("text behind no whitespace", () => {
expect(getTriggerText("[capture]testing", 1)).toEqual(["capture", 1, 8])
})
expect(getTriggerText("[capture]testing", 1)).toEqual([
"capture",
1,
8,
]);
});
test("text before no whitespace", () => {
expect(getTriggerText("test[capture]", 5)).toEqual(["capture", 5, 12])
})
expect(getTriggerText("test[capture]", 5)).toEqual([
"capture",
5,
12,
]);
});
test("text before and behind", () => {
expect(getTriggerText("test [capture] testing", 6)).toEqual(["capture", 6, 13])
})
expect(getTriggerText("test [capture] testing", 6)).toEqual([
"capture",
6,
13,
]);
});
test("text and colon", () => {
expect(getTriggerText("[capture:] testing", 1)).toEqual(["capture:", 1, 9])
})
expect(getTriggerText("[capture:] testing", 1)).toEqual([
"capture:",
1,
9,
]);
});
test("text and double colon", () => {
expect(getTriggerText("[capture::] testing", 1)).toEqual(["capture::", 1, 10])
})
expect(getTriggerText("[capture::] testing", 1)).toEqual([
"capture::",
1,
10,
]);
});
test("metadata field", () => {
expect(getTriggerText("[capture::Bob] testing", 1)).toEqual(["capture::Bob", 1, 13])
})
expect(getTriggerText("[capture::Bob] testing", 1)).toEqual([
"capture::Bob",
1,
13,
]);
});
test("metadata field with whitespace", () => {
expect(getTriggerText("[capture:: Bob] testing", 1)).toEqual(["capture:: Bob", 1, 14])
})
expect(getTriggerText("[capture:: Bob] testing", 1)).toEqual([
"capture:: Bob",
1,
14,
]);
});
test("metadata field with more white space", () => {
expect(getTriggerText("[capture:: Bob] testing", 1)).toEqual(["capture:: Bob", 1, 16])
})
expect(getTriggerText("[capture:: Bob] testing", 1)).toEqual([
"capture:: Bob",
1,
16,
]);
});
test("text with markdown link", () => {
expect(getTriggerText("[[[test]]] testing", 1)).toEqual(["[[test]]", 1, 9])
})
expect(getTriggerText("[[[test]]] testing", 1)).toEqual([
"[[test]]",
1,
9,
]);
});
test("text with aliased markdown link", () => {
expect(getTriggerText("[[[test|display]]] testing", 1)).toEqual(["[[test|display]]", 1, 17])
})
expect(getTriggerText("[[[test|display]]] testing", 1)).toEqual([
"[[test|display]]",
1,
17,
]);
});
test("text with wiki link", () => {
expect(getTriggerText("[[[test](https://example.com)]] testing", 1)).toEqual(["[[test](https://example.com)]", 1, 30])
})
expect(
getTriggerText("[[[test](https://example.com)]] testing", 1),
).toEqual(["[[test](https://example.com)]", 1, 30]);
});
test("text with wiki link local", () => {
expect(getTriggerText("[[[test](test)]] testing", 1)).toEqual(["[[test](test)]", 1, 15])
})
})
expect(getTriggerText("[[[test](test)]] testing", 1)).toEqual([
"[[test](test)]",
1,
15,
]);
});
});
describe("cursor position", () => {
test("cursor in first field", () => {
expect(getTriggerText("test (test) string (test2) testing", 9)).toEqual(["test", 6, 10])
})
expect(
getTriggerText("test (test) string (test2) testing", 9),
).toEqual(["test", 6, 10]);
});
test("cursor in second field", () => {
expect(getTriggerText("test (test) string (test2) testing", 21)).toEqual(["test2", 20, 25])
})
expect(
getTriggerText("test (test) string (test2) testing", 21),
).toEqual(["test2", 20, 25]);
});
test("ignore cursor out of field", () => {
expect(getTriggerText("test (test) string (test2) testing", 2)).toEqual(null)
})
})
expect(
getTriggerText("test (test) string (test2) testing", 2),
).toEqual(null);
});
});
describe("ignore plain markdown links", () => {
test("cursor in link text", () => {
expect(getTriggerText("test [test](https://example.com)", 8)).toEqual(null)
})
expect(
getTriggerText("test [test](https://example.com)", 8),
).toEqual(null);
});
test("cursor in link url", () => {
expect(getTriggerText("test [test](https://example.com)", 15)).toEqual(null)
})
expect(
getTriggerText("test [test](https://example.com)", 15),
).toEqual(null);
});
test("cursor in empty link text", () => {
expect(getTriggerText("test [](https://example.com)", 6)).toEqual(null)
})
expect(getTriggerText("test [](https://example.com)", 6)).toEqual(
null,
);
});
test("cursor in empty link url", () => {
expect(getTriggerText("test [test]()", 12)).toEqual(null)
})
})
})
expect(getTriggerText("test [test]()", 12)).toEqual(null);
});
});
});

View File

@@ -1,20 +1,20 @@
/**
* Matches single square bracket pair [] or parahtheses (), but not a double square bracket pair [[]]
* (?<!\[) # Negative lookbehind to make sure there is no second [
* \[] # Matches []
* \[] # Matches []
* (?![\]\(]) # Negative lookahead to make sure there is no second closing ] from wiki link or opening ( from a markdown link
* | # OR
* (?<!\]) # Negative lookbehind to make sure there is no closing ] from a markdown link
* \(\) # Matches ()
*/
const emptyRegex = /(?<!\[)\[](?![\]\(])|(?<!\])\(\)/g
const emptyRegex = /(?<!\[)\[](?![\]\(])|(?<!\])\(\)/g;
/**
* Maches single square brackets or parantheses with some text in them
* and captures the text
* If the brackets start a wiki link or markdown link, they are ignored
* but links inside another layer of brackets are returned:
*
*
* (
* (?<=^\(|\s\() # Pattern for parantheses
* .+?:{0,2}.*?
@@ -25,7 +25,8 @@ const emptyRegex = /(?<!\[)\[](?![\]\(])|(?<!\])\(\)/g
* (?=\]$|\]\s)
* )
*/
const filledRegex = /((?<=^\(|\s\().+?:{0,2}.*?(?=\)$|\)\s)|(?<=^\[|\s\[).+?:{0,2}.*?(?=\]$|\]\s))/g
const filledRegex =
/((?<=^\(|\s\().+?:{0,2}.*?(?=\)$|\)\s)|(?<=^\[|\s\[).+?:{0,2}.*?(?=\]$|\]\s))/g;
/**
* Finds the dataview metadata field the user is currently inside.
@@ -33,38 +34,44 @@ const filledRegex = /((?<=^\(|\s\().+?:{0,2}.*?(?=\)$|\)\s)|(?<=^\[|\s\[).+?:{0,
* and start and end are the cursor positions of the start and end of the field.
* If the user is not inside a field, it returns null.
*/
export function getTriggerText(line: string, cursorPos: number): [string, number, number] | null {
export function getTriggerText(
line: string,
cursorPos: number,
): [string, number, number] | null {
// Check for empty [] or ().
// If the user starts typing with no text in the field, this is the fastest way to find it.
let match = getEmptyTrigger(line, cursorPos)
let match = getEmptyTrigger(line, cursorPos);
if (match) {
return match
return match;
}
// If the user types inside an existing field, this is the function to find it.
match = getTriggerTextFromRegex(line, cursorPos, filledRegex)
match = getTriggerTextFromRegex(line, cursorPos, filledRegex);
if (match !== null) {
return match
return match;
}
return null
return null;
}
/**
* Matches an empty [] or empty (), but not [[]]
* Has its own function since there is no capture group resulting in a different index calculation
*/
function getEmptyTrigger(line: string, cursorPos: number): [string, number, number] | null {
let matches = Array.from(line.matchAll(emptyRegex))
function getEmptyTrigger(
line: string,
cursorPos: number,
): [string, number, number] | null {
let matches = Array.from(line.matchAll(emptyRegex));
for (const match of matches) {
if (match.index === undefined) {
continue
continue;
}
if (cursorPos === match.index+1) {
return ["", match.index+1, match.index+1]
if (cursorPos === match.index + 1) {
return ["", match.index + 1, match.index + 1];
}
}
return null
return null;
}
/**
@@ -74,20 +81,24 @@ function getEmptyTrigger(line: string, cursorPos: number): [string, number, numb
* start is the position of the start of the match, and end is the position of the end of the match.
* Otherwise, returns null.
*/
function getTriggerTextFromRegex(line: string, cursorPos: number, regex: RegExp): [string, number, number] | null {
let matches = Array.from(line.matchAll(regex))
function getTriggerTextFromRegex(
line: string,
cursorPos: number,
regex: RegExp,
): [string, number, number] | null {
let matches = Array.from(line.matchAll(regex));
for (const match of matches) {
if (match.index === undefined) {
continue
continue;
}
const matchStart = match!.index
const matchEnd = matchStart + match[1].length
const cursorInMatch = cursorPos >= matchStart && cursorPos <= matchEnd
const matchStart = match!.index;
const matchEnd = matchStart + match[1].length;
const cursorInMatch = cursorPos >= matchStart && cursorPos <= matchEnd;
if (cursorInMatch) {
return [match[1], matchStart, matchEnd]
return [match[1], matchStart, matchEnd];
}
}
return null
return null;
}

View File

@@ -1,4 +0,0 @@
[
"dataview",
"sample-plugin"
]

View File

@@ -1,11 +0,0 @@
{
"id": "sample-plugin",
"name": "Sample Plugin",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Demonstrates some of the capabilities of the Obsidian API.",
"author": "Obsidian",
"authorUrl": "https://obsidian.md",
"fundingUrl": "https://obsidian.md/pricing",
"isDesktopOnly": false
}

View File

@@ -1,8 +0,0 @@
/*
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.
*/

View File

@@ -1,11 +0,0 @@
{
"id": "dataview",
"name": "Dataview",
"version": "0.5.67",
"minAppVersion": "0.13.11",
"description": "Complex data views for the data-obsessed.",
"author": "Michael Brenan <blacksmithgu@gmail.com>",
"authorUrl": "https://github.com/blacksmithgu",
"helpUrl": "https://blacksmithgu.github.io/obsidian-dataview/",
"isDesktopOnly": false
}

View File

@@ -1,146 +0,0 @@
/** Live Preview padding fixes, specifically for DataviewJS custom HTML elements. */
.is-live-preview .block-language-dataviewjs > p, .is-live-preview .block-language-dataviewjs > span {
line-height: 1.0;
}
.block-language-dataview {
overflow-y: auto;
}
/*****************/
/** Table Views **/
/*****************/
/* List View Default Styling; rendered internally as a table. */
.table-view-table {
width: 100%;
}
.table-view-table > thead > tr, .table-view-table > tbody > tr {
margin-top: 1em;
margin-bottom: 1em;
text-align: left;
}
.table-view-table > tbody > tr:hover {
background-color: var(--table-row-background-hover);
}
.table-view-table > thead > tr > th {
font-weight: 700;
font-size: larger;
border-top: none;
border-left: none;
border-right: none;
border-bottom: solid;
max-width: 100%;
}
.table-view-table > tbody > tr > td {
text-align: left;
border: none;
font-weight: 400;
max-width: 100%;
}
.table-view-table ul, .table-view-table ol {
margin-block-start: 0.2em !important;
margin-block-end: 0.2em !important;
}
/** Rendered value styling for any view. */
.dataview-result-list-root-ul {
padding: 0em !important;
margin: 0em !important;
}
.dataview-result-list-ul {
margin-block-start: 0.2em !important;
margin-block-end: 0.2em !important;
}
/** Generic grouping styling. */
.dataview.result-group {
padding-left: 8px;
}
/*******************/
/** Inline Fields **/
/*******************/
.dataview.inline-field-key {
padding-left: 8px;
padding-right: 8px;
font-family: var(--font-monospace);
background-color: var(--background-primary-alt);
color: var(--text-nav-selected);
}
.dataview.inline-field-value {
padding-left: 8px;
padding-right: 8px;
font-family: var(--font-monospace);
background-color: var(--background-secondary-alt);
color: var(--text-nav-selected);
}
.dataview.inline-field-standalone-value {
padding-left: 8px;
padding-right: 8px;
font-family: var(--font-monospace);
background-color: var(--background-secondary-alt);
color: var(--text-nav-selected);
}
/***************/
/** Task View **/
/***************/
.dataview.task-list-item, .dataview.task-list-basic-item {
margin-top: 3px;
margin-bottom: 3px;
transition: 0.4s;
}
.dataview.task-list-item:hover, .dataview.task-list-basic-item:hover {
background-color: var(--text-selection);
box-shadow: -40px 0 0 var(--text-selection);
cursor: pointer;
}
/*****************/
/** Error Views **/
/*****************/
div.dataview-error-box {
width: 100%;
min-height: 150px;
display: flex;
align-items: center;
justify-content: center;
border: 4px dashed var(--background-secondary);
}
.dataview-error-message {
color: var(--text-muted);
text-align: center;
}
/*************************/
/** Additional Metadata **/
/*************************/
.dataview.small-text {
font-size: smaller;
color: var(--text-muted);
margin-left: 3px;
}
.dataview.small-text::before {
content: "(";
}
.dataview.small-text::after {
content: ")";
}

View File

@@ -1,11 +1,10 @@
(test:: test)
(test::test)
(test:: test)
(test:: test)
(test::)
[test:: test]
[test:: test]
[test:: test]
[test:: [[Moods]]]
[test:: [[Moods|Wiki link display]]]
[test:: [example link](https://example.com)]
[test::Text with [[Moods|wiki link]] and more text]

View File

@@ -1,8 +1,8 @@
{
"compilerOptions": {
"baseUrl": ".",
"sourceMap": true,
"inlineSourceMap": false,
"sourceMap": true,
"inlineSourceMap": false,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
@@ -12,15 +12,7 @@
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7",
"es2020.string"
]
"lib": ["DOM", "ES5", "ES6", "ES7", "es2020.string"]
},
"include": [
"**/*.ts"
]
"include": ["**/*.ts"]
}

View File

@@ -1,3 +1,3 @@
{
"1.0.0": "0.15.0"
"1.0.0": "0.15.0"
}