Merge branch 'master' into develop
# Conflicts: # package.json
This commit is contained in:
144
README.md
144
README.md
@@ -13,6 +13,19 @@ Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/mi
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
https://publish.obsidian.md/omnisearch/Index
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
- Omnisearch is available on [the official Community Plugins repository](https://obsidian.md/plugins?search=Omnisearch).
|
||||||
|
- Beta releases can be installed through [BRAT](https://github.com/TfTHacker/obsidian42-brat). **Be advised that those
|
||||||
|
versions can be buggy and break things.**
|
||||||
|
|
||||||
|
You can check the [CHANGELOG](./CHANGELOG.md) for more information on the different versions.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
> Omnisearch's first goal is to _locate_ files instantly. You can see it as a _Quick Switcher_ on steroids.
|
> Omnisearch's first goal is to _locate_ files instantly. You can see it as a _Quick Switcher_ on steroids.
|
||||||
@@ -37,137 +50,6 @@ Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/mi
|
|||||||
on [this additional plugin](https://github.com/aidenlx/cm-chs-patch). Please read its documentation for more
|
on [this additional plugin](https://github.com/aidenlx/cm-chs-patch). Please read its documentation for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
- Omnisearch is available on [the official Community Plugins repository](https://obsidian.md/plugins?search=Omnisearch).
|
|
||||||
- Beta releases can be installed through [BRAT](https://github.com/TfTHacker/obsidian42-brat). **Be advised that those
|
|
||||||
versions can be buggy and break things.**
|
|
||||||
|
|
||||||
You can check the [CHANGELOG](./CHANGELOG.md) for more information on the different versions.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Omnisearch can be used within 2 different contexts:
|
|
||||||
|
|
||||||
### Vault Search
|
|
||||||
|
|
||||||
Omnisearch's core feature, accessible with the Command Palette "**_Omnisearch: Vault search_**". This modal searches
|
|
||||||
through your vault and returns the most relevant notes. That's all you need to _find_ a note.
|
|
||||||
|
|
||||||
If you want to list all the search matches of a single note, you can do so by using `tab` to open the In-File Search.
|
|
||||||
|
|
||||||
### In-File Search
|
|
||||||
|
|
||||||
Also accessible through the Command Palette "**_Omnisearch: In-file search_**". This modal searches through the active
|
|
||||||
note's content and lists the matching results. Just press enter to automatically scroll to the right place.
|
|
||||||
|
|
||||||
## URL Scheme & Public API
|
|
||||||
|
|
||||||
You can open Omnisearch with the following scheme: `obsidian://omnisearch?query=foo bar`
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
For plugin developers and Dataview users, Omnisearch is also accessible through the global
|
|
||||||
object `omnisearch` (`window.omnisearch`)
|
|
||||||
|
|
||||||
> This API is an experimental feature, the `ResultNote` interface may change in the future. The `search()` function
|
|
||||||
> returns at most 50 results.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// API:
|
|
||||||
type OmnisearchApi = {
|
|
||||||
// Returns a promise that will contain the same results as the Vault modal
|
|
||||||
search: (query: string) => Promise<ResultNoteApi[]>,
|
|
||||||
// Refreshes the index
|
|
||||||
refreshIndex: () => Promise<void>
|
|
||||||
// Register a callback that will be called when the indexing is done
|
|
||||||
registerOnIndexed: (callback: () => void) => void,
|
|
||||||
// Unregister a callback that was previously registered
|
|
||||||
unregisterOnIndexed: (callback: () => void) => void,
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultNoteApi = {
|
|
||||||
score: number
|
|
||||||
path: string
|
|
||||||
basename: string
|
|
||||||
foundWords: string[]
|
|
||||||
matches: SearchMatchApi[]
|
|
||||||
excerpt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SearchMatchApi = {
|
|
||||||
match: string
|
|
||||||
offset: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dataview Integration
|
|
||||||
|
|
||||||
You can use the Omnisearch API directly within the [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) plugin.
|
|
||||||
|
|
||||||
~~~js
|
|
||||||
```dataviewjs
|
|
||||||
const results = await omnisearch.search('your query')
|
|
||||||
const arr = dv.array(results).sort(r => r.score, 'desc')
|
|
||||||
dv.table(['File', 'Score'], arr.map(o => [dv.fileLink(o.path), Math.round(o.score)]))
|
|
||||||
```
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## CSS Customization
|
|
||||||
|
|
||||||
There are several CSS classes you can use to customize the appearance of Omnisearch.
|
|
||||||
|
|
||||||
```css
|
|
||||||
.omnisearch-modal
|
|
||||||
.omnisearch-result
|
|
||||||
.omnisearch-result__title
|
|
||||||
.omnisearch-result__counter
|
|
||||||
.omnisearch-result__body
|
|
||||||
.omnisearch-highlight
|
|
||||||
.omnisearch-input-container
|
|
||||||
.omnisearch-input-field
|
|
||||||
```
|
|
||||||
|
|
||||||
See [styles.css](./assets/styles.css) for more information.
|
|
||||||
|
|
||||||
## Issues & Solutions
|
|
||||||
|
|
||||||
**Omnisearch makes Obsidian sluggish/freeze at startup.**
|
|
||||||
|
|
||||||
- While Omnisearch does its best to work smoothly in the background, bigger vaults and files can make Obsidian stutter
|
|
||||||
during indexing.
|
|
||||||
- If you have several thousands of files, Obsidian may freeze a few seconds at startup while the Omnisearch cache is
|
|
||||||
loaded in memory.
|
|
||||||
|
|
||||||
**Omnisearch seems to make Obsidian slower.**
|
|
||||||
|
|
||||||
- Once Obsidian has indexed your files at startup, it doesn't do anything while its modal is closed. Your changes are
|
|
||||||
not indexed until you open the modal again. If you experience slowdowns while using Obsidian, it's unlikely that
|
|
||||||
Omnisearch is responsible.
|
|
||||||
- However, Text Extractor can make Obsidian slower while indexing PDFs and images for the first time. If you don't need
|
|
||||||
those features, you can disable them in the plugin settings.
|
|
||||||
|
|
||||||
**Omnisearch is slow to index my PDFs and images**
|
|
||||||
|
|
||||||
- The first time Text Extractor reads those files, it can take a long time to extract their text. The results are then
|
|
||||||
cached for the text startup.
|
|
||||||
|
|
||||||
**Omnisearch gives inconsistent/invalid results, there are errors in the developer console**
|
|
||||||
|
|
||||||
- Restart Obsidian to force a reindex of Omnisearch.
|
|
||||||
- The cache could be corrupted; you can clear it at the bottom of the settings page, then restart Obsidian.
|
|
||||||
|
|
||||||
**A query should return a result that does not appear.**
|
|
||||||
|
|
||||||
- If applicable, make sure that "*Ignore diacritics*" is enabled.
|
|
||||||
- If you have modified them, reset weightings to their original values.
|
|
||||||
- Rewrite your query and avoid numbers and common words.
|
|
||||||
|
|
||||||
**I'm still having an issue**
|
|
||||||
|
|
||||||
You can write your issue [here](https://github.com/scambier/obsidian-omnisearch/issues) with as much details as
|
|
||||||
possible.
|
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
Omnisearch is licensed under [GPL-3](https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)).
|
Omnisearch is licensed under [GPL-3](https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "omnisearch",
|
"id": "omnisearch",
|
||||||
"name": "Omnisearch",
|
"name": "Omnisearch",
|
||||||
"version": "1.12.2",
|
"version": "1.13.0-beta.2",
|
||||||
"minAppVersion": "1.0.0",
|
"minAppVersion": "1.0.0",
|
||||||
"description": "A search engine that just works",
|
"description": "A search engine that just works",
|
||||||
"author": "Simon Cambier",
|
"author": "Simon Cambier",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "omnisearch",
|
"id": "omnisearch",
|
||||||
"name": "Omnisearch",
|
"name": "Omnisearch",
|
||||||
"version": "1.12.2",
|
"version": "1.12.3",
|
||||||
"minAppVersion": "1.0.0",
|
"minAppVersion": "1.0.0",
|
||||||
"description": "A search engine that just works",
|
"description": "A search engine that just works",
|
||||||
"author": "Simon Cambier",
|
"author": "Simon Cambier",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
type ResultNote,
|
type ResultNote,
|
||||||
type SearchMatch,
|
type SearchMatch,
|
||||||
} from 'src/globals'
|
} from 'src/globals'
|
||||||
import { loopIndex } from 'src/tools/utils'
|
import { getCtrlKeyLabel, loopIndex } from 'src/tools/utils'
|
||||||
import { onDestroy, onMount, tick } from 'svelte'
|
import { onDestroy, onMount, tick } from 'svelte'
|
||||||
import { MarkdownView } from 'obsidian'
|
import { MarkdownView } from 'obsidian'
|
||||||
import ModalContainer from './ModalContainer.svelte'
|
import ModalContainer from './ModalContainer.svelte'
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
eventBus.enable('infile')
|
eventBus.enable('infile')
|
||||||
|
|
||||||
eventBus.on('infile', 'enter', openSelection)
|
eventBus.on('infile', 'enter', openSelection)
|
||||||
|
eventBus.on('infile', 'open-in-new-pane', openSelectionInNewTab)
|
||||||
eventBus.on('infile', 'arrow-up', () => moveIndex(-1))
|
eventBus.on('infile', 'arrow-up', () => moveIndex(-1))
|
||||||
eventBus.on('infile', 'arrow-down', () => moveIndex(1))
|
eventBus.on('infile', 'arrow-down', () => moveIndex(1))
|
||||||
eventBus.on('infile', 'tab', switchToVaultModal)
|
eventBus.on('infile', 'tab', switchToVaultModal)
|
||||||
@@ -108,15 +109,17 @@
|
|||||||
elem?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
|
elem?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openSelection(
|
async function openSelectionInNewTab(): Promise<void> {
|
||||||
evt?: MouseEvent | KeyboardEvent
|
return openSelection(true)
|
||||||
): Promise<void> {
|
}
|
||||||
|
|
||||||
|
async function openSelection(newTab = false): Promise<void> {
|
||||||
if (note) {
|
if (note) {
|
||||||
modal.close()
|
modal.close()
|
||||||
if (parent) parent.close()
|
if (parent) parent.close()
|
||||||
|
|
||||||
// Open (or switch focus to) the note
|
// Open (or switch focus to) the note
|
||||||
await openNote(note, evt?.ctrlKey)
|
await openNote(note, newTab)
|
||||||
|
|
||||||
// Move cursor to the match
|
// Move cursor to the match
|
||||||
const view = app.workspace.getActiveViewOfType(MarkdownView)
|
const view = app.workspace.getActiveViewOfType(MarkdownView)
|
||||||
@@ -157,7 +160,10 @@
|
|||||||
index="{i}"
|
index="{i}"
|
||||||
selected="{i === selectedIndex}"
|
selected="{i === selectedIndex}"
|
||||||
on:mousemove="{_e => (selectedIndex = i)}"
|
on:mousemove="{_e => (selectedIndex = i)}"
|
||||||
on:click="{openSelection}" />
|
on:click="{evt => openSelection(evt.ctrlKey)}"
|
||||||
|
on:auxclick="{evt => {
|
||||||
|
if (evt.button == 1) openSelection(true)
|
||||||
|
}}" />
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
@@ -174,7 +180,7 @@
|
|||||||
<span class="prompt-instruction-command">↵</span><span>to open</span>
|
<span class="prompt-instruction-command">↵</span><span>to open</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="prompt-instruction">
|
<div class="prompt-instruction">
|
||||||
<span class="prompt-instruction-command">↹</span>
|
<span class="prompt-instruction-command">tab</span>
|
||||||
<span>to switch to Vault Search</span>
|
<span>to switch to Vault Search</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="prompt-instruction">
|
<div class="prompt-instruction">
|
||||||
@@ -185,4 +191,9 @@
|
|||||||
<span>to close</span>
|
<span>to close</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="prompt-instruction">
|
||||||
|
<span class="prompt-instruction-command">{getCtrlKeyLabel()} ↵</span>
|
||||||
|
<span>to open in a new pane</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -266,7 +266,10 @@
|
|||||||
selected="{i === selectedIndex}"
|
selected="{i === selectedIndex}"
|
||||||
note="{result}"
|
note="{result}"
|
||||||
on:mousemove="{_ => (selectedIndex = i)}"
|
on:mousemove="{_ => (selectedIndex = i)}"
|
||||||
on:click="{onClick}" />
|
on:click="{onClick}"
|
||||||
|
on:auxclick="{evt => {
|
||||||
|
if (evt.button == 1) openNoteInNewPane()
|
||||||
|
}}" />
|
||||||
{/each}
|
{/each}
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
{#if !resultNotes.length && searchQuery && !searching}
|
{#if !resultNotes.length && searchQuery && !searching}
|
||||||
@@ -298,12 +301,10 @@
|
|||||||
<span class="prompt-instruction-command">↵</span><span>to open</span>
|
<span class="prompt-instruction-command">↵</span><span>to open</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="prompt-instruction">
|
<div class="prompt-instruction">
|
||||||
<span class="prompt-instruction-command">↹</span>
|
<span class="prompt-instruction-command">tab</span>
|
||||||
<span>to switch to In-File Search</span>
|
<span>to switch to In-File Search</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<div class="prompt-instruction">
|
<div class="prompt-instruction">
|
||||||
<span class="prompt-instruction-command">{getCtrlKeyLabel()} ↵</span>
|
<span class="prompt-instruction-command">{getCtrlKeyLabel()} ↵</span>
|
||||||
<span>to open in a new pane</span>
|
<span>to open in a new pane</span>
|
||||||
@@ -317,8 +318,6 @@
|
|||||||
<span>to create in a new pane</span>
|
<span>to create in a new pane</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<div class="prompt-instruction">
|
<div class="prompt-instruction">
|
||||||
<span class="prompt-instruction-command">alt ↵</span>
|
<span class="prompt-instruction-command">alt ↵</span>
|
||||||
<span>to insert a link</span>
|
<span>to insert a link</span>
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
id="{index.toString()}"
|
id="{index.toString()}"
|
||||||
selected="{selected}"
|
selected="{selected}"
|
||||||
on:mousemove
|
on:mousemove
|
||||||
on:click>
|
on:click
|
||||||
|
on:auxclick>
|
||||||
<div class="omnisearch-result__body">
|
<div class="omnisearch-result__body">
|
||||||
{@html cleanedContent.replace(reg, highlighterGroups)}
|
{@html cleanedContent.replace(reg, highlighterGroups)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
glyph="{glyph}"
|
glyph="{glyph}"
|
||||||
id="{note.path}"
|
id="{note.path}"
|
||||||
on:click
|
on:click
|
||||||
|
on:auxclick
|
||||||
on:mousemove
|
on:mousemove
|
||||||
selected="{selected}">
|
selected="{selected}">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -99,5 +99,8 @@
|
|||||||
"1.12.0": "1.0.0",
|
"1.12.0": "1.0.0",
|
||||||
"1.12.1-beta.1": "1.0.0",
|
"1.12.1-beta.1": "1.0.0",
|
||||||
"1.12.1": "1.0.0",
|
"1.12.1": "1.0.0",
|
||||||
"1.12.2": "1.0.0"
|
"1.12.2": "1.0.0",
|
||||||
|
"1.12.3": "1.0.0",
|
||||||
|
"1.13.0-beta.1": "1.0.0",
|
||||||
|
"1.13.0-beta.2": "1.0.0"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user