├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmrc ├── LICENSE ├── README-zh_CN.md ├── README.md ├── esbuild.config.mjs ├── manifest.json ├── package.json ├── screenshot └── demo.gif ├── src ├── SearchBox.svelte ├── editor-extension.ts ├── i18n │ ├── index.ts │ └── locale │ │ ├── en.json │ │ └── zh_cn.json ├── main.ts ├── styles │ └── index.scss ├── types │ └── global.d.ts └── util │ ├── common-helper.ts │ └── text-helper.ts ├── style-settings.css ├── tsconfig.json ├── version-bump.mjs └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = tab 9 | indent_size = 4 10 | tab_width = 4 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | main.js 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "env": { "node": true }, 5 | "plugins": [ 6 | "@typescript-eslint" 7 | ], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended" 12 | ], 13 | "parserOptions": { 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | "no-unused-vars": "off", 18 | "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], 19 | "@typescript-eslint/ban-ts-comment": "off", 20 | "no-prototype-builtins": "off", 21 | "@typescript-eslint/no-empty-function": "off" 22 | } 23 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # vscode 2 | .vscode 3 | 4 | # Intellij 5 | *.iml 6 | .idea 7 | 8 | # npm 9 | node_modules 10 | dist 11 | package-lock.json 12 | 13 | # Don't include the compiled main.js file in the repo. 14 | # They should be uploaded to GitHub releases instead. 15 | main.js 16 | 17 | # Exclude sourcemaps 18 | *.map 19 | 20 | # obsidian 21 | data.json 22 | 23 | # Exclude macOS Finder (System Explorer) View States 24 | .DS_Store 25 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix="" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 nyable 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-zh_CN.md: -------------------------------------------------------------------------------- 1 | # Obsidian 文本查找器 2 | 3 | [English](README.md) 4 | [中文说明](README-zh_CN.md) 5 | 6 | 这是一个用于 Obsidian 的插件(https://obsidian.md)。 7 | 在编辑模式下提供类似于 VSCode 的搜索/替换窗口。 8 | 9 | **注意:** Obsidian API 仍处于早期 alpha 阶段,可能随时发生变化! 10 | 11 | ## 功能 12 | 13 | 在 **编辑模式** 下搜索或替换当前 Markdown 文件的文本。 14 | 15 | - 在当前文件中搜索/替换 16 | - 高亮匹配文本 17 | - 显示匹配数量 18 | - 支持正则表达式 19 | - 支持区分大小写 20 | 21 | ## To Do 22 | 23 | - [ ] 在选取范围内搜索/替换 24 | - [ ] 输入历史 25 | 26 | ## 截图 27 | 28 | ![Text Finder](https://github.com/nyable/obsidian-text-finder/blob/master/screenshot/demo.gif?raw=true) 29 | 30 | # 如何使用 31 | 32 | ## 安装 33 | 34 | ### 社区插件 35 | 36 | - 在社区插件市场中搜索"text finder"并安装。 37 | - 在 Obsidian 设置中启用插件。 38 | 39 | ### 使用 BRAT 安装 40 | 41 | - [安装 BRAT 插件](https://obsidian.md/plugins?id=obsidian42-brat)。 42 | - 执行命令 `Obsidian42 - BRAT: Add a beta plugin for testing`。 43 | - 粘贴此存储库的 URL 并确认。 44 | - 在 Obsidian 设置中启用插件。 45 | 46 | ### 从源代码安装 47 | 48 | - 克隆此仓库。 49 | - 使用 `npm i` 或 `yarn` 安装依赖。 50 | - 使用 `npm run build` 在 `./dist` 中构建文件。 51 | - 将 `main.js`、`styles.css`、`manifest.json` 复制到你的 vault 的 `VaultFolder/.obsidian/plugins/text-finder/` 中。 52 | - 在 Obsidian 设置中启用插件。 53 | 54 | ### 从 Release 安装 55 | 56 | - 在 [最新发布版本](https://github.com/nyable/obsidian-text-finder/releases/latest) 中下载 `main.js`、`styles.css`、`manifest.json`。 57 | - 将 `main.js`、`styles.css`、`manifest.json` 复制到你的 vault 的 `VaultFolder/.obsidian/plugins/text-finder/` 中。 58 | - 在 Obsidian 设置中启用插件。 59 | 60 | ## 设置 61 | 62 | - 在设置页面为对应的命令设置快捷键。 63 | 64 | ## 自定义样式 65 | 66 | 使用 [CSS 代码片段](https://help.obsidian.md/Extending+Obsidian/CSS+snippets)或[Style Settings Plugin](https://github.com/mgmeyers/obsidian-style-settings)来自定义样式。 67 | 68 | [示例的 Style Settings 配置文件](./style-settings.css). 69 | 70 | 以下是部分 CSS 片段示例。 71 | 72 | ### 匹配高亮与当前项 73 | 74 | ```css 75 | .nya-text-finder-match { 76 | border-radius: 2px; 77 | box-shadow: 0 0 0 1px rgb(60, 115, 75); 78 | background-color: inherit; 79 | color: inherit; 80 | } 81 | 82 | .nya-text-finder-match-current { 83 | box-shadow: 0 0 0 1px rgb(187, 187, 187); 84 | background-color: rgba(255, 170, 0, 0.8); 85 | color: black; 86 | } 87 | ``` 88 | 89 | ### 修改位置 90 | 91 | 左上角 92 | 93 | ```css 94 | .nya-finder { 95 | right: unset !important; 96 | left: 376px; 97 | } 98 | ``` 99 | 100 | 右下角 101 | 102 | ```css 103 | .nya-finder { 104 | top: unset !important; 105 | bottom: 72px; 106 | } 107 | ``` 108 | 109 | 左下角 110 | 111 | ```css 112 | .nya-finder { 113 | top: unset !important; 114 | right: unset !important; 115 | left: 376px; 116 | bottom: 72px; 117 | } 118 | ``` 119 | 120 | ### 更改聚焦时的边框颜色 121 | 122 | ```css 123 | body { 124 | --nya-focus-border-color: #39c5bb; 125 | } 126 | ``` 127 | 128 | ### 更改折叠按钮的颜色 129 | 130 | ```css 131 | .nya-toggle { 132 | border-left: 3px solid red !important; 133 | } 134 | ``` 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Obsidian Text Finder 2 | 3 | [English](README.md) 4 | [中文说明](README-zh_CN.md) 5 | 6 | This plugin for Obsidian(https://obsidian.md). 7 | Provides a search/replace window similar to VSCode in editing mode. 8 | 9 | **Note:** The Obsidian API is still in early alpha and is subject to change at any time! 10 | 11 | ## Feature 12 | 13 | Search or replace the text of the current MarkDown file **in editor mode**. 14 | 15 | - Search/Replace in current file 16 | - Highlight matching text 17 | - Show number of matches 18 | - Supports regular expressions 19 | - Supports case sensitivity 20 | 21 | ## To Do 22 | 23 | - [ ] Search/Replace in Selection 24 | - [ ] Input history 25 | 26 | ## ScreenShot 27 | 28 | ![Text Finder](https://github.com/nyable/obsidian-text-finder/blob/master/screenshot/demo.gif?raw=true) 29 | 30 | # How to use 31 | 32 | ## Install 33 | 34 | ### Community plugins 35 | 36 | - Search for "text finder" in the community plugins and install it. 37 | - Enable plugin in Obsidian setting. 38 | 39 | ### BRAT 40 | 41 | - [Install the BRAT Plugin](https://obsidian.md/plugins?id=obsidian42-brat) 42 | - Execute command `Obsidian42 - BRAT: Add a beta plugin for testing` 43 | - Paste the URL of this repository and confirm 44 | - Enable plugin in Obsidian setting. 45 | 46 | ### Source Code 47 | 48 | - Clone this repo. 49 | - `npm i` or `yarn` to install dependencies 50 | - `npm run build` to build file in `./dist`. 51 | - Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/text-finder/`. 52 | - Enable plugin in Obsidian setting. 53 | 54 | ### Releases 55 | 56 | - Download `main.js`, `styles.css`, `manifest.json` in the [latest release](https://github.com/nyable/obsidian-text-finder/releases/latest) 57 | - Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/text-finder/`. 58 | - Enable plugin in Obsidian setting. 59 | 60 | ## Settings 61 | 62 | - Assign a hotkeys for the plugin's command. 63 | 64 | ## Customize Style 65 | 66 | Use [CSS snippets](https://help.obsidian.md/Extending+Obsidian/CSS+snippets) or [Style Settings Plugin](https://github.com/mgmeyers/obsidian-style-settings) to customize styles. 67 | 68 | [Example Style Settings configuration file](./style-settings.css). 69 | 70 | Here are some CSS snippets examples. 71 | 72 | ### Match Highlight and Current Item 73 | 74 | ```css 75 | .nya-text-finder-match { 76 | border-radius: 2px; 77 | box-shadow: 0 0 0 1px rgb(60, 115, 75); 78 | background-color: inherit; 79 | color: inherit; 80 | } 81 | 82 | .nya-text-finder-match-current { 83 | box-shadow: 0 0 0 1px rgb(187, 187, 187); 84 | background-color: rgba(255, 170, 0, 0.8); 85 | color: black; 86 | } 87 | ``` 88 | 89 | ### Change Position 90 | 91 | Top Left 92 | 93 | ```css 94 | .nya-finder { 95 | right: unset !important; 96 | left: 376px; 97 | } 98 | ``` 99 | 100 | Bottom Right 101 | 102 | ```css 103 | .nya-finder { 104 | top: unset !important; 105 | bottom: 72px; 106 | } 107 | ``` 108 | 109 | Bottom Left 110 | 111 | ```css 112 | .nya-finder { 113 | top: unset !important; 114 | right: unset !important; 115 | left: 376px; 116 | bottom: 72px; 117 | } 118 | ``` 119 | 120 | ### Change the border color when focused 121 | 122 | ```css 123 | body { 124 | --nya-focus-border-color: #39c5bb; 125 | } 126 | ``` 127 | 128 | ### Change the color of the collapse button 129 | 130 | ```css 131 | .nya-toggle { 132 | border-left: 3px solid red !important; 133 | } 134 | ``` 135 | -------------------------------------------------------------------------------- /esbuild.config.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild"; 2 | import process from "process"; 3 | import builtins from "builtin-modules"; 4 | import esbuildSvelte from "esbuild-svelte"; 5 | import { sveltePreprocess } from "svelte-preprocess"; 6 | import { sassPlugin } from "esbuild-sass-plugin"; 7 | 8 | const banner = `/* 9 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 10 | if you want to view the source, please visit the github repository of this plugin 11 | */ 12 | `; 13 | 14 | const prod = process.argv[2] === "production"; 15 | 16 | const context = await esbuild.context({ 17 | plugins: [ 18 | esbuildSvelte({ 19 | compilerOptions: { css: "injected" }, 20 | preprocess: sveltePreprocess(), 21 | }), 22 | sassPlugin(), 23 | ], 24 | banner: { 25 | js: banner, 26 | }, 27 | entryPoints: [ 28 | "src/main.ts", 29 | { in: "src/styles/index.scss", out: "styles" }, 30 | ], 31 | bundle: true, 32 | external: [ 33 | "obsidian", 34 | "electron", 35 | "@codemirror/autocomplete", 36 | "@codemirror/collab", 37 | "@codemirror/commands", 38 | "@codemirror/language", 39 | "@codemirror/lint", 40 | "@codemirror/search", 41 | "@codemirror/state", 42 | "@codemirror/view", 43 | "@lezer/common", 44 | "@lezer/highlight", 45 | "@lezer/lr", 46 | ...builtins, 47 | ], 48 | format: "cjs", 49 | target: "es2018", 50 | logLevel: "info", 51 | sourcemap: prod ? false : "inline", 52 | treeShaking: true, 53 | outdir: "dist", 54 | minify: prod, 55 | }); 56 | 57 | if (prod) { 58 | await context.rebuild(); 59 | process.exit(0); 60 | } else { 61 | await context.watch(); 62 | } 63 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "text-finder", 3 | "name": "Text Finder", 4 | "version": "0.2.2", 5 | "minAppVersion": "0.15.0", 6 | "description": "Provides a find/replace window in edit mode similar to VSCode (supports regular expressions and case sensitivity).", 7 | "author": "hafuhafu", 8 | "authorUrl": "https://github.com/nyable", 9 | "fundingUrl": "https://buymeacoffee.com/nyable", 10 | "isDesktopOnly": false 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-text-finder", 3 | "version": "0.2.2", 4 | "description": "Provides a find/replace window in edit mode similar to VSCode (supports regular expressions and case sensitivity).", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "node esbuild.config.mjs", 8 | "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", 9 | "version": "node version-bump.mjs && git add manifest.json versions.json" 10 | }, 11 | "keywords": [ 12 | "obsidian", 13 | "text", 14 | "find", 15 | "replace", 16 | "regular express" 17 | ], 18 | "author": "hafuhafu", 19 | "license": "MIT", 20 | "devDependencies": { 21 | "@tsconfig/svelte": "5.0.4", 22 | "@types/node": "^16.11.6", 23 | "@typescript-eslint/eslint-plugin": "5.29.0", 24 | "@typescript-eslint/parser": "5.29.0", 25 | "builtin-modules": "3.3.0", 26 | "esbuild": "0.25.0", 27 | "esbuild-sass-plugin": "^3.3.1", 28 | "esbuild-svelte": "0.8.2", 29 | "obsidian": "latest", 30 | "postcss": "8.4.47", 31 | "sass": "^1.79.4", 32 | "svelte": "4.2.19", 33 | "svelte-preprocess": "6.0.3", 34 | "tslib": "2.4.0", 35 | "typescript": "5.6.2" 36 | }, 37 | "dependencies": { 38 | "@codemirror/language": "6.10.3", 39 | "@codemirror/state": "^6.0.0", 40 | "@codemirror/view": "^6.23.0", 41 | "i18next": "23.15.1", 42 | "lucide-svelte": "^0.446.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /screenshot/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyable/obsidian-text-finder/53509ecc3ec3f4ee7f081055395fc18834eb2272/screenshot/demo.gif -------------------------------------------------------------------------------- /src/SearchBox.svelte: -------------------------------------------------------------------------------- 1 | 428 | 429 |
435 | 436 |
437 |
445 | {#if isCollapsed} 446 | 447 | {:else} 448 | 449 | {/if} 450 |
451 |
452 |
453 |