Initial commit
This commit is contained in:
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
46
.eslintrc.js
Normal file
46
.eslintrc.js
Normal file
@@ -0,0 +1,46 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: ['standard'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 13,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint'],
|
||||
rules: {
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'arrow-parens': ['error', 'as-needed'],
|
||||
'brace-style': ['error', 'stroustrup', { allowSingleLine: true }],
|
||||
'func-call-spacing': 'off',
|
||||
// unused vars - fix for enums
|
||||
'no-unused-vars': ['off'],
|
||||
'@typescript-eslint/no-unused-vars': ['warn'],
|
||||
// no redeclare - fix for overloading
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': ['error'],
|
||||
// 'simple-import-sort/imports': 'warn',
|
||||
// 'simple-import-sort/exports': 'warn',
|
||||
'@typescript-eslint/func-call-spacing': ['error'],
|
||||
'@typescript-eslint/explicit-function-return-type': [
|
||||
'error',
|
||||
{
|
||||
allowExpressions: true,
|
||||
allowTypedFunctionExpressions: true,
|
||||
allowHigherOrderFunctions: true,
|
||||
allowDirectConstAssertionInArrowFunctions: true,
|
||||
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
|
||||
},
|
||||
],
|
||||
'space-before-function-paren': [
|
||||
'error',
|
||||
{
|
||||
anonymous: 'always',
|
||||
named: 'never',
|
||||
asyncArrow: 'always',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
|
||||
dist
|
||||
.pnpm-debug.log
|
||||
72
README.md
Normal file
72
README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
## Obsidian Sample Plugin
|
||||
|
||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
||||
|
||||
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.
|
||||
|
||||
**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Changes the default font color to red using `styles.css`.
|
||||
- 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.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
|
||||
### First time developing plugins?
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
|
||||
### Releasing new releases
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
|
||||
### Adding your plugin to the community plugin list
|
||||
|
||||
- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
|
||||
### How to use
|
||||
|
||||
- Clone this repo.
|
||||
- `npm i` or `yarn` to install dependencies
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
|
||||
### Manually installing the plugin
|
||||
|
||||
- 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.
|
||||
- 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:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
|
||||
|
||||
### API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
10
assets/manifest.json
Normal file
10
assets/manifest.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "scambier.obsidian-omnisearch",
|
||||
"name": "Omnisearch",
|
||||
"version": "0.0.1",
|
||||
"minAppVersion": "0.14.2",
|
||||
"description": "Search over organization",
|
||||
"author": "Simon Cambier",
|
||||
"authorUrl": "",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
4
assets/styles.css
Normal file
4
assets/styles.css
Normal file
@@ -0,0 +1,4 @@
|
||||
/* Sets all the text color to red! */
|
||||
body {
|
||||
color: red;
|
||||
}
|
||||
66
esbuild.config.mjs
Normal file
66
esbuild.config.mjs
Normal file
@@ -0,0 +1,66 @@
|
||||
import esbuild from 'esbuild'
|
||||
import process from 'process'
|
||||
import builtins from 'builtin-modules'
|
||||
import { copy } from 'esbuild-plugin-copy'
|
||||
import path from 'path'
|
||||
|
||||
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'
|
||||
|
||||
esbuild
|
||||
.build({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ['./src/main.ts'],
|
||||
bundle: true,
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/closebrackets',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/comment',
|
||||
'@codemirror/fold',
|
||||
'@codemirror/gutter',
|
||||
'@codemirror/highlight',
|
||||
'@codemirror/history',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/matchbrackets',
|
||||
'@codemirror/panel',
|
||||
'@codemirror/rangeset',
|
||||
'@codemirror/rectangular-selection',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/stream-parser',
|
||||
'@codemirror/text',
|
||||
'@codemirror/tooltip',
|
||||
'@codemirror/view',
|
||||
...builtins,
|
||||
],
|
||||
outfile: path.join('./dist', 'main.js'),
|
||||
plugins: [
|
||||
copy({
|
||||
// this is equal to process.cwd(), which means we use cwd path as base path to resolve `to` path
|
||||
// if not specified, this plugin uses ESBuild.build outdir/outfile options as base path.
|
||||
assets: {
|
||||
from: ['./assets/*'],
|
||||
to: ['./'],
|
||||
},
|
||||
}),
|
||||
],
|
||||
format: 'cjs',
|
||||
watch: !prod,
|
||||
target: 'chrome98',
|
||||
logLevel: 'info',
|
||||
sourcemap: prod ? false : 'inline',
|
||||
treeShaking: true,
|
||||
})
|
||||
.catch(() => process.exit(1))
|
||||
36
package.json
Normal file
36
package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "scambier.obsidian-search",
|
||||
"version": "0.0.1",
|
||||
"description": "Search over organization",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"builtin-modules": "^3.2.0",
|
||||
"esbuild": "0.13.12",
|
||||
"esbuild-plugin-copy": "^1.2.1",
|
||||
"eslint": "7.12.1",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-node": "11.1.0",
|
||||
"eslint-plugin-promise": "5.0.0",
|
||||
"obsidian": "latest",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier-eslint": "^13.0.0",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"minisearch": "^4.0.3",
|
||||
"remove-markdown": "^0.3.0"
|
||||
}
|
||||
}
|
||||
2152
pnpm-lock.yaml
generated
Normal file
2152
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
115
src/main.ts
Normal file
115
src/main.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { App, Plugin, SuggestModal, TFile } from 'obsidian'
|
||||
import MiniSearch from 'minisearch'
|
||||
import removeMarkdown from 'remove-markdown'
|
||||
|
||||
type OmnisearchMatch = {
|
||||
path: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export default class OmnisearchPlugin extends Plugin {
|
||||
minisearch: MiniSearch<OmnisearchMatch>
|
||||
files: TFile[]
|
||||
contents: Record<string, string>
|
||||
|
||||
async onload(): Promise<void> {
|
||||
this.contents = {}
|
||||
this.minisearch = new MiniSearch<OmnisearchMatch>({
|
||||
idField: 'path',
|
||||
fields: ['content', 'title'],
|
||||
storeFields: ['path'],
|
||||
extractField: (document, fieldName) => {
|
||||
if (fieldName === 'title') return getNoteTitle(document.content)
|
||||
return (document as any)[fieldName] as string
|
||||
},
|
||||
})
|
||||
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
this.files = this.app.vault.getMarkdownFiles()
|
||||
for (const file of this.files) {
|
||||
const content = await this.app.vault.cachedRead(file)
|
||||
this.contents[file.path] = truncateBody(getNoteBody(content))
|
||||
this.minisearch.add({ content, path: file.path })
|
||||
}
|
||||
console.log('minisearch loaded')
|
||||
console.log(this.files.length + ' notes')
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: 'show-modal',
|
||||
name: 'Open Omnisearch',
|
||||
hotkeys: [{ modifiers: ['Mod'], key: 'o' }],
|
||||
callback: () => {
|
||||
new OmnisearchModal(this).open()
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class OmnisearchModal extends SuggestModal<OmnisearchMatch> {
|
||||
plugin: OmnisearchPlugin
|
||||
|
||||
constructor(plugin: OmnisearchPlugin) {
|
||||
super(plugin.app)
|
||||
this.plugin = plugin
|
||||
}
|
||||
|
||||
getSuggestions(query: string): OmnisearchMatch[] {
|
||||
const results = this.plugin.minisearch.search(query, {
|
||||
prefix: true,
|
||||
fuzzy: term => (term.length > 4 ? 0.2 : false),
|
||||
combineWith: 'AND',
|
||||
// processTerm: term => term.length <= minLength ? false : term,
|
||||
boost: { title: 2 },
|
||||
})
|
||||
return results.map(result => {
|
||||
const file = this.plugin.files.find(f => f.path === result.id)
|
||||
return {
|
||||
path: file.path,
|
||||
content: this.plugin.contents[file.path],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
renderSuggestion(value: OmnisearchMatch, el: HTMLElement) {
|
||||
el.createEl('div', { text: value.path })
|
||||
el.createEl('small', { text: value.content })
|
||||
}
|
||||
|
||||
onChooseSuggestion(item: OmnisearchMatch, evt: MouseEvent | KeyboardEvent) {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
}
|
||||
|
||||
function truncateBody(body: string): string {
|
||||
return body.substring(0, 200) + (body.length > 0 ? '...' : '')
|
||||
}
|
||||
function getNoteTitle(note: string): string {
|
||||
return getFirstLine(removeMd(note))
|
||||
}
|
||||
function getNoteBody(contents: string): string {
|
||||
return truncateFirstLine(removeMd(contents))
|
||||
}
|
||||
|
||||
function getFirstLine(text: string): string {
|
||||
return splitLines(text.trim())[0]
|
||||
}
|
||||
function splitLines(text: string): string[] {
|
||||
return text.split(/\r?\n|\r/)
|
||||
}
|
||||
|
||||
function removeMd(text: string): string {
|
||||
return removeMarkdown(removeFrontMatter(text))
|
||||
}
|
||||
function removeFrontMatter(text: string): string {
|
||||
// Regex to recognize YAML Front Matter (at beginning of file, 3 hyphens, than any charecter, including newlines, then 3 hyphens).
|
||||
const YAMLFrontMatter = /^---\s*\n(.*?)\n?^---\s?/ms
|
||||
return text.replace(YAMLFrontMatter, '')
|
||||
}
|
||||
|
||||
function truncateFirstLine(text: string): string {
|
||||
// https://stackoverflow.com/questions/2528076/delete-a-line-of-text-in-javascript
|
||||
const lines = splitLines(text.trim())
|
||||
lines.splice(0, 1)
|
||||
return lines.join('\n')
|
||||
}
|
||||
1
src/modules.d.ts
vendored
Normal file
1
src/modules.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'remove-markdown'
|
||||
4
src/styles.css
Normal file
4
src/styles.css
Normal file
@@ -0,0 +1,4 @@
|
||||
/* Sets all the text color to red! */
|
||||
body {
|
||||
color: red;
|
||||
}
|
||||
23
tsconfig.json
Normal file
23
tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
14
version-bump.mjs
Normal file
14
version-bump.mjs
Normal file
@@ -0,0 +1,14 @@
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
4
versions.json
Normal file
4
versions.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"1.0.0": "0.9.7",
|
||||
"1.0.1": "0.12.0"
|
||||
}
|
||||
Reference in New Issue
Block a user