diff --git a/.prettierrc b/.prettierrc index 85039d8..21e6acd 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,8 @@ { - "arrowParens": "always", - "printWidth": 140, - "semi": true, - "singleQuote": false, - "tabWidth": 4, - "trailingComma": "es5" + "arrowParens": "always", + "printWidth": 100, + "semi": true, + "singleQuote": false, + "tabWidth": 4, + "trailingComma": "es5" } diff --git a/manifest.json b/manifest.json index dbb39cb..1cc8b1c 100644 --- a/manifest.json +++ b/manifest.json @@ -5,5 +5,5 @@ "author": "lazyloong", "minAppVersion": "1.0.0", - "version": "2.10.3" + "version": "2.11.0" } diff --git a/package.json b/package.json index 4a525d1..3bf390c 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,20 @@ { - "name": "fuzyy_chinese", - "version": "0.0.1", - "description": "", - "main": "lib/main.js", - "license": "MIT", - "scripts": { - "build": "obsidian-plugin build ./src/main.ts && cp styles.css dist", - "build-win": "obsidian-plugin build ./src/main.ts && copy styles.css dist", - "dev": "obsidian-plugin dev src/main.ts", - "help": "obsidian-plugin --help" - }, - "devDependencies": { - "builtin-modules": "^3.3.0", - "obsidian": "github:obsidianmd/obsidian-api", - "obsidian-plugin-cli": "^0.9.0", - "typescript": "^4.9.5" - } + "name": "fuzyy_chinese", + "version": "0.0.1", + "description": "", + "main": "lib/main.js", + "license": "MIT", + "scripts": { + "build": "obsidian-plugin build ./src/main.ts && cp styles.css dist", + "build-win": "obsidian-plugin build ./src/main.ts && copy styles.css dist", + "dev": "obsidian-plugin dev src/main.ts", + "help": "obsidian-plugin --help" + }, + "devDependencies": { + "builtin-modules": "^3.3.0", + "obsidian": "github:obsidianmd/obsidian-api", + "templater": "github:SilentVoid13/Templater", + "obsidian-plugin-cli": "^0.9.0", + "typescript": "^4.9.5" + } } diff --git a/src/fuzzyCommandModal.ts b/src/fuzzyCommandModal.ts index b6aba56..9e634b5 100644 --- a/src/fuzzyCommandModal.ts +++ b/src/fuzzyCommandModal.ts @@ -1,4 +1,4 @@ -import { App, Hotkey, Modifier, Platform } from "obsidian"; +import { App, Hotkey, Modifier, Platform, getIcon } from "obsidian"; import FuzzyModal from "./fuzzyModal"; import { PinyinIndex as PI, Pinyin, MatchData } from "./utils"; import FuzzyChinesePinyinPlugin from "./main"; @@ -53,11 +53,11 @@ function generateHotKeyText(hotkey: Hotkey): string { } export default class FuzzyCommandModal extends FuzzyModal { - historyCommand: Array; + historyCommands: Array; constructor(app: App, plugin: FuzzyChinesePinyinPlugin) { super(app, plugin); this.index = this.plugin.addChild(new PinyinIndex(this.app, this.plugin)); - this.historyCommand = []; + this.historyCommands = []; this.emptyStateText = "未发现命令。"; this.setPlaceholder("输入命令……"); let prompt = [ @@ -77,16 +77,42 @@ export default class FuzzyCommandModal extends FuzzyModal { this.index.update(); } getEmptyInputSuggestions(): MatchData[] { - return this.historyCommand - .concat(this.index.items.filter((p) => !this.historyCommand.includes(p))) - .slice(0, 100) - .map((p) => { - return { item: p, score: 0, range: null }; - }); + let pinnedCommands: MatchData[] = this.plugin.settings.command.pinnedCommands.map( + (p) => ({ + item: this.index.items.find((q) => q.name == p), + score: -2, + range: null, + }) + ), + historyCommands: MatchData[] = this.historyCommands + .filter((p) => !this.plugin.settings.command.pinnedCommands.includes(p.name)) + .map((p) => ({ + item: this.index.items.find((q) => q.name == p.name), + score: -1, + range: null, + })), + commonCommands: MatchData[] = this.index.items + .filter( + (p) => + !this.plugin.settings.command.pinnedCommands.includes(p.name) && + !this.historyCommands.includes(p) + ) + .map((p) => ({ + item: p, + score: 0, + range: null, + })); + return pinnedCommands + .concat(historyCommands) + .concat(commonCommands) + .filter((p) => p.item) + .slice(0, 100); } onChooseSuggestion(matchData: MatchData, evt: MouseEvent | KeyboardEvent) { - this.historyCommand = this.historyCommand.filter((p) => p.command.id != matchData.item.command.id); - this.historyCommand.unshift(matchData.item); + this.historyCommands = this.historyCommands.filter( + (p) => p.command.id != matchData.item.command.id + ); + this.historyCommands.unshift(matchData.item); app.commands.executeCommand(matchData.item.command); } renderSuggestion(matchData: MatchData, el: HTMLElement): void { @@ -104,7 +130,10 @@ export default class FuzzyCommandModal extends FuzzyModal { if (range) { for (const r of range) { e_content.appendText(text.slice(index, r[0])); - e_content.createSpan({ cls: "suggestion-highlight", text: text.slice(r[0], r[1] + 1) }); + e_content.createSpan({ + cls: "suggestion-highlight", + text: text.slice(r[0], r[1] + 1), + }); index = r[1] + 1; } } @@ -116,6 +145,12 @@ export default class FuzzyCommandModal extends FuzzyModal { text: generateHotKeyText(hotkey), }); }); + + let e_flair = el.createEl("span", { + cls: "suggestion-flair", + }); + if (matchData.score == -2) e_flair.appendChild(getIcon("pin")); + else if (matchData.score == -1) e_flair.appendChild(getIcon("history")); } } class PinyinIndex extends PI { @@ -136,8 +171,12 @@ class PinyinIndex extends PI { let commands = app.commands.listCommands(); let oldCommandsNames = this.items.map((item) => item.name); let newCommandsNames = commands.map((command) => command.name); - let addedCommands = newCommandsNames.filter((command) => !oldCommandsNames.includes(command)); - let removedCommands = oldCommandsNames.filter((command) => !newCommandsNames.includes(command)); + let addedCommands = newCommandsNames.filter( + (command) => !oldCommandsNames.includes(command) + ); + let removedCommands = oldCommandsNames.filter( + (command) => !newCommandsNames.includes(command) + ); if (addedCommands.length > 0) { // 添加新命令 this.items.push( diff --git a/src/fuzzyFileModal.ts b/src/fuzzyFileModal.ts index 236b17f..0e891e7 100644 --- a/src/fuzzyFileModal.ts +++ b/src/fuzzyFileModal.ts @@ -1,4 +1,4 @@ -import { TFile, App, WorkspaceLeaf, TAbstractFile, CachedMetadata } from "obsidian"; +import { TFile, App, WorkspaceLeaf, TAbstractFile, CachedMetadata, getIcon } from "obsidian"; import { Pinyin, PinyinIndex as PI, HistoryMatchDataNode } from "./utils"; import FuzzyChinesePinyinPlugin from "./main"; import FuzzyModal from "./fuzzyModal"; @@ -75,19 +75,28 @@ export default class FuzzyFileModal extends FuzzyModal { this.scope.register(["Shift"], "Enter", async (e) => { if (this.inputEl.value == "") return; this.close(); - let nf = await app.vault.create(app.fileManager.getNewFileParent("").path + "/" + this.inputEl.value + ".md", ""); + let nf = await app.vault.create( + app.fileManager.getNewFileParent("").path + "/" + this.inputEl.value + ".md", + "" + ); app.workspace.getMostRecentLeaf().openFile(nf); }); this.scope.register(["Mod", "Shift"], "Enter", async (e) => { if (this.inputEl.value == "") return; this.close(); - let nf = await app.vault.create(app.fileManager.getNewFileParent("").path + "/" + this.inputEl.value + ".md", ""); + let nf = await app.vault.create( + app.fileManager.getNewFileParent("").path + "/" + this.inputEl.value + ".md", + "" + ); app.workspace.getLeaf("tab").openFile(nf); }); this.scope.register(["Shift", "Alt"], "Enter", async (e) => { if (this.inputEl.value == "") return; this.close(); - let nf = await app.vault.create(app.fileManager.getNewFileParent("").path + "/" + this.inputEl.value + ".md", ""); + let nf = await app.vault.create( + app.fileManager.getNewFileParent("").path + "/" + this.inputEl.value + ".md", + "" + ); getNewOrAdjacentLeaf(app.workspace.getMostRecentLeaf()).openFile(nf); }); this.scope.register(["Alt"], "Enter", async (e) => { @@ -99,8 +108,9 @@ export default class FuzzyFileModal extends FuzzyModal { this.scope.register(["Mod"], "p", (event: KeyboardEvent) => { this.close(); let item = this.chooser.values[this.chooser.selectedItem]; - const newLeaf = app.plugins.plugins["obsidian-hover-editor"].spawnPopover(undefined, () => - this.app.workspace.setActiveLeaf(newLeaf) + const newLeaf = app.plugins.plugins["obsidian-hover-editor"].spawnPopover( + undefined, + () => this.app.workspace.setActiveLeaf(newLeaf) ); newLeaf.openFile(item.item.file); }); @@ -158,8 +168,13 @@ export default class FuzzyFileModal extends FuzzyModal { } if (this.plugin.settings.file.usePathToSearch && matchData1.length <= 10) { - toMatchData = indexNode.itemIndexByPath.length == 0 ? this.index.items : indexNode.itemIndexByPath; - for (let p of toMatchData.filter((p) => p.type == "file" && !matchData1.map((p) => p.item.path).includes(p.path))) { + toMatchData = + indexNode.itemIndexByPath.length == 0 + ? this.index.items + : indexNode.itemIndexByPath; + for (let p of toMatchData.filter( + (p) => p.type == "file" && !matchData1.map((p) => p.item.path).includes(p.path) + )) { let d = p.pinyinOfPath.match(query, p, smathCase); if (d) { d.usePath = true; @@ -201,7 +216,10 @@ export default class FuzzyFileModal extends FuzzyModal { if (range) { for (const r of range) { e_title.appendText(text.slice(index, r[0])); - e_title.createSpan({ cls: "suggestion-highlight", text: text.slice(r[0], r[1] + 1) }); + e_title.createSpan({ + cls: "suggestion-highlight", + text: text.slice(r[0], r[1] + 1), + }); index = r[1] + 1; } } @@ -231,8 +249,7 @@ export default class FuzzyFileModal extends FuzzyModal { let e_flair = el.createEl("span", { cls: "fz-suggestion-flair", }); - e_flair.innerHTML += - ''; + e_flair.appendChild(getIcon("forward")); if (!this.plugin.settings.file.showPath) e_flair.style.top = "9px"; if (e_note) e_note.style.width = "calc(100% - 30px)"; } @@ -251,13 +268,20 @@ export default class FuzzyFileModal extends FuzzyModal { } } onNoSuggestion(): void { - super.onNoSuggestion({ item: { type: "file", path: this.inputEl.value }, score: -1, usePath: true }); + super.onNoSuggestion({ + item: { type: "file", path: this.inputEl.value }, + score: -1, + usePath: true, + }); } async getChoosenItemFile(matchData?: MatchData): Promise { matchData = matchData ?? this.chooser.values[this.chooser.selectedItem]; let file = matchData.score == -1 - ? await app.vault.create(app.fileManager.getNewFileParent("").path + "/" + matchData.item.path + ".md", "") + ? await app.vault.create( + app.fileManager.getNewFileParent("").path + "/" + matchData.item.path + ".md", + "" + ) : matchData.item.file; return file; } @@ -281,13 +305,18 @@ const getNewOrAdjacentLeaf = (leaf: WorkspaceLeaf): WorkspaceLeaf => { const getMainLeaf = (): WorkspaceLeaf => { let mainLeaf = app.workspace.getMostRecentLeaf(); - if (mainLeaf && mainLeaf !== leaf && mainLeaf.view?.containerEl.ownerDocument === document) { + if ( + mainLeaf && + mainLeaf !== leaf && + mainLeaf.view?.containerEl.ownerDocument === document + ) { return mainLeaf; } mainLeavesIds.forEach((id: any) => { const l = app.workspace.getLeafById(id); - if ((leaf.parent.id == l.parent.id && mainLeaf) || !l.view?.navigation || leaf === l) return; + if ((leaf.parent.id == l.parent.id && mainLeaf) || !l.view?.navigation || leaf === l) + return; mainLeaf = l; }); let newLeaf: WorkspaceLeaf; @@ -316,12 +345,22 @@ class PinyinIndex extends PI { } } initEvent() { - this.registerEvent(this.metadataCache.on("changed", (file, data, cache) => this.update("changed", file, { data, cache }))); - this.registerEvent(this.vault.on("rename", (file, oldPath) => this.update("rename", file, { oldPath }))); + this.registerEvent( + this.metadataCache.on("changed", (file, data, cache) => + this.update("changed", file, { data, cache }) + ) + ); + this.registerEvent( + this.vault.on("rename", (file, oldPath) => this.update("rename", file, { oldPath })) + ); this.registerEvent(this.vault.on("create", (file) => this.update("create", file))); this.registerEvent(this.vault.on("delete", (file) => this.update("delete", file))); } - update(type: string, file: TAbstractFile, keys?: { oldPath?: string; data?: string; cache?: CachedMetadata }) { + update( + type: string, + file: TAbstractFile, + keys?: { oldPath?: string; data?: string; cache?: CachedMetadata } + ) { if (!this.isEffectiveFile(file)) return; switch (type) { case "changed": { @@ -353,7 +392,10 @@ class PinyinIndex extends PI { if (this.plugin.settings.file.showAllFileTypes) return true; else if (DOCUMENT_EXTENSIONS.includes(file.extension)) return true; - else if (this.plugin.settings.file.showAttachments && this.plugin.settings.file.attachmentExtensions.includes(file.extension)) + else if ( + this.plugin.settings.file.showAttachments && + this.plugin.settings.file.attachmentExtensions.includes(file.extension) + ) return true; else return false; } @@ -381,7 +423,12 @@ function TFile2Item(file: TFile, plugin: FuzzyChinesePinyinPlugin): Item { }; } -function CachedMetadata2Item(file: TFile, plugin: FuzzyChinesePinyinPlugin, items: Item[], cache?: CachedMetadata): Item[] { +function CachedMetadata2Item( + file: TFile, + plugin: FuzzyChinesePinyinPlugin, + items: Item[], + cache?: CachedMetadata +): Item[] { cache = cache ?? app.metadataCache.getFileCache(file); let alias = cache?.frontmatter?.alias || cache?.frontmatter?.aliases; let item = items.find((item) => item.path == file.path && item.type == "file"); diff --git a/src/fuzzyModal.ts b/src/fuzzyModal.ts index cf768ce..ac8af46 100644 --- a/src/fuzzyModal.ts +++ b/src/fuzzyModal.ts @@ -8,6 +8,7 @@ export default abstract class FuzzyModal extends SuggestModal; plugin: FuzzyChinesePinyinPlugin; useInput: boolean; + onInput: any; constructor(app: App, plugin: FuzzyChinesePinyinPlugin) { super(app); this.useInput = false; diff --git a/src/main.ts b/src/main.ts index 9820e0b..9fb8994 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ -import { App, Notice, Plugin, PluginSettingTab, Setting, EditorSuggest } from "obsidian"; -import { Item, PinyinIndex, runOnLayoutReady } from "./utils"; +import { Plugin, EditorSuggest } from "obsidian"; +import { fullPinyin2doublePinyin, Item, PinyinIndex, runOnLayoutReady } from "./utils"; import FuzzyModal from "./fuzzyModal"; import FuzzyFileModal from "./fuzzyFileModal"; import FuzzyFolderModal from "./fuzzyFolderModal"; @@ -13,13 +13,14 @@ import TraditionalDict from "./traditional_dict"; import DoublePinyinDict from "./double_pinyin"; import { fuzzyPinyinSearch, stringArray2Items } from "./search"; +import SettingTab from "./settingTab"; interface FuzyyChinesePinyinSettings { global: { traditionalChineseSupport: boolean; doublePinyin: string; closeWithBackspace: boolean; - autoCaseSensitivity: boolean, + autoCaseSensitivity: boolean; }; file: { showAllFileTypes: boolean; @@ -31,6 +32,9 @@ interface FuzyyChinesePinyinSettings { showTags: boolean; historyDisplay: string; }; + command: { + pinnedCommands: Array; + }; other: { useTagEditorSuggest: boolean; devMode: boolean; @@ -76,6 +80,9 @@ const DEFAULT_SETTINGS: FuzyyChinesePinyinSettings = { showTags: false, historyDisplay: "使用完整路径", }, + command: { + pinnedCommands: [], + }, other: { useTagEditorSuggest: true, devMode: false, @@ -209,183 +216,11 @@ export default class FuzzyChinesePinyinPlugin extends Plugin { } } -class SettingTab extends PluginSettingTab { - plugin: FuzzyChinesePinyinPlugin; - constructor(app: App, plugin: FuzzyChinesePinyinPlugin) { - super(app, plugin); - this.plugin = plugin; - } - display(): void { - let { containerEl } = this; - containerEl.empty(); - containerEl.createEl("h1", { text: "设置" }); - containerEl.createEl("h2", { text: "全局" }); - new Setting(containerEl) - .setName("Backspace 关闭搜索") - .setDesc("当输入框为空时按下 Backspace 关闭搜索") - .addToggle((text) => - text.setValue(this.plugin.settings.global.closeWithBackspace).onChange(async (value) => { - this.plugin.settings.global.closeWithBackspace = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl).setName("繁体支持").addToggle((text) => { - text.setValue(this.plugin.settings.global.traditionalChineseSupport).onChange(async (value) => { - this.plugin.settings.global.traditionalChineseSupport = value; - await this.plugin.saveSettings(); - this.plugin.loadPinyinDict(); - }); - }); - new Setting(containerEl).setName("双拼方案").addDropdown((text) => - text - .addOptions({ - 全拼: "全拼", - 智能ABC: "智能ABC", - 小鹤双拼: "小鹤双拼", - 微软双拼: "微软双拼", - }) - .setValue(this.plugin.settings.global.doublePinyin) - .onChange(async (value: string) => { - this.plugin.settings.global.doublePinyin = value; - this.plugin.pinyinDict.keys = - value == "全拼" - ? this.plugin.pinyinDict.originalKeys - : this.plugin.pinyinDict.originalKeys.map((p) => fullPinyin2doublePinyin(p, DoublePinyinDict[value])); - this.plugin.fileModal.index.initIndex(); - new Notice("双拼方案切换为:" + value, 4000); - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl).setName("自动大小写敏感").addToggle((text) => { - text.setValue(this.plugin.settings.global.autoCaseSensitivity).onChange(async (value) => { - this.plugin.settings.global.autoCaseSensitivity = value; - await this.plugin.saveSettings(); - }); - }); - containerEl.createEl("h2", { text: "文件搜索" }); - new Setting(containerEl) - .setName("显示附件") - .setDesc("显示如图片、视频、PDF等附件文件。") - .addToggle((text) => - text.setValue(this.plugin.settings.file.showAttachments).onChange(async (value) => { - this.plugin.settings.file.showAttachments = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl).setName("显示所有类型文件").addToggle((text) => - text.setValue(this.plugin.settings.file.showAllFileTypes).onChange(async (value) => { - this.plugin.settings.file.showAllFileTypes = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl) - .setName("使用路径搜索") - .setDesc("当搜索结果少于10个时搜索路径") - .addToggle((text) => - text.setValue(this.plugin.settings.file.usePathToSearch).onChange(async (value) => { - this.plugin.settings.file.usePathToSearch = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl).setName("显示路径").addToggle((text) => - text.setValue(this.plugin.settings.file.showPath).onChange(async (value) => { - this.plugin.settings.file.showPath = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl).setName("显示 Tag").addToggle((text) => - text.setValue(this.plugin.settings.file.showTags).onChange(async (value) => { - this.plugin.settings.file.showTags = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl) - .setName("使用双链建议") - .setDesc("输入[[的时候文件连接能支持中文拼音搜索(实验性功能)") - .addToggle((text) => - text.setValue(this.plugin.settings.file.useFileEditorSuggest).onChange(async (value) => { - this.plugin.settings.file.useFileEditorSuggest = value; - if (value) { - this.app.workspace.editorSuggest.suggests.unshift(this.plugin.fileEditorSuggest); - } else { - this.app.workspace.editorSuggest.removeSuggest(this.plugin.fileEditorSuggest); - } - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl).setName("历史记录").addDropdown((text) => - text - .addOptions({ - 使用完整路径: "使用完整路径", - 仅使用文件名: "仅使用文件名", - }) - .setValue(this.plugin.settings.file.historyDisplay) - .onChange(async (value: string) => { - this.plugin.settings.file.historyDisplay = value; - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl) - .setName("附件后缀") - .setDesc("只显示这些后缀的附件") - .addTextArea((text) => { - text.inputEl.addClass("fuzzy-chinese-attachment-extensions"); - text.setValue(this.plugin.settings.file.attachmentExtensions.join("\n")).onChange(async (value) => { - this.plugin.settings.file.attachmentExtensions = value - .trim() - .split("\n") - .map((x) => x.trim()); - await this.plugin.saveSettings(); - }); - }); - containerEl.createEl("h2", { text: "其他" }); - new Setting(containerEl) - .setName("使用标签建议") - .setDesc("实验性功能") - .addToggle((text) => - text.setValue(this.plugin.settings.other.useTagEditorSuggest).onChange(async (value) => { - this.plugin.settings.other.useTagEditorSuggest = value; - if (value) { - this.app.workspace.editorSuggest.suggests.unshift(this.plugin.tagEditorSuggest); - } else { - this.app.workspace.editorSuggest.removeSuggest(this.plugin.tagEditorSuggest); - } - await this.plugin.saveSettings(); - }) - ); - new Setting(containerEl) - .setName("dev 模式") - .setDesc("将索引存储到 global 以便重启时不重建索引") - .addToggle((text) => - text.setValue(this.plugin.settings.other.devMode).onChange(async (value) => { - this.plugin.settings.other.devMode = value; - await this.plugin.saveSettings(); - }) - ); - } -} - -function fullPinyin2doublePinyin(fullPinyin: string, doublePinyinDict): string { - let doublePinyin = ""; - let findKeys = (obj, condition) => { - return Object.keys(obj).find((key) => condition(obj[key])); - }; - if (["sh", "ch", "zh"].some((p) => fullPinyin.startsWith(p))) { - doublePinyin += findKeys(doublePinyinDict, (p) => p.includes(fullPinyin.slice(0, 2))); - fullPinyin = fullPinyin.slice(2); - } else { - doublePinyin += fullPinyin[0]; - fullPinyin = fullPinyin.slice(1); - } - if (fullPinyin.length != 0) doublePinyin += findKeys(doublePinyinDict, (p) => p.includes(fullPinyin)); - return doublePinyin; -} - class IndexManager extends Array> { plugin: FuzzyChinesePinyinPlugin; - constructor(plugin: FuzzyChinesePinyinPlugin, com: Array | EditorSuggest>) { + constructor(plugin: FuzzyChinesePinyinPlugin, component: Array | EditorSuggest>) { super(); - com.forEach((p: any) => this.push(p.index)); + component.forEach((p: any) => this.push(p.index)); this.plugin = plugin; } load() { diff --git a/src/settingTab.ts b/src/settingTab.ts new file mode 100644 index 0000000..31f1fb6 --- /dev/null +++ b/src/settingTab.ts @@ -0,0 +1,244 @@ +import { App, Notice, PluginSettingTab, Setting } from "obsidian"; +import DoublePinyinDict from "./double_pinyin"; +import FuzzyChinesePinyinPlugin from "./main"; +import { Item, MatchData, arraymove, fullPinyin2doublePinyin } from "./utils"; +import { TextInputSuggest } from "templater/src/settings/suggesters/suggest"; + +export default class SettingTab extends PluginSettingTab { + plugin: FuzzyChinesePinyinPlugin; + constructor(app: App, plugin: FuzzyChinesePinyinPlugin) { + super(app, plugin); + this.plugin = plugin; + } + display(): void { + this.containerEl.empty(); + this.containerEl.createEl("h1", { text: "设置" }); + this.addGlobalSetting(); + this.addFileSetting(); + this.addCommandSettings(); + this.addOtherSetting(); + } + addGlobalSetting() { + this.containerEl.createEl("h2", { text: "全局" }); + new Setting(this.containerEl) + .setName("Backspace 关闭搜索") + .setDesc("当输入框为空时按下 Backspace 关闭搜索") + .addToggle((cb) => + cb.setValue(this.plugin.settings.global.closeWithBackspace).onChange(async (value) => { + this.plugin.settings.global.closeWithBackspace = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl).setName("繁体支持").addToggle((cb) => { + cb.setValue(this.plugin.settings.global.traditionalChineseSupport).onChange(async (value) => { + this.plugin.settings.global.traditionalChineseSupport = value; + await this.plugin.saveSettings(); + this.plugin.loadPinyinDict(); + }); + }); + new Setting(this.containerEl).setName("双拼方案").addDropdown((cb) => + cb + .addOptions({ + 全拼: "全拼", + 智能ABC: "智能ABC", + 小鹤双拼: "小鹤双拼", + 微软双拼: "微软双拼", + }) + .setValue(this.plugin.settings.global.doublePinyin) + .onChange(async (value: string) => { + this.plugin.settings.global.doublePinyin = value; + this.plugin.pinyinDict.keys = + value == "全拼" + ? this.plugin.pinyinDict.originalKeys + : this.plugin.pinyinDict.originalKeys.map((p) => fullPinyin2doublePinyin(p, DoublePinyinDict[value])); + this.plugin.fileModal.index.initIndex(); + new Notice("双拼方案切换为:" + value, 4000); + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl).setName("自动大小写敏感").addToggle((cb) => { + cb.setValue(this.plugin.settings.global.autoCaseSensitivity).onChange(async (value) => { + this.plugin.settings.global.autoCaseSensitivity = value; + await this.plugin.saveSettings(); + }); + }); + } + addFileSetting() { + this.containerEl.createEl("h2", { text: "文件搜索" }); + new Setting(this.containerEl) + .setName("显示附件") + .setDesc("显示如图片、视频、PDF等附件文件。") + .addToggle((cb) => + cb.setValue(this.plugin.settings.file.showAttachments).onChange(async (value) => { + this.plugin.settings.file.showAttachments = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl).setName("显示所有类型文件").addToggle((cb) => + cb.setValue(this.plugin.settings.file.showAllFileTypes).onChange(async (value) => { + this.plugin.settings.file.showAllFileTypes = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl) + .setName("使用路径搜索") + .setDesc("当搜索结果少于10个时搜索路径") + .addToggle((cb) => + cb.setValue(this.plugin.settings.file.usePathToSearch).onChange(async (value) => { + this.plugin.settings.file.usePathToSearch = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl).setName("显示路径").addToggle((cb) => + cb.setValue(this.plugin.settings.file.showPath).onChange(async (value) => { + this.plugin.settings.file.showPath = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl).setName("显示 Tag").addToggle((cb) => + cb.setValue(this.plugin.settings.file.showTags).onChange(async (value) => { + this.plugin.settings.file.showTags = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl) + .setName("使用双链建议") + .setDesc("输入[[的时候文件连接能支持中文拼音搜索(实验性功能)") + .addToggle((cb) => + cb.setValue(this.plugin.settings.file.useFileEditorSuggest).onChange(async (value) => { + this.plugin.settings.file.useFileEditorSuggest = value; + if (value) { + this.app.workspace.editorSuggest.suggests.unshift(this.plugin.fileEditorSuggest); + } else { + this.app.workspace.editorSuggest.removeSuggest(this.plugin.fileEditorSuggest); + } + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl).setName("历史记录").addDropdown((cb) => + cb + .addOptions({ + 使用完整路径: "使用完整路径", + 仅使用文件名: "仅使用文件名", + }) + .setValue(this.plugin.settings.file.historyDisplay) + .onChange(async (value: string) => { + this.plugin.settings.file.historyDisplay = value; + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl) + .setName("附件后缀") + .setDesc("只显示这些后缀的附件") + .addTextArea((cb) => { + cb.inputEl.addClass("fuzzy-chinese-attachment-extensions"); + cb.setValue(this.plugin.settings.file.attachmentExtensions.join("\n")).onChange(async (value) => { + this.plugin.settings.file.attachmentExtensions = value + .trim() + .split("\n") + .map((x) => x.trim()); + await this.plugin.saveSettings(); + }); + }); + } + addCommandSettings() { + this.containerEl.createEl("h2", { text: "命令" }); + this.addPinnedCommands(); + new Setting(this.containerEl) + .setName("新的置顶命令") + .setDesc("在你未进行检索时,置顶命令将优先出现在命令面板的顶端。") + .addSearch((cb) => { + new CommandSuggest(cb.inputEl, this.plugin); + cb.setPlaceholder("输入命令……").onChange(async (value) => { + let commands = this.app.commands.listCommands().map((p) => p.name); + if (!commands.includes(value)) return; + this.plugin.settings.command.pinnedCommands.push(value); + await this.plugin.saveSettings(); + this.display(); + }); + }); + } + addPinnedCommands() { + this.plugin.settings.command.pinnedCommands.forEach((command, index) => { + new Setting(this.containerEl) + .setName(command) + .addExtraButton((cb) => + cb + .setIcon("x") + .setTooltip("删除") + .onClick(() => { + this.plugin.settings.command.pinnedCommands = this.plugin.settings.command.pinnedCommands.filter( + (x) => x !== command + ); + this.plugin.saveSettings(); + this.display(); + }) + ) + .addExtraButton((cb) => { + cb.setIcon("up-chevron-glyph") + .setTooltip("Move up") + .onClick(() => { + arraymove(this.plugin.settings.command.pinnedCommands, index, index - 1); + this.plugin.saveSettings(); + this.display(); + }); + }) + .addExtraButton((cb) => { + cb.setIcon("down-chevron-glyph") + .setTooltip("Move down") + .onClick(() => { + arraymove(this.plugin.settings.command.pinnedCommands, index, index + 1); + this.plugin.saveSettings(); + this.display(); + }); + }); + }); + } + addOtherSetting() { + this.containerEl.createEl("h2", { text: "其他" }); + new Setting(this.containerEl) + .setName("使用标签建议") + .setDesc("实验性功能") + .addToggle((cb) => + cb.setValue(this.plugin.settings.other.useTagEditorSuggest).onChange(async (value) => { + this.plugin.settings.other.useTagEditorSuggest = value; + if (value) { + this.app.workspace.editorSuggest.suggests.unshift(this.plugin.tagEditorSuggest); + } else { + this.app.workspace.editorSuggest.removeSuggest(this.plugin.tagEditorSuggest); + } + await this.plugin.saveSettings(); + }) + ); + new Setting(this.containerEl) + .setName("dev 模式") + .setDesc("将索引存储到 global 以便重启时不重建索引") + .addToggle((cb) => + cb.setValue(this.plugin.settings.other.devMode).onChange(async (value) => { + this.plugin.settings.other.devMode = value; + await this.plugin.saveSettings(); + }) + ); + } +} + +export class CommandSuggest extends TextInputSuggest> { + plugin: FuzzyChinesePinyinPlugin; + constructor(inputEl: HTMLInputElement | HTMLTextAreaElement, plugin: FuzzyChinesePinyinPlugin) { + super(inputEl); + this.plugin = plugin; + } + getSuggestions(inputStr: string): MatchData[] { + return this.plugin.commandModal.getSuggestions(inputStr); + } + + renderSuggestion(matchData: MatchData, el: HTMLElement): void { + el.setText(matchData.item.name); + } + + selectSuggestion(matchData: MatchData): void { + this.inputEl.value = matchData.item.name; + this.inputEl.trigger("input"); + this.close(); + } +} diff --git a/src/utils.ts b/src/utils.ts index 2d68742..65b01d7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -229,3 +229,28 @@ export function runOnLayoutReady(fun: Function) { }); } } + +export function fullPinyin2doublePinyin(fullPinyin: string, doublePinyinDict): string { + let doublePinyin = ""; + let findKeys = (obj, condition) => { + return Object.keys(obj).find((key) => condition(obj[key])); + }; + if (["sh", "ch", "zh"].some((p) => fullPinyin.startsWith(p))) { + doublePinyin += findKeys(doublePinyinDict, (p) => p.includes(fullPinyin.slice(0, 2))); + fullPinyin = fullPinyin.slice(2); + } else { + doublePinyin += fullPinyin[0]; + fullPinyin = fullPinyin.slice(1); + } + if (fullPinyin.length != 0) doublePinyin += findKeys(doublePinyinDict, (p) => p.includes(fullPinyin)); + return doublePinyin; +} + +export function arraymove(arr: T[], fromIndex: number, toIndex: number): void { + if (toIndex < 0 || toIndex === arr.length) { + return; + } + const element = arr[fromIndex]; + arr[fromIndex] = arr[toIndex]; + arr[toIndex] = element; +}