Merge branch 'develop'
This commit is contained in:
30
.github/workflows/release.yml
vendored
30
.github/workflows/release.yml
vendored
@@ -14,17 +14,20 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v2.1.0
|
|
||||||
with:
|
with:
|
||||||
version: 7.17.0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9.3.0
|
||||||
run_install: true
|
run_install: true
|
||||||
|
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "18.x"
|
cache: 'pnpm'
|
||||||
|
node-version: "20.x"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: build
|
id: build
|
||||||
@@ -37,6 +40,18 @@ jobs:
|
|||||||
ls
|
ls
|
||||||
echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)"
|
echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)"
|
||||||
|
|
||||||
|
- name: Generate a changelog
|
||||||
|
uses: orhun/git-cliff-action@v3
|
||||||
|
id: git-cliff
|
||||||
|
with:
|
||||||
|
config: cliff.toml
|
||||||
|
args: --verbose
|
||||||
|
env:
|
||||||
|
GITHUB_REPO: ${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Print the changelog
|
||||||
|
run: cat "${{ steps.git-cliff.outputs.changelog }}"
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
@@ -46,7 +61,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
release_name: ${{ github.ref }}
|
release_name: ${{ github.ref }}
|
||||||
draft: false
|
body: ${{ steps.git-cliff.outputs.changelog }}
|
||||||
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
- name: Upload zip file
|
- name: Upload zip file
|
||||||
|
|||||||
12
cliff.toml
Normal file
12
cliff.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[changelog]
|
||||||
|
header = "Changelog"
|
||||||
|
body = """
|
||||||
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
|
### {{ group | upper_first }}
|
||||||
|
{% for commit in commits %}
|
||||||
|
- {{ commit.message | upper_first }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
"""
|
||||||
|
trim = true
|
||||||
|
footer = "<!-- generated by git-cliff -->"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "scambier.obsidian-search",
|
"name": "scambier.obsidian-search",
|
||||||
"version": "1.23.1",
|
"version": "1.24.0-beta.3",
|
||||||
"description": "A search engine for Obsidian",
|
"description": "A search engine for Obsidian",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -52,6 +52,5 @@
|
|||||||
"overrides": {
|
"overrides": {
|
||||||
"moment@>=2.18.0 <2.29.4": ">=2.29.4"
|
"moment@>=2.18.0 <2.29.4": ">=2.29.4"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"packageManager": "pnpm@9.1.0+sha512.67f5879916a9293e5cf059c23853d571beaf4f753c707f40cb22bed5fb1578c6aad3b6c4107ccb3ba0b35be003eb621a16471ac836c87beb53f9d54bb4612724"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ describe('The Query class', () => {
|
|||||||
|
|
||||||
it('should correctly parse string queries', () => {
|
it('should correctly parse string queries', () => {
|
||||||
// Act
|
// Act
|
||||||
const query = new Query(stringQuery, { ignoreDiacritics: true })
|
const query = new Query(stringQuery, {
|
||||||
|
ignoreDiacritics: true,
|
||||||
|
ignoreArabicDiacritics: true,
|
||||||
|
})
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
const segments = query.query.text
|
const segments = query.query.text
|
||||||
@@ -25,7 +28,10 @@ describe('The Query class', () => {
|
|||||||
|
|
||||||
it('should not exclude words when there is no space before', () => {
|
it('should not exclude words when there is no space before', () => {
|
||||||
// Act
|
// Act
|
||||||
const query = new Query('foo bar-baz', { ignoreDiacritics: true })
|
const query = new Query('foo bar-baz', {
|
||||||
|
ignoreDiacritics: true,
|
||||||
|
ignoreArabicDiacritics: true,
|
||||||
|
})
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(query.query.exclude.text).toHaveLength(0)
|
expect(query.query.exclude.text).toHaveLength(0)
|
||||||
@@ -34,7 +40,10 @@ describe('The Query class', () => {
|
|||||||
describe('.getExactTerms()', () => {
|
describe('.getExactTerms()', () => {
|
||||||
it('should an array of strings containg "exact" values', () => {
|
it('should an array of strings containg "exact" values', () => {
|
||||||
// Act
|
// Act
|
||||||
const query = new Query(stringQuery, { ignoreDiacritics: true })
|
const query = new Query(stringQuery, {
|
||||||
|
ignoreDiacritics: true,
|
||||||
|
ignoreArabicDiacritics: true,
|
||||||
|
})
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(query.getExactTerms()).toEqual(['lorem ipsum', 'sit amet'])
|
expect(query.getExactTerms()).toEqual(['lorem ipsum', 'sit amet'])
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
getAliasesFromMetadata,
|
getAliasesFromMetadata,
|
||||||
getTagsFromMetadata,
|
getTagsFromMetadata,
|
||||||
isFileCanvas,
|
isFileCanvas,
|
||||||
isFileFromDataloomPlugin,
|
isFileFromDataloom,
|
||||||
isFileImage,
|
isFileImage,
|
||||||
isFileOffice,
|
isFileOffice,
|
||||||
isFilePDF,
|
isFilePDF,
|
||||||
@@ -136,7 +136,7 @@ export class CacheManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ** Dataloom plugin **
|
// ** Dataloom plugin **
|
||||||
else if (isFileFromDataloomPlugin(path)) {
|
else if (isFileFromDataloom(path)) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(await app.vault.cachedRead(file))
|
const data = JSON.parse(await app.vault.cachedRead(file))
|
||||||
// data is a json object, we recursively iterate the keys
|
// data is a json object, we recursively iterate the keys
|
||||||
@@ -230,10 +230,11 @@ export class CacheManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const displayTitle = metadata?.frontmatter?.[this.plugin.settings.displayTitle] ?? ''
|
||||||
const tags = getTagsFromMetadata(metadata)
|
const tags = getTagsFromMetadata(metadata)
|
||||||
return {
|
return {
|
||||||
basename: file.basename,
|
basename: file.basename,
|
||||||
|
displayTitle,
|
||||||
content,
|
content,
|
||||||
/** Content without diacritics and markdown chars */
|
/** Content without diacritics and markdown chars */
|
||||||
cleanedContent: stripMarkdownCharacters(removeDiacritics(content)),
|
cleanedContent: stripMarkdownCharacters(removeDiacritics(content)),
|
||||||
|
|||||||
@@ -141,6 +141,7 @@
|
|||||||
}
|
}
|
||||||
query = new Query(searchQuery, {
|
query = new Query(searchQuery, {
|
||||||
ignoreDiacritics: plugin.settings.ignoreDiacritics,
|
ignoreDiacritics: plugin.settings.ignoreDiacritics,
|
||||||
|
ignoreArabicDiacritics: plugin.settings.ignoreArabicDiacritics,
|
||||||
})
|
})
|
||||||
cancelableQuery = cancelable(
|
cancelableQuery = cancelable(
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import type { ResultNote } from '../globals'
|
import type { ResultNote } from '../globals'
|
||||||
import {
|
import {
|
||||||
getExtension,
|
getExtension,
|
||||||
isFileCanvas,
|
isFileCanvas, isFileExcalidraw,
|
||||||
isFileImage,
|
isFileImage,
|
||||||
isFilePDF,
|
isFilePDF,
|
||||||
pathWithoutFilename,
|
pathWithoutFilename,
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
$: cleanedContent = plugin.textProcessor.makeExcerpt(note.content, note.matches[0]?.offset ?? -1)
|
$: cleanedContent = plugin.textProcessor.makeExcerpt(note.content, note.matches[0]?.offset ?? -1)
|
||||||
$: glyph = false //cacheManager.getLiveDocument(note.path)?.doesNotExist
|
$: glyph = false //cacheManager.getLiveDocument(note.path)?.doesNotExist
|
||||||
$: {
|
$: {
|
||||||
title = note.basename
|
title = note.displayTitle || note.basename
|
||||||
notePath = pathWithoutFilename(note.path)
|
notePath = pathWithoutFilename(note.path)
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
@@ -44,11 +44,18 @@
|
|||||||
setIcon(elFolderPathIcon, 'folder-open')
|
setIcon(elFolderPathIcon, 'folder-open')
|
||||||
}
|
}
|
||||||
if (elFilePathIcon) {
|
if (elFilePathIcon) {
|
||||||
if (isFileImage(note.path)) setIcon(elFilePathIcon, 'image')
|
if (isFileImage(note.path)) {
|
||||||
else if (isFilePDF(note.path)) setIcon(elFilePathIcon, 'file-text')
|
setIcon(elFilePathIcon, 'image')
|
||||||
else if (isFileCanvas(note.path))
|
}
|
||||||
|
else if (isFilePDF(note.path)) {
|
||||||
|
setIcon(elFilePathIcon, 'file-text')
|
||||||
|
}
|
||||||
|
else if (isFileCanvas(note.path) || isFileExcalidraw(note.path)) {
|
||||||
setIcon(elFilePathIcon, 'layout-dashboard')
|
setIcon(elFilePathIcon, 'layout-dashboard')
|
||||||
else setIcon(elFilePathIcon, 'file')
|
}
|
||||||
|
else {
|
||||||
|
setIcon(elFilePathIcon, 'file')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ abstract class OmnisearchModal extends Modal {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Open in background
|
// Open in background
|
||||||
this.scope.register(['Alt'], 'O', e => {
|
this.scope.register(['Ctrl'], 'O', e => {
|
||||||
if (!isInputComposition()) {
|
if (!isInputComposition()) {
|
||||||
// Check if the user is still typing
|
// Check if the user is still typing
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export type DocumentRef = { path: string; mtime: number }
|
|||||||
export type IndexedDocument = {
|
export type IndexedDocument = {
|
||||||
path: string
|
path: string
|
||||||
basename: string
|
basename: string
|
||||||
|
displayTitle: string
|
||||||
mtime: number
|
mtime: number
|
||||||
|
|
||||||
content: string
|
content: string
|
||||||
@@ -76,6 +77,7 @@ export type ResultNote = {
|
|||||||
score: number
|
score: number
|
||||||
path: string
|
path: string
|
||||||
basename: string
|
basename: string
|
||||||
|
displayTitle: string
|
||||||
content: string
|
content: string
|
||||||
foundWords: string[]
|
foundWords: string[]
|
||||||
matches: SearchMatch[]
|
matches: SearchMatch[]
|
||||||
|
|||||||
17
src/main.ts
17
src/main.ts
@@ -138,7 +138,9 @@ export default class OmnisearchPlugin extends Plugin {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
this.refreshIndexCallback = this.notesIndexer.refreshIndex.bind(this.notesIndexer)
|
this.refreshIndexCallback = this.notesIndexer.refreshIndex.bind(
|
||||||
|
this.notesIndexer
|
||||||
|
)
|
||||||
addEventListener('blur', this.refreshIndexCallback)
|
addEventListener('blur', this.refreshIndexCallback)
|
||||||
removeEventListener
|
removeEventListener
|
||||||
|
|
||||||
@@ -272,15 +274,20 @@ export default class OmnisearchPlugin extends Plugin {
|
|||||||
indexingStep.set(IndexingStepType.WritingCache)
|
indexingStep.set(IndexingStepType.WritingCache)
|
||||||
|
|
||||||
// Disable settings.useCache while writing the cache, in case it freezes
|
// Disable settings.useCache while writing the cache, in case it freezes
|
||||||
this.settings.useCache = false
|
const cacheEnabled = this.settings.useCache
|
||||||
await saveSettings(this)
|
if (cacheEnabled && !this.settings.DANGER_forceSaveCache) {
|
||||||
|
this.settings.useCache = false
|
||||||
|
await saveSettings(this)
|
||||||
|
}
|
||||||
|
|
||||||
// Write the cache
|
// Write the cache
|
||||||
await searchEngine.writeToCache()
|
await searchEngine.writeToCache()
|
||||||
|
|
||||||
// Re-enable settings.caching
|
// Re-enable settings.caching
|
||||||
this.settings.useCache = true
|
if (cacheEnabled) {
|
||||||
await saveSettings(this)
|
this.settings.useCache = true
|
||||||
|
await saveSettings(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.timeEnd('Omnisearch - Indexing total time')
|
console.timeEnd('Omnisearch - Indexing total time')
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { removeAnchors } from './tools/notes'
|
|||||||
import type { IndexedDocument } from './globals'
|
import type { IndexedDocument } from './globals'
|
||||||
import {
|
import {
|
||||||
isFileCanvas,
|
isFileCanvas,
|
||||||
isFileFromDataloomPlugin,
|
isFileFromDataloom,
|
||||||
isFileImage,
|
isFileImage,
|
||||||
isFilePDF,
|
isFilePDF,
|
||||||
logDebug,
|
logDebug,
|
||||||
@@ -51,7 +51,7 @@ export class NotesIndexer {
|
|||||||
return (
|
return (
|
||||||
this.isFilePlaintext(path) ||
|
this.isFilePlaintext(path) ||
|
||||||
isFileCanvas(path) ||
|
isFileCanvas(path) ||
|
||||||
isFileFromDataloomPlugin(path) ||
|
isFileFromDataloom(path) ||
|
||||||
(canIndexPDF && isFilePDF(path)) ||
|
(canIndexPDF && isFilePDF(path)) ||
|
||||||
(canIndexImages && isFileImage(path)) ||
|
(canIndexImages && isFileImage(path)) ||
|
||||||
(canIndexImagesAI && isFileImage(path))
|
(canIndexImagesAI && isFileImage(path))
|
||||||
@@ -63,7 +63,7 @@ export class NotesIndexer {
|
|||||||
this.canIndexUnsupportedFiles() ||
|
this.canIndexUnsupportedFiles() ||
|
||||||
this.isFilePlaintext(path) ||
|
this.isFilePlaintext(path) ||
|
||||||
isFileCanvas(path) ||
|
isFileCanvas(path) ||
|
||||||
isFileFromDataloomPlugin(path)
|
isFileFromDataloom(path)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +91,7 @@ export class NotesIndexer {
|
|||||||
return {
|
return {
|
||||||
path: filename,
|
path: filename,
|
||||||
basename: name,
|
basename: name,
|
||||||
|
displayTitle: '',
|
||||||
mtime: 0,
|
mtime: 0,
|
||||||
|
|
||||||
content: '',
|
content: '',
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ export class Query {
|
|||||||
}
|
}
|
||||||
#inQuotes: string[]
|
#inQuotes: string[]
|
||||||
|
|
||||||
constructor(text = '', options: { ignoreDiacritics: boolean }) {
|
constructor(text = '', options: { ignoreDiacritics: boolean, ignoreArabicDiacritics: boolean}) {
|
||||||
if (options.ignoreDiacritics) {
|
if (options.ignoreDiacritics) {
|
||||||
text = removeDiacritics(text)
|
text = removeDiacritics(text, options.ignoreArabicDiacritics)
|
||||||
}
|
}
|
||||||
const parsed = parse(text.toLowerCase(), {
|
const parsed = parse(text.toLowerCase(), {
|
||||||
tokenize: true,
|
tokenize: true,
|
||||||
|
|||||||
@@ -154,8 +154,9 @@ export class SearchEngine {
|
|||||||
term.length <= 3 ? 0 : term.length <= 5 ? fuzziness / 2 : fuzziness,
|
term.length <= 3 ? 0 : term.length <= 5 ? fuzziness / 2 : fuzziness,
|
||||||
boost: {
|
boost: {
|
||||||
basename: settings.weightBasename,
|
basename: settings.weightBasename,
|
||||||
directory: settings.weightDirectory,
|
|
||||||
aliases: settings.weightBasename,
|
aliases: settings.weightBasename,
|
||||||
|
displayTitle: settings.weightBasename,
|
||||||
|
directory: settings.weightDirectory,
|
||||||
headings1: settings.weightH1,
|
headings1: settings.weightH1,
|
||||||
headings2: settings.weightH2,
|
headings2: settings.weightH2,
|
||||||
headings3: settings.weightH3,
|
headings3: settings.weightH3,
|
||||||
@@ -304,7 +305,12 @@ export class SearchEngine {
|
|||||||
const title = document?.path.toLowerCase() ?? ''
|
const title = document?.path.toLowerCase() ?? ''
|
||||||
const content = (document?.cleanedContent ?? '').toLowerCase()
|
const content = (document?.cleanedContent ?? '').toLowerCase()
|
||||||
return exactTerms.every(
|
return exactTerms.every(
|
||||||
q => content.includes(q) || removeDiacritics(title).includes(q)
|
q =>
|
||||||
|
content.includes(q) ||
|
||||||
|
removeDiacritics(
|
||||||
|
title,
|
||||||
|
this.plugin.settings.ignoreArabicDiacritics
|
||||||
|
).includes(q)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -434,7 +440,7 @@ export class SearchEngine {
|
|||||||
},
|
},
|
||||||
processTerm: (term: string) =>
|
processTerm: (term: string) =>
|
||||||
(this.plugin.settings.ignoreDiacritics
|
(this.plugin.settings.ignoreDiacritics
|
||||||
? removeDiacritics(term)
|
? removeDiacritics(term, this.plugin.settings.ignoreArabicDiacritics)
|
||||||
: term
|
: term
|
||||||
).toLowerCase(),
|
).toLowerCase(),
|
||||||
idField: 'path',
|
idField: 'path',
|
||||||
|
|||||||
@@ -15,36 +15,41 @@ export class Tokenizer {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public tokenizeForIndexing(text: string): string[] {
|
public tokenizeForIndexing(text: string): string[] {
|
||||||
const words = this.tokenizeWords(text)
|
try {
|
||||||
let urls: string[] = []
|
const words = this.tokenizeWords(text)
|
||||||
if (this.plugin.settings.tokenizeUrls) {
|
let urls: string[] = []
|
||||||
try {
|
if (this.plugin.settings.tokenizeUrls) {
|
||||||
urls = markdownLinkExtractor(text)
|
try {
|
||||||
} catch (e) {
|
urls = markdownLinkExtractor(text)
|
||||||
logDebug('Error extracting urls', e)
|
} catch (e) {
|
||||||
|
logDebug('Error extracting urls', e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tokens = this.tokenizeTokens(text, { skipChs: true })
|
||||||
|
|
||||||
|
// Split hyphenated tokens
|
||||||
|
tokens = [...tokens, ...tokens.flatMap(splitHyphens)]
|
||||||
|
|
||||||
|
// Split camelCase tokens into "camel" and "case
|
||||||
|
tokens = [...tokens, ...tokens.flatMap(splitCamelCase)]
|
||||||
|
|
||||||
|
// Add whole words (aka "not tokens")
|
||||||
|
tokens = [...tokens, ...words]
|
||||||
|
|
||||||
|
// Add urls
|
||||||
|
if (urls.length) {
|
||||||
|
tokens = [...tokens, ...urls]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
tokens = [...new Set(tokens)]
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error tokenizing text, skipping document', e)
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
let tokens = this.tokenizeTokens(text, { skipChs: true })
|
|
||||||
|
|
||||||
// Split hyphenated tokens
|
|
||||||
tokens = [...tokens, ...tokens.flatMap(splitHyphens)]
|
|
||||||
|
|
||||||
// Split camelCase tokens into "camel" and "case
|
|
||||||
tokens = [...tokens, ...tokens.flatMap(splitCamelCase)]
|
|
||||||
|
|
||||||
// Add whole words (aka "not tokens")
|
|
||||||
tokens = [...tokens, ...words]
|
|
||||||
|
|
||||||
// Add urls
|
|
||||||
if (urls.length) {
|
|
||||||
tokens = [...tokens, ...urls]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove duplicates
|
|
||||||
tokens = [...new Set(tokens)]
|
|
||||||
|
|
||||||
return tokens
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
190
src/settings.ts
190
src/settings.ts
@@ -11,7 +11,8 @@ import {
|
|||||||
import { writable } from 'svelte/store'
|
import { writable } from 'svelte/store'
|
||||||
import { K_DISABLE_OMNISEARCH } from './globals'
|
import { K_DISABLE_OMNISEARCH } from './globals'
|
||||||
import type OmnisearchPlugin from './main'
|
import type OmnisearchPlugin from './main'
|
||||||
import { enablePrintDebug } from "./tools/utils";
|
import { enablePrintDebug } from './tools/utils'
|
||||||
|
import { debounce } from 'lodash-es'
|
||||||
|
|
||||||
interface WeightingSettings {
|
interface WeightingSettings {
|
||||||
weightBasename: number
|
weightBasename: number
|
||||||
@@ -32,8 +33,12 @@ export interface OmnisearchSettings extends WeightingSettings {
|
|||||||
downrankedFoldersFilters: string[]
|
downrankedFoldersFilters: string[]
|
||||||
/** Ignore diacritics when indexing files */
|
/** Ignore diacritics when indexing files */
|
||||||
ignoreDiacritics: boolean
|
ignoreDiacritics: boolean
|
||||||
|
ignoreArabicDiacritics: boolean
|
||||||
|
|
||||||
/** Extensions of plain text files to index, in addition to .md */
|
/** Extensions of plain text files to index, in addition to .md */
|
||||||
indexedFileTypes: string[]
|
indexedFileTypes: string[]
|
||||||
|
/** Custom title field */
|
||||||
|
displayTitle: string
|
||||||
/** Enable PDF indexing */
|
/** Enable PDF indexing */
|
||||||
PDFIndexing: boolean
|
PDFIndexing: boolean
|
||||||
/** Enable Images indexing */
|
/** Enable Images indexing */
|
||||||
@@ -71,6 +76,7 @@ export interface OmnisearchSettings extends WeightingSettings {
|
|||||||
httpApiNotice: boolean
|
httpApiNotice: boolean
|
||||||
|
|
||||||
DANGER_httpHost: string | null
|
DANGER_httpHost: string | null
|
||||||
|
DANGER_forceSaveCache: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,6 +103,11 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
const { containerEl } = this
|
const { containerEl } = this
|
||||||
const database = this.plugin.database
|
const database = this.plugin.database
|
||||||
const textExtractor = this.plugin.getTextExtractor()
|
const textExtractor = this.plugin.getTextExtractor()
|
||||||
|
|
||||||
|
const clearCacheDebounced = debounce(async () => {
|
||||||
|
await database.clearCache()
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
const aiImageAnalyzer = this.plugin.getAIImageAnalyzer()
|
const aiImageAnalyzer = this.plugin.getAIImageAnalyzer()
|
||||||
containerEl.empty()
|
containerEl.empty()
|
||||||
|
|
||||||
@@ -138,18 +149,24 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Indexing')
|
.setName('Indexing')
|
||||||
.setHeading()
|
.setHeading()
|
||||||
.setDesc(indexingDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`⚠️ <span style="color: var(--text-accent)">Changing indexing settings will clear the cache, and requires a restart of Obsidian.</span><br/><br/>
|
||||||
|
${
|
||||||
|
textExtractor
|
||||||
|
? `👍 You have installed <a href="https://github.com/scambier/obsidian-text-extractor">Text Extractor</a>, Omnisearch can use it to index PDFs and images contents.
|
||||||
|
<br />Text extraction only works on desktop, but the cache can be synchronized with your mobile device.`
|
||||||
|
: `⚠️ Omnisearch requires <a href="https://github.com/scambier/obsidian-text-extractor">Text Extractor</a> to index PDFs and images.`
|
||||||
|
}`)
|
||||||
|
)
|
||||||
|
|
||||||
// PDF Indexing
|
// PDF Indexing
|
||||||
const indexPDFsDesc = new DocumentFragment()
|
|
||||||
indexPDFsDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Omnisearch will use Text Extractor to index the content of your PDFs.`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(
|
.setName(`PDFs content indexing ${textExtractor ? '' : '⚠️ Disabled'}`)
|
||||||
`PDFs content indexing ${textExtractor ? '' : '⚠️ Disabled'}`
|
.setDesc(
|
||||||
|
htmlDescription(
|
||||||
|
`Omnisearch will use Text Extractor to index the content of your PDFs.`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.setDesc(indexPDFsDesc)
|
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle.setValue(settings.PDFIndexing).onChange(async v => {
|
toggle.setValue(settings.PDFIndexing).onChange(async v => {
|
||||||
await database.clearCache()
|
await database.clearCache()
|
||||||
@@ -160,13 +177,13 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
.setDisabled(!textExtractor)
|
.setDisabled(!textExtractor)
|
||||||
|
|
||||||
// Images Indexing
|
// Images Indexing
|
||||||
const indexImagesDesc = new DocumentFragment()
|
|
||||||
indexImagesDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Omnisearch will use Text Extractor to OCR your images and index their content.`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(`Images OCR indexing ${textExtractor ? '' : '⚠️ Disabled'}`)
|
.setName(`Images OCR indexing ${textExtractor ? '' : '⚠️ Disabled'}`)
|
||||||
.setDesc(indexImagesDesc)
|
.setDesc(
|
||||||
|
htmlDescription(
|
||||||
|
`Omnisearch will use Text Extractor to OCR your images and index their content.`
|
||||||
|
)
|
||||||
|
)
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle.setValue(settings.imagesIndexing).onChange(async v => {
|
toggle.setValue(settings.imagesIndexing).onChange(async v => {
|
||||||
await database.clearCache()
|
await database.clearCache()
|
||||||
@@ -213,38 +230,49 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
.setDisabled(!aiImageAnalyzer)
|
.setDisabled(!aiImageAnalyzer)
|
||||||
|
|
||||||
// Index filenames of unsupported files
|
// Index filenames of unsupported files
|
||||||
const indexUnsupportedDesc = new DocumentFragment()
|
|
||||||
indexUnsupportedDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `
|
|
||||||
Omnisearch can index file<strong>names</strong> of "unsupported" files, such as e.g. <pre style="display:inline">.mp4</pre>
|
|
||||||
or non-extracted PDFs & images.<br/>
|
|
||||||
"Obsidian setting" will respect the value of "Files & Links > Detect all file extensions".`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Index paths of unsupported files')
|
.setName('Index paths of unsupported files')
|
||||||
.setDesc(indexUnsupportedDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`
|
||||||
|
Omnisearch can index file<strong>names</strong> of "unsupported" files, such as e.g. <pre style="display:inline">.mp4</pre>
|
||||||
|
or non-extracted PDFs & images.<br/>
|
||||||
|
"Obsidian setting" will respect the value of "Files & Links > Detect all file extensions".`)
|
||||||
|
)
|
||||||
.addDropdown(dropdown => {
|
.addDropdown(dropdown => {
|
||||||
dropdown
|
dropdown
|
||||||
.addOptions({ yes: 'Yes', no: 'No', default: 'Obsidian setting' })
|
.addOptions({ yes: 'Yes', no: 'No', default: 'Obsidian setting' })
|
||||||
.setValue(settings.unsupportedFilesIndexing)
|
.setValue(settings.unsupportedFilesIndexing)
|
||||||
.onChange(async v => {
|
.onChange(async v => {
|
||||||
await database.clearCache()
|
await clearCacheDebounced()
|
||||||
;(settings.unsupportedFilesIndexing as any) = v
|
;(settings.unsupportedFilesIndexing as any) = v
|
||||||
await saveSettings(this.plugin)
|
await saveSettings(this.plugin)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Custom display title
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Set frontmatter property key as title')
|
||||||
|
.setDesc(
|
||||||
|
htmlDescription(`If you have a custom property in your notes that you want to use as the title in search results.<br>
|
||||||
|
Leave empty to disable.`)
|
||||||
|
)
|
||||||
|
.addText(component => {
|
||||||
|
component.setValue(settings.displayTitle).onChange(async v => {
|
||||||
|
await clearCacheDebounced()
|
||||||
|
settings.displayTitle = v
|
||||||
|
await saveSettings(this.plugin)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// Additional text files to index
|
// Additional text files to index
|
||||||
const indexedFileTypesDesc = new DocumentFragment()
|
|
||||||
indexedFileTypesDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `In addition to standard <code>md</code> files, Omnisearch can also index other <strong style="color: var(--text-accent)">PLAINTEXT</strong> files.<br/>
|
|
||||||
Add extensions separated by a space, without the dot. Example: "<code>txt org csv</code>".<br />
|
|
||||||
⚠️ <span style="color: var(--text-accent)">Using extensions of non-plaintext files (like .pptx) WILL cause crashes,
|
|
||||||
because Omnisearch will try to index their content.</span>`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Additional TEXT files to index')
|
.setName('Additional TEXT files to index')
|
||||||
.setDesc(indexedFileTypesDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`In addition to standard <code>md</code> files, Omnisearch can also index other <strong style="color: var(--text-accent)">PLAINTEXT</strong> files.<br/>
|
||||||
|
Add extensions separated by a space, without the dot. Example: "<code>txt org csv</code>".<br />
|
||||||
|
⚠️ <span style="color: var(--text-accent)">Using extensions of non-plaintext files (like .pptx) WILL cause crashes,
|
||||||
|
because Omnisearch will try to index their content.</span>`)
|
||||||
|
)
|
||||||
.addText(component => {
|
.addText(component => {
|
||||||
component
|
component
|
||||||
.setValue(settings.indexedFileTypes.join(' '))
|
.setValue(settings.indexedFileTypes.join(' '))
|
||||||
@@ -319,16 +347,13 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Split CamelCaseWords
|
// Split CamelCaseWords
|
||||||
const camelCaseDesc = new DocumentFragment()
|
|
||||||
camelCaseDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Enable this if you want to be able to search for CamelCaseWords as separate words.<br/>
|
|
||||||
⚠️ <span style="color: var(--text-accent)">Changing this setting will clear the cache.</span><br>
|
|
||||||
${needsARestart}
|
|
||||||
`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Split CamelCaseWords')
|
.setName('Split CamelCaseWords')
|
||||||
.setDesc(camelCaseDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`Enable this if you want to be able to search for CamelCaseWords as separate words.<br/>
|
||||||
|
⚠️ <span style="color: var(--text-accent)">Changing this setting will clear the cache.</span><br>
|
||||||
|
${needsARestart}`)
|
||||||
|
)
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle.setValue(settings.splitCamelCase).onChange(async v => {
|
toggle.setValue(settings.splitCamelCase).onChange(async v => {
|
||||||
await database.clearCache()
|
await database.clearCache()
|
||||||
@@ -469,14 +494,12 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Show "Create note" button
|
// Show "Create note" button
|
||||||
const createBtnDesc = new DocumentFragment()
|
|
||||||
createBtnDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Shows a button next to the search input, to create a note.
|
|
||||||
Acts the same as the <code>shift ↵</code> shortcut, can be useful for mobile device users.`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Show "Create note" button')
|
.setName('Show "Create note" button')
|
||||||
.setDesc(createBtnDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`Shows a button next to the search input, to create a note.
|
||||||
|
Acts the same as the <code>shift ↵</code> shortcut, can be useful for mobile device users.`)
|
||||||
|
)
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle.setValue(settings.showCreateButton).onChange(async v => {
|
toggle.setValue(settings.showCreateButton).onChange(async v => {
|
||||||
settings.showCreateButton = v
|
settings.showCreateButton = v
|
||||||
@@ -589,14 +612,14 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
//#region HTTP Server
|
//#region HTTP Server
|
||||||
|
|
||||||
if (!Platform.isMobile) {
|
if (!Platform.isMobile) {
|
||||||
const httpServerDesc = new DocumentFragment()
|
|
||||||
httpServerDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Omnisearch can be used through a simple HTTP server (<a href="https://publish.obsidian.md/omnisearch/Public+API+%26+URL+Scheme#HTTP+Server">more information</a>).`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('API Access Through HTTP')
|
.setName('API Access Through HTTP')
|
||||||
.setHeading()
|
.setHeading()
|
||||||
.setDesc(httpServerDesc)
|
.setDesc(
|
||||||
|
htmlDescription(
|
||||||
|
`Omnisearch can be used through a simple HTTP server (<a href="https://publish.obsidian.md/omnisearch/Public+API+%26+URL+Scheme#HTTP+Server">more information</a>).`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Enable the HTTP server')
|
.setName('Enable the HTTP server')
|
||||||
@@ -668,17 +691,14 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
new Setting(containerEl).setName('Danger Zone').setHeading()
|
new Setting(containerEl).setName('Danger Zone').setHeading()
|
||||||
|
|
||||||
// Ignore diacritics
|
// Ignore diacritics
|
||||||
const diacriticsDesc = new DocumentFragment()
|
|
||||||
diacriticsDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Normalize diacritics in search terms. Words like "brûlée" or "žluťoučký" will be indexed as "brulee" and "zlutoucky".<br/>
|
|
||||||
⚠️ <span style="color: var(--text-accent)">You probably should <strong>NOT</strong> disable this.</span><br>
|
|
||||||
⚠️ <span style="color: var(--text-accent)">Changing this setting will clear the cache.</span><br>
|
|
||||||
${needsARestart}
|
|
||||||
`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Ignore diacritics')
|
.setName('Ignore diacritics')
|
||||||
.setDesc(diacriticsDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`Normalize diacritics in search terms. Words like "brûlée" or "žluťoučký" will be indexed as "brulee" and "zlutoucky".<br/>
|
||||||
|
⚠️ <span style="color: var(--text-accent)">You probably should <strong>NOT</strong> disable this.</span><br>
|
||||||
|
⚠️ <span style="color: var(--text-accent)">Changing this setting will clear the cache.</span><br>
|
||||||
|
${needsARestart}`)
|
||||||
|
)
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle.setValue(settings.ignoreDiacritics).onChange(async v => {
|
toggle.setValue(settings.ignoreDiacritics).onChange(async v => {
|
||||||
await database.clearCache()
|
await database.clearCache()
|
||||||
@@ -687,6 +707,16 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Ignore Arabic diacritics (beta)')
|
||||||
|
.addToggle(toggle =>
|
||||||
|
toggle.setValue(settings.ignoreArabicDiacritics).onChange(async v => {
|
||||||
|
await database.clearCache()
|
||||||
|
settings.ignoreArabicDiacritics = v
|
||||||
|
await saveSettings(this.plugin)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
// Disable Omnisearch
|
// Disable Omnisearch
|
||||||
const disableDesc = new DocumentFragment()
|
const disableDesc = new DocumentFragment()
|
||||||
disableDesc.createSpan({}, span => {
|
disableDesc.createSpan({}, span => {
|
||||||
@@ -700,24 +730,38 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
toggle.setValue(isPluginDisabled(this.app)).onChange(async v => {
|
toggle.setValue(isPluginDisabled(this.app)).onChange(async v => {
|
||||||
if (v) {
|
if (v) {
|
||||||
this.app.saveLocalStorage(K_DISABLE_OMNISEARCH, '1')
|
this.app.saveLocalStorage(K_DISABLE_OMNISEARCH, '1')
|
||||||
|
new Notice('Omnisearch - Disabled. Please restart Obsidian.')
|
||||||
} else {
|
} else {
|
||||||
this.app.saveLocalStorage(K_DISABLE_OMNISEARCH) // No value = unset
|
this.app.saveLocalStorage(K_DISABLE_OMNISEARCH) // No value = unset
|
||||||
|
new Notice('Omnisearch - Enabled. Please restart Obsidian.')
|
||||||
}
|
}
|
||||||
new Notice('Omnisearch - Disabled. Please restart Obsidian.')
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Force save cache
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Force save the cache')
|
||||||
|
.setDesc(
|
||||||
|
htmlDescription(`Omnisearch has a security feature that automatically disables cache writing if it cannot fully perform the operation.<br>
|
||||||
|
Use this option to force the cache to be saved, even if it causes a crash.<br>
|
||||||
|
⚠️ <span style="color: var(--text-accent)">Enabling this setting could lead to crash loops</span>`)
|
||||||
|
)
|
||||||
|
.addToggle(toggle =>
|
||||||
|
toggle.setValue(settings.DANGER_forceSaveCache).onChange(async v => {
|
||||||
|
settings.DANGER_forceSaveCache = v
|
||||||
|
await saveSettings(this.plugin)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Clear cache data
|
// Clear cache data
|
||||||
if (isCacheEnabled()) {
|
if (isCacheEnabled()) {
|
||||||
const resetCacheDesc = new DocumentFragment()
|
|
||||||
resetCacheDesc.createSpan({}, span => {
|
|
||||||
span.innerHTML = `Erase all Omnisearch cache data.
|
|
||||||
Use this if Omnisearch results are inconsistent, missing, or appear outdated.<br>
|
|
||||||
${needsARestart}`
|
|
||||||
})
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Clear cache data')
|
.setName('Clear cache data')
|
||||||
.setDesc(resetCacheDesc)
|
.setDesc(
|
||||||
|
htmlDescription(`Erase all Omnisearch cache data.
|
||||||
|
Use this if Omnisearch results are inconsistent, missing, or appear outdated.<br>
|
||||||
|
${needsARestart}`)
|
||||||
|
)
|
||||||
.addButton(btn => {
|
.addButton(btn => {
|
||||||
btn.setButtonText('Clear cache')
|
btn.setButtonText('Clear cache')
|
||||||
btn.onClick(async () => {
|
btn.onClick(async () => {
|
||||||
@@ -725,6 +769,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Danger Zone
|
//#endregion Danger Zone
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +790,9 @@ export function getDefaultSettings(app: App): OmnisearchSettings {
|
|||||||
hideExcluded: false,
|
hideExcluded: false,
|
||||||
downrankedFoldersFilters: [] as string[],
|
downrankedFoldersFilters: [] as string[],
|
||||||
ignoreDiacritics: true,
|
ignoreDiacritics: true,
|
||||||
|
ignoreArabicDiacritics: false,
|
||||||
indexedFileTypes: [] as string[],
|
indexedFileTypes: [] as string[],
|
||||||
|
displayTitle: '',
|
||||||
PDFIndexing: false,
|
PDFIndexing: false,
|
||||||
officeIndexing: false,
|
officeIndexing: false,
|
||||||
imagesIndexing: false,
|
imagesIndexing: false,
|
||||||
@@ -781,11 +828,20 @@ export function getDefaultSettings(app: App): OmnisearchSettings {
|
|||||||
verboseLogging: false,
|
verboseLogging: false,
|
||||||
|
|
||||||
DANGER_httpHost: null,
|
DANGER_httpHost: null,
|
||||||
|
DANGER_forceSaveCache: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let settings: OmnisearchSettings
|
let settings: OmnisearchSettings
|
||||||
|
|
||||||
|
function htmlDescription(innerHTML: string): DocumentFragment {
|
||||||
|
const desc = new DocumentFragment()
|
||||||
|
desc.createSpan({}, span => {
|
||||||
|
span.innerHTML = innerHTML
|
||||||
|
})
|
||||||
|
return desc
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * @deprecated
|
// * @deprecated
|
||||||
// */
|
// */
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export function getApi(plugin: OmnisearchPlugin) {
|
|||||||
async search(q: string): Promise<ResultNoteApi[]> {
|
async search(q: string): Promise<ResultNoteApi[]> {
|
||||||
const query = new Query(q, {
|
const query = new Query(q, {
|
||||||
ignoreDiacritics: plugin.settings.ignoreDiacritics,
|
ignoreDiacritics: plugin.settings.ignoreDiacritics,
|
||||||
|
ignoreArabicDiacritics: plugin.settings.ignoreArabicDiacritics,
|
||||||
})
|
})
|
||||||
const raw = await plugin.searchEngine.getSuggestions(query)
|
const raw = await plugin.searchEngine.getSuggestions(query)
|
||||||
return mapResults(plugin, raw)
|
return mapResults(plugin, raw)
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export class TextProcessor {
|
|||||||
const originalText = text
|
const originalText = text
|
||||||
// text = text.toLowerCase().replace(new RegExp(SEPARATORS, 'gu'), ' ')
|
// text = text.toLowerCase().replace(new RegExp(SEPARATORS, 'gu'), ' ')
|
||||||
if (this.plugin.settings.ignoreDiacritics) {
|
if (this.plugin.settings.ignoreDiacritics) {
|
||||||
text = removeDiacritics(text)
|
text = removeDiacritics(text, this.plugin.settings.ignoreArabicDiacritics)
|
||||||
}
|
}
|
||||||
const startTime = new Date().getTime()
|
const startTime = new Date().getTime()
|
||||||
let match: RegExpExecArray | null = null
|
let match: RegExpExecArray | null = null
|
||||||
|
|||||||
@@ -109,15 +109,30 @@ export function getTagsFromMetadata(metadata: CachedMetadata | null): string[] {
|
|||||||
/**
|
/**
|
||||||
* https://stackoverflow.com/a/37511463
|
* https://stackoverflow.com/a/37511463
|
||||||
*/
|
*/
|
||||||
export function removeDiacritics(str: string): string {
|
export function removeDiacritics(str: string, arabic = false): string {
|
||||||
// Japanese diacritics that should be distinguished
|
|
||||||
const excludeDiacritics: string[] = ['\\u30FC', '\\u309A', '\\u3099']
|
|
||||||
const regexpExclude: string = excludeDiacritics.join('|')
|
|
||||||
const regexp: RegExp = new RegExp(`(?!${regexpExclude})\\p{Diacritic}`, 'gu')
|
|
||||||
|
|
||||||
if (str === null || str === undefined) {
|
if (str === null || str === undefined) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Japanese diacritics that should be distinguished
|
||||||
|
const japaneseDiacritics: string[] = ['\\u30FC', '\\u309A', '\\u3099']
|
||||||
|
const regexpExclude: string = japaneseDiacritics.join('|')
|
||||||
|
const regexp: RegExp = new RegExp(`(?!${regexpExclude})\\p{Diacritic}`, 'gu')
|
||||||
|
|
||||||
|
if (arabic) {
|
||||||
|
// Arabic diacritics
|
||||||
|
// https://stackoverflow.com/a/40959537
|
||||||
|
str = str
|
||||||
|
.replace(/([^\u0621-\u063A\u0641-\u064A\u0660-\u0669a-zA-Z 0-9])/g, '')
|
||||||
|
.replace(/(آ|إ|أ)/g, 'ا')
|
||||||
|
.replace(/(ة)/g, 'ه')
|
||||||
|
.replace(/(ئ|ؤ)/g, 'ء')
|
||||||
|
.replace(/(ى)/g, 'ي')
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
str.replace(String.fromCharCode(0x660 + i), String.fromCharCode(48 + i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keep backticks for code blocks, because otherwise they are removed by the .normalize() function
|
// Keep backticks for code blocks, because otherwise they are removed by the .normalize() function
|
||||||
// https://stackoverflow.com/a/36100275
|
// https://stackoverflow.com/a/36100275
|
||||||
str = str.replaceAll('`', '[__omnisearch__backtick__]')
|
str = str.replaceAll('`', '[__omnisearch__backtick__]')
|
||||||
@@ -152,7 +167,11 @@ export function isFileCanvas(path: string): boolean {
|
|||||||
return path.endsWith('.canvas')
|
return path.endsWith('.canvas')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFileFromDataloomPlugin(path: string): boolean {
|
export function isFileExcalidraw(path: string): boolean {
|
||||||
|
return path.endsWith('.excalidraw')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFileFromDataloom(path: string): boolean {
|
||||||
return path.endsWith('.loom')
|
return path.endsWith('.loom')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +238,7 @@ export function warnDebug(...args: any[]): void {
|
|||||||
printDebug(console.warn, ...args)
|
printDebug(console.warn, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
let printDebugEnabled= false
|
let printDebugEnabled = false
|
||||||
export function enablePrintDebug(enable: boolean): void {
|
export function enablePrintDebug(enable: boolean): void {
|
||||||
printDebugEnabled = enable
|
printDebugEnabled = enable
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user